Quant Modelling [HFT] All modules
3 Module 03

Financial Time Series for Traders

How markets turn time into data — and how returns, volatility and moving averages let a quant measure movement, quantify uncertainty and separate signal from noise.

Exam: Quantitative Analysis Fundamentals Source: Lecture 3 Numerics-heavy

What is a financial time series?

A financial time series is simply data indexed by time: a sequence of observations recorded at successive moments — every second, minute, hour or day. Markets never stop generating it. Each trade, quote and tick is stamped with a time, so a price chart is just a time series drawn on a screen.

Definition — Time series

A time series is an ordered collection of values $P_1, P_2, \dots, P_t$ where the index $t$ is time. Order matters: shuffling the observations destroys the information, because the whole point is how each value relates to the ones before it.

Markets generate continuous streams of this data. A quant's first job is to treat that stream as a dataset — something to measure, transform and model — rather than a flickering chart to react to emotionally.

Prices vs returns

Raw prices are awkward to compare. A \$5 move means something very different for a \$10 stock than for a \$1,000 stock. Returns fix this by expressing each move as a fraction of the starting price, so movements are normalized and assets become directly comparable.

Why returns, not prices

Returns normalize movement: a 5% gain is 5% whether the stock costs \$10 or \$1,000. This lets us compare assets fairly, add them into portfolios, and build statistics (mean, volatility) that are stable over time.

Simple return

The simple (arithmetic) return is the change in price divided by the old price:

Simple return $$ r_t = \dfrac{P_t - P_{t-1}}{P_{t-1}} $$

Log return

Log (continuously compounded) returns take the natural log of the price ratio. They are convenient because they add over time instead of compounding multiplicatively, and they are nearly identical to simple returns for small moves.

Log return $$ r_t = \ln\!\left(\dfrac{P_t}{P_{t-1}}\right) $$

Cumulative return

To combine many periods of simple returns into one total figure, chain the growth factors $(1 + r_t)$ and subtract 1:

Cumulative return over a window $$ R_{\text{cum}} = \prod_t (1 + r_t) - 1 $$
Worked example (a) Simple return from \$100 to \$105
  1. Old price $P_{t-1} = 100$, new price $P_t = 105$.
  2. Apply the formula: $r_t = \dfrac{105 - 100}{100}$.
  3. Compute the numerator: $105 - 100 = 5$, then divide: $\dfrac{5}{100} = 0.05$.
Simple return = 0.05 = 5%.
Worked example (b) Log return for the same move
  1. Same prices: $P_{t-1} = 100$, $P_t = 105$, so the ratio is $\dfrac{105}{100} = 1.05$.
  2. Take the natural log: $r_t = \ln(1.05)$.
  3. Evaluate: $\ln(1.05) \approx 0.0488$.
Log return ≈ 0.0488 = 4.88% — slightly below the 5% simple return, as expected for a gain (log returns are always a touch smaller for positive moves).
Worked example (c) Cumulative return: +10% then −5%
  1. Day 1 return $r_1 = +10\% = 0.10$, day 2 return $r_2 = -5\% = -0.05$.
  2. Form the growth factors: $(1 + 0.10) = 1.10$ and $(1 - 0.05) = 0.95$.
  3. Multiply: $1.10 \times 0.95 = 1.045$.
  4. Subtract 1: $1.045 - 1 = 0.045$.
Cumulative return = 0.045 = 4.5%. Note it is not simply $10\% - 5\% = 5\%$: gains and losses compound, so order and base matter.
Returns don't just add up

A +10% then −5% is 4.5%, not 5%. And a +50% followed by −50% leaves you at $1.5 \times 0.5 = 0.75$, a 25% loss, not break-even. This asymmetry is why drawdowns hurt so much.

Understanding volatility

Volatility measures how much returns fluctuate around their average. It is the statistical fingerprint of uncertainty: higher volatility means wider swings, less predictability and more risk.

Definition — Volatility

Volatility is the variability of returns, measured as their standard deviation. Higher volatility = larger typical deviations from the mean = higher uncertainty. It says nothing about direction — only about the size of the swings.

We first need the mean (average) return over the sample:

