The Analyst's Path

Historical vs parametric vs Monte Carlo VaR

Historical VaR reads the loss threshold off past returns, while parametric VaR assumes a Normal distribution and calculates the threshold from its formula. Monte Carlo VaR simulates returns from an assumed model and reads the threshold off the simulated sample. On the same book the three should roughly agree when returns look Normal, so a large gap is worth investigating: a historical figure far above the parametric one points to fat tails or skew in the data.

4 min readPart of Risk Systems in Code: VaR, ES, Stress & ScenarioOpen in course mode

Advertisement

Put all three side by side on the same underlying book and one fact becomes visible immediately: when the world genuinely looks Normal, all three methods should roughly agree, and that agreement is a standing sanity check you should run on every book, every quarter, for the rest of your career, not a coincidence to celebrate once and forget. The moment they disagree materially, that disagreement is informative, not merely annoying, and it is informative in a specific, diagnosable direction:

  • Historical VaR much larger than parametric VaR on the same sample is the classic fingerprint of fat tails and/or skew in the actual data that the Normal assumption cannot see, the historical method is "seeing" a real crash that happened in your sample window, while the parametric method has smoothed it away into a symmetric bell curve.
  • Parametric VaR larger than historical VaR typically means your historical sample simply has not yet contained its worst-case day, a dangerous form of false comfort, because it means the assumption-free method's only defence (real, unfiltered history) hasn't been tested by history yet.
  • Monte Carlo disagreeing with parametric, when both are built on the identical Normal assumption, is not informative about the market at all, it is either a bug in your simulation code or simply not enough simulated draws, and the fix is more draws or a code review, never a market interpretation.

Advertisement

This is precisely why a serious risk report never ships a single VaR number in isolation, it ships all three, side by side, and treats their spread as a risk signal in its own right, on top of whatever the middle estimate happens to be.

{
  "skill": "Scaffolding the repetitive plumbing of a risk pipeline (roll-forward loops, report tables, plotting) without letting an assistant own the actual risk formulas",
  "use": "Once you can already derive and hand-verify historical, parametric, and Monte Carlo VaR/ES yourself (the gate this module gives you), use a coding assistant to generate the surrounding boilerplate — a pandas rolling-window loop that recomputes VaR every day over a year of returns, a formatted comparison table of all three methods, or a matplotlib exhibit of VaR versus realized P&L — so you spend your own time on the risk logic, not on loop syntax.",
  "tools": ["Coding assistants — Claude Code, GitHub Copilot, Cursor", "Chat assistants for a first-pass code skeleton — Claude, ChatGPT"],
  "prompt": "I have a working, hand-verified function `historical_var_es(returns, confidence)` that returns (var, es). Write a pandas-based roll-forward loop that computes a 250-day rolling historical VaR at 99% confidence over a full return series, storing one VaR estimate per day (using only data available up to and including that day — no look-ahead), and return the result as a Series aligned to the original index. Do not change the VaR formula itself.",
  "verify": "Read every line before running it — a rolling-window helper is exactly where a look-ahead bug hides (does the window truly end at day t, or does a careless `.rolling()` call include day t+1 through a shift-direction mistake?). Run it and manually check the very first non-NaN output against your own by-hand historical_var_es call on that identical slice. Then check it against the no_lookahead discipline from QD1.03: perturb a single FUTURE return far outside the current window and confirm today's VaR estimate does not change. Never trust an assistant's claim that a loop 'has no look-ahead' — verify it by breaking it on purpose.",
  "diy": "You must already be able to compute historical_var_es(returns, confidence) correctly by hand on a small sample (this module's Worked Example 1 and code pack exercise QD2.02-e01) before asking an assistant to wrap it in a loop — otherwise you cannot tell a fluent-looking rolling-window bug from a correct one.",
  "market": "US"
}

Advertisement

Part of the course

This page is part of Risk Systems in Code: VaR, ES, Stress & Scenario (QD2.02), in Phase 12: Finance Plus, AI and the quant-code track. The module's flashcards and its quiz are in the app.