Chapter 8 · Quantitative Finance
Value at Risk (VaR) vs. CVaR: A Practical Guide for Investors
Build Value at Risk and Conditional VaR from return data in Python, and see why VaR hides the tail loss that actually bankrupts a portfolio.
By Nathan Updated 10 min Intermediate
On this page
Phase 2 has given us the pieces we need to ask the one question every risk manager actually cares about: how much could I lose on a bad day? Chapter 5 handed us a return distribution and showed that its tails are fatter than they look, Chapter 6 built portfolios out of those returns, and Chapter 7 showed how an option can quietly load the tail with catastrophic losses. Now we try to put a single number on the danger, and then we watch that number lie to us.
We usually measure risk as volatility, or standard deviation, but for an ordinary investor a figure like 15% volatility is hopelessly abstract. What we really want to know is how much money we could lose if things go against us. We could look at the absolute worst case, but the worst case is often so catastrophic, every bond in the portfolio defaulting at once, that it paralyses any decision. What we need is a measure that captures a bad-but-plausible outcome rather than the end of the world, and that is exactly what Value at Risk is built to do.
What is Value at Risk
VaR puts a real number on risk. In plain language it answers the question “on a bad day, how much could I lose?”, and more precisely it says something like “on only 5% of days will my loss be worse than X.” So instead of chasing the absolute worst outcome, VaR draws a practical boundary that holds with some high probability. Formally it is a quantile of the loss distribution, and it asks: what is the least I stand to lose on the worst of days over a period ?
- With you are looking at the 95% VaR. Over a one-day horizon, that is roughly the loss on the two or three worst trading days of the year.
- With you are looking at the 99% VaR, focused on about the single worst day of the month.
There are two main ways to compute it: looking backward at what actually happened, or looking forward with a model.
The historical method
This is the most intuitive one. You take a history of returns, sort them from worst to best, and read off the loss at the appropriate point in the tail. For the 95% one-day VaR you simply look at the return sitting at the bottom 5% of the sorted list. Here is a small example that pulls an index history with yfinance and computes both the 95% and 99% figures.
import yfinance as yf
import numpy as np
# Download an index history (Toronto Stock Exchange)
data = yf.download("^GSPTSE", start="2000-01-03", end="2024-01-01")
data['Log_Ret'] = np.log(data['Adj Close'] / data['Adj Close'].shift(1))
returns = data['Log_Ret'].dropna()
# Historical VaR is just a percentile of the return distribution
var_95 = np.percentile(returns, 5)
var_99 = np.percentile(returns, 1)
print(f"95% 1-day Historical VaR: {var_95:.2%}")
print(f"99% 1-day Historical VaR: {var_99:.2%}")
There is a trap to watch for here, which is sensitivity at the extreme. Move just one or two places in the sorted list and the 99% VaR shifts far more than the 95% does, because the data thins out as you go further into the tail. With only a handful of observations that far down, the estimate is genuinely unstable, and that instability is the historical method’s main weakness.
The parametric method
History is useful, but often we want to model what might happen from current conditions rather than replay the past. If we are willing to assume returns are normally distributed, we can compute VaR straight from the mean and volatility without sorting a single row. Suppose the daily mean is 0.02% and the daily volatility is 1.27%.
from scipy.stats import norm
mu = 0.0002
sigma = 0.0127
# Parametric VaR: a quantile of the fitted normal
var_95_param = norm.ppf(0.05, mu, sigma)
var_99_param = norm.ppf(0.01, mu, sigma)
print(f"95% Parametric VaR: {var_95_param:.2%}")
print(f"99% Parametric VaR: {var_99_param:.2%}")
Now compare the two. The historical 99% VaR came out at -3.19%, while the parametric one is only -2.93%. The historical tail is worse, and that gap is the fat tails from Chapter 5 showing up exactly where they hurt. The normal distribution is smooth and thin at the edges, so it systematically underestimates how often extreme days happen, which means parametric VaR tends to look reassuring precisely when it should not.
Scaling VaR over time
Sometimes we want VaR over a longer horizon than a single day. The standard move is to scale the drift by the number of periods and the volatility by :
Because volatility grows with the square root of time rather than linearly, risk over a year is a lot larger than the one-day figure, but not as large as naively multiplying by 250 would suggest. Applying that scaling to the parametric numbers gives:
| Period | Horizon | 95% VaR | 99% VaR |
|---|---|---|---|
| 1 Day | 1 | -2.07% | -2.93% |
| 1 Week | 5 | -4.57% | -6.51% |
| 1 Month | 20 | -8.94% | -12.81% |
| 1 Year | 250 | -28.03% | -41.71% |
The pitfalls of VaR
VaR is genuinely useful, and it is also one of the most dangerous numbers in finance, for two connected reasons.
The first is that VaR tells you where the danger zone begins and absolutely nothing about how deep it goes. It is a single point on the distribution. A 95% VaR of -2% says you will lose at least 2% on the worst one day in twenty, but it is completely silent on whether that bad day costs you 2.1% or 40%. Two portfolios can report the identical VaR while one has a modest tail and the other is holding a bomb, and VaR reports them as equally risky.
The second reason is that VaR can be gamed, and worse, it is not even a coherent risk measure in the formal sense. Coherence requires a property called subadditivity, which says the risk of a combined portfolio should never exceed the sum of the parts, because diversification is supposed to help. VaR can violate this. Combining two portfolios can produce a VaR larger than the sum of their individual VaRs, which is nonsense as a measure of risk. The practical consequence is that VaR is easy to manipulate. Picture a trader whose bonus depends on keeping the 95% VaR below some limit. They can buy cheap insurance that covers small losses and pay for it by selling deep out-of-the-money puts. The 95% number now looks wonderful, but they have quietly stuffed an enormous loss into the 99% tail that the 95% VaR simply cannot see. This is exactly the premium-selling trap from Chapter 7, now dressed up as good risk management. The metric hands you a confident, precise, reassuring number, and the whole disaster lives in the region the number was designed to ignore.
The fix: Conditional VaR
The response to all of this is Conditional VaR, also called Expected Shortfall. Where VaR asks where the danger zone starts, CVaR asks how deep the water is once you have fallen overboard. Instead of the boundary of the worst cases, it takes the average of everything beyond that boundary:
CVaR fixes both of VaR’s problems at once. It is coherent, so the CVaR of a diversified portfolio is always at most the sum of its parts, and it rewards diversification instead of occasionally punishing it. And because it averages the entire tail, it cannot be hidden from by pushing losses further out, since the further-out losses are exactly what it measures. Computing it is almost the same work as VaR: find the cutoff, then average everything past it.
import numpy as np
# 'returns' is a pandas Series of historical log returns
alpha = 0.05 # for 95% confidence
# 1. The VaR cutoff
var_95 = np.percentile(returns, alpha * 100)
# 2. Every return worse than the cutoff
tail_losses = returns[returns <= var_95]
# 3. CVaR is the average of that tail
cvar_95 = tail_losses.mean()
print(f"95% 1-day VaR: {var_95:.2%}")
print(f"95% 1-day CVaR: {cvar_95:.2%}")
The 95% VaR is -2.24% and the 95% CVaR is -2.84%, so there is a 5% chance of losing at least 2.24% on the day, and when that happens the average loss is 2.84%. The gap between those two numbers is precisely what VaR was hiding.
The explorer below lets you feel all of this at once. Slide the confidence level and watch the white VaR line march deeper into the tail while the red shading, the mass that CVaR averages, grows behind it. Flip from the historical sample to the fitted normal and you can watch the parametric cutoff pull inward, understating the fat tail the real returns actually carry. And stretch the horizon to see VaR grow with the square root of time rather than in proportion to it.
Recall the trader who sold deep out-of-the-money puts to flatter their VaR. Under VaR their risk looks fine, because the 95th percentile has barely moved. Under CVaR it explodes, because the enormous potential losses from those sold puts sit squarely in the tail, and CVaR averages the whole tail. The strategy that looked safe under one number is exposed as reckless under the other, which is the entire case for preferring CVaR when the stakes are real.
VaR or CVaR: Which Number to Trust
We set out to answer how much we could lose on a bad day and found two answers. VaR draws the line where the bad days begin, and it is intuitive, easy to compute, and quietly treacherous, because it says nothing about the losses beyond the line and can be gamed by anyone who understands that blind spot. CVaR steps past the line and averages what it finds there, which makes it coherent, harder to manipulate, and far more honest about the tail. If you remember one thing from this chapter, let it be the habit of always asking the second question: not just where does it start, but how bad does it get.
That question keeps returning because we still do not have a real model for how prices move through time. Every VaR we computed leaned on either a fixed history or a static normal, neither of which captures the actual dynamics of a market grinding forward day by day. Building that dynamic model is the whole job of Phase 3, and it starts with the simplest possible motion.
Next up is Chapter 9: The Random Walk. We go right back to a coin flip, let it repeat, and watch a jagged random path emerge. Then we push the step size toward zero and see that path converge on the continuous process, the Wiener process, that underlies all of modern derivatives pricing. It is the first real piece of the stochastic core, and the last stretch of maths before we start building the exchange itself.
⚠️ Financial Education Disclaimer
The quantitative models and Python code provided in this post (including the Value at Risk and CVaR calculations) are for educational and research purposes only.
- Not Financial Advice: This content does not constitute professional financial or investment advice.
- Illustrative Data: The return figures shown are from a representative sample, not live market data, and are used only to demonstrate the method.
- Model Risk: Both historical and parametric VaR can badly understate risk during regime changes and extreme events. Always pair any single risk number with an understanding of the tail it may be hiding.
Get the next part
New parts of Finding P values and false hope land in your inbox the day they publish. No spam, unsubscribe in one click.
We send your address to Kit, our email provider, and ask you to confirm by email before anything is sent. See our Privacy Statement.