Mean return $$ \bar r = \dfrac{1}{n}\sum_{i=1}^{n} r_i $$

Then volatility is the sample standard deviation of returns — using $n-1$ in the denominator (Bessel's correction) because we estimated the mean from the same data:

Rolling / sample volatility $$ \sigma = \sqrt{\dfrac{1}{n-1}\sum_{i=1}^{n} (r_i - \bar r)^2} $$

Daily volatility is scaled to an annual figure by multiplying by $\sqrt{252}$ — the square-root-of-time rule, where 252 is the number of trading days in a year:

Annualized volatility $$ \sigma_{\text{ann}} = \sigma_{\text{daily}}\,\sqrt{252} $$
Worked example (e) Rolling volatility of returns [2%, −1%, 3%, −2%, 1%]
  1. List the returns as decimals: $0.02,\ -0.01,\ 0.03,\ -0.02,\ 0.01$, with $n = 5$.
  2. Mean: $\bar r = \dfrac{2 - 1 + 3 - 2 + 1}{5}\% = \dfrac{3}{5}\% = 0.6\%$.
  3. Deviations from the mean (in %): $1.4,\ -1.6,\ 2.4,\ -2.6,\ 0.4$.
  4. Squared deviations (in %²): $1.96,\ 2.56,\ 5.76,\ 6.76,\ 0.16$.
  5. Sum of squares: $1.96 + 2.56 + 5.76 + 6.76 + 0.16 = 17.2$ (%²).
  6. Sample variance: divide by $n - 1 = 4$: $\sigma^2 = \dfrac{17.2}{4} = 4.3$ (%²).
  7. Volatility: $\sigma = \sqrt{4.3} \approx 2.07\%$.
Daily volatility $\sigma \approx \mathbf{2.07\%}$. Annualized: $2.07\% \times \sqrt{252} \approx 2.07\% \times 15.87 \approx \mathbf{32.9\%}$.
Exam tip — sample vs population

Use $n-1$ for sample standard deviation (the default in rolling-volatility questions and in pandas .std()). If a question explicitly says "population", divide by $n$ instead. Watch the wording.

Moving averages: smoothing noisy prices

Raw price series are jagged with noise. A moving average smooths them by averaging the last $n$ observations, revealing the underlying trend. The simple moving average (SMA) over a window of length $n$ is:

Simple moving average $$ \text{SMA}_n = \dfrac{1}{n}\sum_{i=0}^{n-1} P_{t-i} $$

Shorter windows (e.g. 20-day) react fast but stay noisy; longer windows (e.g. 50-day) are smoother but lag. Comparing the two is the basis of many trend signals: when the fast average crosses above the slow one, momentum is turning up.

WindowReactsSmoothnessTypical use
20-day SMAFast (short lag)NoisierCatch turns early, short-term trend
50-day SMASlow (more lag)SmootherConfirm the broader trend
Worked example (d) 3-day SMA of prices [10, 12, 14, 16, 18]
  1. Window length $n = 3$, so each SMA averages three consecutive prices.
  2. First window [10, 12, 14]: $\dfrac{10 + 12 + 14}{3} = \dfrac{36}{3} = 12$.
  3. Slide one step to [12, 14, 16]: $\dfrac{12 + 14 + 16}{3} = \dfrac{42}{3} = 14$.
  4. Slide again to [14, 16, 18] (the latest window): $\dfrac{14 + 16 + 18}{3} = \dfrac{48}{3} = 16$.
The SMA series is 12 → 14 → 16. The latest 3-day SMA is 16. Notice the average drops the oldest price and adds the newest as the window rolls forward.

Rolling windows: statistics over a sliding window

Both the SMA and rolling volatility are rolling statistics: you fix a window width, compute a statistic, then slide the window one step at a time across the series. Each step produces one new output value, so a single price series spawns a smooth derived series.

flowchart LR
  subgraph SERIES[Price series P₁ … P₄₋]
    P1[P₁]:::s --> P2[P₂]:::s --> P3[P₃]:::s --> P4[P₄]:::s --> P5[P₅]:::s
  end
  W1["Window {P₁,P₂,P₃}"]:::d --> S1[SMA / σ #1]:::d
  W2["Window {P₂,P₃,P₄}"]:::d --> S2[SMA / σ #2]:::d
  W3["Window {P₃,P₄,P₅}"]:::d --> S3[SMA / σ #3]:::d
  classDef s fill:#eef2ff,stroke:#4f46e5,stroke-width:1px,color:#3730a3;
  classDef d fill:#ecfdf5,stroke:#0d9488,color:#0d9488;
      
A fixed-width window slides one step at a time. Each position yields one rolling statistic (mean, SMA, or volatility), turning a price series into a smoothed derived series.

From prices to returns: the core transformation

Almost every analysis starts by converting the price series into a return series, then deriving statistics from the returns. This pipeline is the backbone of the lab session.

flowchart LR
  A([Raw price series P_t]):::s --> B([Compute returns r_t]):::s
  B --> C([Mean return r̄]):::d
  B --> D([Rolling volatility σ]):::d
  A --> E([Moving averages SMA]):::d
  C --> F([Signal vs noise:
trend or mean reversion?]):::s D --> F E --> F classDef s fill:#eef2ff,stroke:#4f46e5,stroke-width:1px,color:#3730a3; classDef d fill:#ecfdf5,stroke:#0d9488,color:#0d9488;
Prices feed returns; returns feed mean and volatility; prices also feed moving averages. Together they let a researcher decide whether a move is signal or noise.

Trend following vs mean reversion

Two opposing intuitions explain most price behaviour, and a quant must decide which regime an asset is in.

📈

Trend following

Momentum strategies follow trends. Strong, persistent moves may continue as buying attracts more buying. Rising fast SMA over slow SMA is a classic trend cue.

↩️

Mean reversion

Markets sometimes overreact. After an extreme move, prices may snap back toward their normal level (the moving average) as emotions cool.

Same data, opposite bets

A price far above its 50-day SMA is bullish to a trend follower (momentum is strong) but bearish to a mean reverter (it is stretched and due to fall back). The edge lies in knowing which regime currently holds.

Randomness and noise

Not every wiggle means something. Much of short-term price movement is noise — random fluctuation with no predictive content. The researcher's hardest job is distinguishing genuine signal from noise.

Don't trade the noise

If you react to every tick, you will overtrade, pay costs and chase ghosts. Smoothing (moving averages) and statistical thresholds (volatility bands) exist precisely to filter noise so only meaningful moves trigger a decision.

Self-check: A stock goes \$50 → \$56. What is the simple return?
$r = \dfrac{56 - 50}{50} = \dfrac{6}{50} = 0.12 = \mathbf{12\%}$. Always divide the change by the old price.
Self-check: Why is +20% then −20% a loss, not break-even?
Growth factors compound: $1.20 \times 0.80 = 0.96$, a $0.96 - 1 = \mathbf{-4\%}$ cumulative return. The −20% applies to a larger base than the +20% did, so you end up below where you started.
Self-check: Why do we annualize daily volatility with $\sqrt{252}$ rather than $\times 252$?
Variance scales linearly with time, so over 252 days variance is $252\,\sigma_{\text{daily}}^2$. Volatility is the square root of variance, so it scales with $\sqrt{252}$, giving $\sigma_{\text{ann}} = \sigma_{\text{daily}}\sqrt{252}$.

Lab, assignment & mini project

🧪

Lab session

Compute returns, estimate volatility, and build moving averages from a real price series.

📊

Assignment

Build a financial market dashboard visualizing prices, returns and rolling statistics.

⚙️

Mini project

Implement a simple trend-following system using fast vs slow moving-average crossovers.

Key takeaways

Remember
  • A financial time series is data indexed by time; markets generate it continuously.
  • Returns normalize price moves so assets are comparable: $r_t = \dfrac{P_t - P_{t-1}}{P_{t-1}}$.
  • Returns compound, they don't add: chain $(1 + r_t)$ for cumulative return.
  • Volatility = standard deviation of returns = uncertainty; annualize with $\sqrt{252}$.
  • Moving averages smooth noise; rolling stats slide a fixed window across the series.
  • Decide between trend following and mean reversion, and always separate signal from noise.