- log returns
- pct_change
- rolling()
- std()
- annualised volatility
- rolling volatility
- volatility clustering
- np.sqrt(252)
Returns & Rolling Statistics
Scene: the risk desk, 7:12 am. The stock in your book moved 1.4% overnight — again. The head of risk leans over: "What's vol running at on this name — not since January, right now?" A single full-period standard deviation cannot answer that: it averages the calm of March and the storm of June into one number. What the desk wants is a rolling estimate — volatility with a short memory.
Log Returns vs Simple Returns
| Formula | Best for | |
|---|---|---|
| Simple return | rₜ = (Pₜ − Pₜ₋₁) / Pₜ₋₁ | P&L reporting — intuitive to investors |
| Log return | rₜ = ln(Pₜ / Pₜ₋₁) | Risk models — the quant's default |
Log returns win for risk work because they are:
- ›Time-additive: the weekly log return is exactly the sum of 5 daily log returns
- ›The modelling default: option-pricing and risk models assume prices are lognormal (Black–Scholes, GBM), so log returns are their natural unit — though real returns still have fat tails (see the history box below)
- ›Symmetric: a +10% and a −10% log return cancel out exactly
Annualised Volatility
σ_ann = σ_daily × √252
252 is the number of trading days per year in most markets. A daily vol of 1.5% annualises to about 1.5% × 15.87 ≈ 23.8%.
🧠 The mental model: trip average vs speedometer
- ›
df['log_ret'].std()is your average speed over the whole road trip — one number for six months. It cannot tell you that you are flying down the autobahn right now. - ›
df['log_ret'].rolling(20).std()is the speedometer needle: a window holding only the last 20 observations slides along the series one day at a time, recomputing the std inside each window. Yesterday's regime dominates; January is forgotten.
One consequence to expect: the needle needs data before it can move. rolling(20) returns NaN until it has a full window — and since the very first log return is itself NaN (no previous price), the first 20 rows of vol_20 are NaN. That warm-up is not a bug; it is the honest answer "not enough history yet".
Pythondf['vol_20'] = df['log_ret'].rolling(20).std() * np.sqrt(252)
📜 Why Volatility Clusters — And Who Discovered It
Rolling volatility is not just a calculation — it captures one of the most important empirical facts in financial markets: volatility clustering.
1963 — Benoit Mandelbrot (the fractal mathematician) published "The Variation of Certain Speculative Prices" in the Journal of Business. He showed that cotton price changes had fat tails — extreme moves were far more common than the normal distribution predicted. His insight: "Large changes tend to be followed by large changes, of either sign, and small changes tend to be followed by small changes." This was volatility clustering, observed 20 years before it was formally modelled.
1982 — Robert Engle (then at UC San Diego) formalised this with the ARCH model (AutoRegressive Conditional Heteroskedasticity) — a mathematical model where today's volatility depends on recent squared returns. He received the Nobel Prize in Economics in 2003 specifically for this work. The GARCH model (Bollerslev, 1986) extended ARCH to allow persistence in volatility — now standard in all risk systems.
1987 — Black Monday: The Dow Jones fell 22.6% in a single day on October 19, 1987. No single news event explained it. The crash was partly attributed to portfolio insurance strategies that triggered selling when prices fell — creating a feedback loop of escalating volatility. After the crash, the Chicago Board Options Exchange introduced the VIX (1993) to measure the market's implied 30-day volatility — a direct institutionalisation of the rolling volatility concept.
The practical consequence: You cannot use a static, full-period volatility estimate in risk management. Markets have volatility regimes. The rolling 20-day window you are computing captures these regime changes — and is the same calculation that VaR desks at Goldman Sachs and JPMorgan run every trading day.
Career insight: Volatility is the most important risk input in derivatives pricing, portfolio construction, and risk-limit setting. Every quant role requires fluency with rolling stats.
Your Task
The starter simulates 120 business days of prices, computes log returns, and prints a text volatility dashboard — one row every 10 trading days, one █ block ≈ 2 points of annualised vol. But the vol line is wrong on purpose: it computes one static full-period std and stamps it on every row. Run it as-is and look at the dashboard — every bar identical at 24.8%, the exact mistake the history above warns about. Then fix the 👉 YOUR TURN line so the estimate gets a moving 20-day memory.
Predict before you run: the last five daily log returns are +1.25%, +1.47%, −0.18%, +0.97%, +1.43% — a hot streak. When you switch to the true rolling 20-day estimate, will the latest vol land above or below the static 24.84%? Fix the line, run, and check the last line of the output. If you guessed above — congratulations, you just observed volatility clustering with your own eyes.