Local Volatility vs Implied Volatility
Local volatility vs implied volatility: one is a number per quoted option, the other a surface fitted to the whole chain. What each gets wrong, with data.
Local volatility and implied volatility are two answers to the same question: which volatility number belongs inside a pricing model. Implied volatility is one number per quoted contract, the input that makes the Black-Scholes formula return that contract's market price. Local volatility is a surface, one volatility for every pair of spot level and future date, fitted to reproduce every quoted option at once.
Local volatility vs implied volatility: the short version
Implied volatility is a translator for quotes. Black-Scholes assumes one constant volatility for the life of the option, and the market disagrees with that assumption in plain sight: different strikes and different expiries on the same underlying price out at different implied vols. Instead of discarding the formula, the market inverts it one contract at a time, and each quote ends up with its own sigma. The inversion is a root-find on a monotone function, which how implied volatility is calculated walks through step by step.
Local volatility starts from the other end. It keeps one process for the underlying and lets the instantaneous volatility depend on where spot is and what time it is, written sigma(S, t). Bruno Dupire showed in 1994 that a continuum of European call prices across strike and maturity determines that function uniquely, and gives it in closed form from one partial derivative of call price in maturity over two in strike. The reading matters more than the algebra. A complete set of vanilla prices pins down exactly one local volatility surface, and that surface returns those vanilla prices by construction.
Implied volatility is a per-contract label on the data. Local volatility is a mechanism fitted to all of it at once. Neither one is a forecast. For the inputs that set a vanilla quote in the first place, see what determines an option price.
The shape a surface has to fit
Start with the cross-section across strikes. The panel below takes every SPY option during September 2026 with a converged implied volatility and non-zero traded volume, keeps expiries 20 to 45 days out, and averages implied vol in bands of strike relative to spot.
| strike_vs_spot | iv_pct | contract_count |
|---|---|---|
| 6 to 10% below spot | 20.44 | 1641 |
| 3 to 6% below | 16.75 | 2674 |
| 1 to 3% below | 14.51 | 2268 |
| at the money | 12.97 | 2545 |
| 1 to 3% above | 11.96 | 2124 |
| 3 to 6% above | 11.24 | 2115 |
| 6 to 10% above spot | 12.03 | 1188 |
The exact SQL behind every number
SELECT
bucket AS strike_vs_spot,
round(avg(iv) * 100, 2) AS iv_pct,
count() AS contract_count
FROM
(
SELECT
iv,
m,
multiIf(m < -0.06, '6 to 10% below spot',
m < -0.03, '3 to 6% below',
m < -0.01, '1 to 3% below',
m <= 0.01, 'at the money',
m <= 0.03, '1 to 3% above',
m <= 0.06, '3 to 6% above',
'6 to 10% above spot') AS bucket
FROM
(
SELECT
toFloat64(implied_volatility) AS iv,
toFloat64(strike_price) / toFloat64(underlying_close) - 1 AS m
FROM global_markets.options_greeks
WHERE underlying_symbol = 'SPY'
AND date >= '2026-09-01'
AND date < '2026-10-01'
AND iv_converged = 1
AND volume > 0
AND days_to_expiry BETWEEN 20 AND 45
AND underlying_close > 0
AND implied_volatility > 0
)
WHERE abs(m) <= 0.10
)
GROUP BY bucket
HAVING count() >= 50
ORDER BY min(m)Across the 7 bands, average implied volatility ran from 20.44% in the 6 to 10% below spot band to 12.03% in the 6 to 10% above spot band. One constant volatility cannot sit on all of those points at the same time, which is the whole reason a surface exists. The tilt from low strikes to high strikes is the skew, covered on its own in volatility skew. A local vol surface calibrated to this chain has to pass through every one of these bands, and it will.
Strike is only half of it: the maturity dimension
The same chain prices options at many expiries, and the implied vol attached to a fixed moneyness moves as the expiry moves. The next panel holds moneyness in two bands, at the money and roughly 5 to 8 percent below spot, then walks out the expiry ladder over the same month.
| expiry_band | atm_iv_pct | downside_iv_pct | skew_spread_pts |
|---|---|---|---|
| 7 to 21 days | 12.09 | 22.23 | 10.14 |
| 22 to 45 days | 13.02 | 18.69 | 5.67 |
| 46 to 90 days | 14.02 | 18.67 | 4.65 |
| 91 to 180 days | 15.1 | 18.48 | 3.38 |
| 181 to 365 days | 16.7 | 19.13 | 2.43 |
The exact SQL behind every number
SELECT
band AS expiry_band,
round(avgIf(iv, abs(m) <= 0.01) * 100, 2) AS atm_iv_pct,
round(avgIf(iv, m >= -0.08 AND m <= -0.05) * 100, 2) AS downside_iv_pct,
round((avgIf(iv, m >= -0.08 AND m <= -0.05)
- avgIf(iv, abs(m) <= 0.01)) * 100, 2) AS skew_spread_pts
FROM
(
SELECT
iv,
m,
dte,
multiIf(dte <= 21, '7 to 21 days',
dte <= 45, '22 to 45 days',
dte <= 90, '46 to 90 days',
dte <= 180, '91 to 180 days',
'181 to 365 days') AS band
FROM
(
SELECT
toFloat64(implied_volatility) AS iv,
toFloat64(strike_price) / toFloat64(underlying_close) - 1 AS m,
days_to_expiry AS dte
FROM global_markets.options_greeks
WHERE underlying_symbol = 'SPY'
AND date >= '2026-09-01'
AND date < '2026-10-01'
AND iv_converged = 1
AND volume > 0
AND days_to_expiry BETWEEN 7 AND 365
AND underlying_close > 0
AND implied_volatility > 0
)
)
GROUP BY band
HAVING countIf(abs(m) <= 0.01) >= 50
AND countIf(m >= -0.08 AND m <= -0.05) >= 50
ORDER BY min(dte)At the 7 to 21 days band, at-the-money implied vol averaged 12.09% against 22.23% for the downside band, a gap of 10.14 volatility points. At the 181 to 365 days band the two readings were 16.7% and 19.13%, a gap of 2.43 points. The downside band sits above the at-the-money band at the front of the ladder and still sits above it at the back. Hold on to that: long-dated index smiles are not flat. The level across maturities has its own guide in the IV term structure.
A calibrated surface is a snapshot
Dupire's surface is recovered from one day's quotes. The panel below tracks the same two readings week by week from the start of January 2026 through the end of September 2026.
| week | week_label | atm_iv_pct | skew_spread_pts |
|---|---|---|---|
| 2026-01-05 | Jan 5 | 12.71 | 6.48 |
| 2026-01-12 | Jan 12 | 13.28 | 6.35 |
| 2026-01-19 | Jan 19 | 14.57 | 6.76 |
| 2026-01-26 | Jan 26 | 14.03 | 6.98 |
| 2026-02-02 | Feb 2 | 16.04 | 6.53 |
| 2026-02-09 | Feb 9 | 15.99 | 7.06 |
| 2026-02-16 | Feb 16 | 16.59 | 6.66 |
| 2026-02-23 | Feb 23 | 16.25 | 7.22 |
| 2026-03-02 | Mar 2 | 18.9 | 7.57 |
| 2026-03-09 | Mar 9 | 21.29 | 7.03 |
| 2026-03-16 | Mar 16 | 20.73 | 5.91 |
| 2026-03-23 | Mar 23 | 23.46 | 6.16 |
| 2026-03-30 | Mar 30 | 21.98 | 5.55 |
| 2026-04-06 | Apr 6 | 17.78 | 7.23 |
| 2026-04-13 | Apr 13 | 15.07 | 5.46 |
| 2026-04-20 | Apr 20 | 16 | 5.92 |
| 2026-04-27 | Apr 27 | 15.15 | 6.12 |
| 2026-05-04 | May 4 | 14.98 | 5.75 |
| 2026-05-11 | May 11 | 15.44 | 5.99 |
| 2026-05-18 | May 18 | 14.95 | 5.96 |
The exact SQL behind every number
SELECT
toString(week_start) AS week,
formatDateTime(week_start, '%b %e') AS week_label,
round(avgIf(iv, abs(m) <= 0.01) * 100, 2) AS atm_iv_pct,
round((avgIf(iv, m >= -0.08 AND m <= -0.05)
- avgIf(iv, abs(m) <= 0.01)) * 100, 2) AS skew_spread_pts
FROM
(
SELECT
toMonday(date) AS week_start,
toFloat64(implied_volatility) AS iv,
toFloat64(strike_price) / toFloat64(underlying_close) - 1 AS m
FROM global_markets.options_greeks
WHERE underlying_symbol = 'SPY'
AND date >= '2026-01-05'
AND date < '2026-10-01'
AND iv_converged = 1
AND volume > 0
AND days_to_expiry BETWEEN 20 AND 45
AND underlying_close > 0
AND implied_volatility > 0
)
GROUP BY week_start
HAVING countIf(abs(m) <= 0.01) >= 20
AND countIf(m >= -0.08 AND m <= -0.05) >= 20
ORDER BY week_startOver 39 weekly observations, the at-the-money average read 12.71% in the week of Jan 5 and 13.55% in the week of Sep 28, with the downside gap finishing at 6 points. Recalibrate on Monday and the surface differs from Friday's.
That is awkward for a model whose volatility is a deterministic function of spot and clock time. In local vol, tomorrow's volatility is already settled once you know where spot goes. Volatility that wanders on its own schedule is what a second random driver is for, which is the move the Heston model makes.
Where the two models disagree: the forward smile
A calibrated local vol model reprices every option it was fitted to, inside numerical error. That is the construction, and it is also the limitation: the model adds nothing about those vanillas that their own quotes did not already say. The disagreement with other models lives in payoffs that depend on the surface the market will be quoting at some future date.
A forward-starting option fixes its strike later, at whatever spot turns out to be on a fixing date. A cliquet is a chain of them. A one-year monthly cliquet pays the sum of twelve monthly returns, each one capped and floored. Pricing it needs the smile in force one month out, two months out, eleven months out, none of which is quoted today.
Part of that is pinned by today's quotes. Forward volatility levels follow arithmetically from the term structure: total variance to twelve months, minus total variance to eleven months, leaves the variance of the twelfth month. The panel below extracts that curve from the SPY monthly expiries in the last week of September 2026.
| expiry_date | expiry_label | spot_iv_pct | forward_iv_pct |
|---|---|---|---|
| 2026-11-20 | Nov 20, 2026 | 14.09 | 14.76 |
| 2026-12-18 | Dec 18, 2026 | 14.54 | 15.36 |
| 2027-01-15 | Jan 15, 2027 | 14.75 | 15.35 |
| 2027-03-19 | Mar 19, 2027 | 15.79 | 17.45 |
| 2027-09-17 | Sep 17, 2027 | 17.85 | 19.61 |
The exact SQL behind every number
SELECT
toString(expiration_date) AS expiry_date,
formatDateTime(expiration_date, '%b %e, %Y') AS expiry_label,
round(iv * 100, 2) AS spot_iv_pct,
round(sqrt((dte * iv * iv - prev_dte * prev_iv * prev_iv)
/ (dte - prev_dte)) * 100, 2) AS forward_iv_pct
FROM
(
SELECT
expiration_date,
iv,
dte,
lagInFrame(iv) OVER (ORDER BY expiration_date) AS prev_iv,
lagInFrame(dte) OVER (ORDER BY expiration_date) AS prev_dte
FROM
(
SELECT
expiration_date,
avg(toFloat64(implied_volatility)) AS iv,
avg(days_to_expiry) AS dte
FROM global_markets.options_greeks
WHERE underlying_symbol = 'SPY'
AND date >= '2026-09-24'
AND date < '2026-10-01'
AND iv_converged = 1
AND volume > 0
AND underlying_close > 0
AND implied_volatility > 0
AND days_to_expiry BETWEEN 10 AND 400
AND toDayOfWeek(expiration_date) = 5
AND toDayOfMonth(expiration_date) BETWEEN 15 AND 21
AND abs(toFloat64(strike_price) / toFloat64(underlying_close) - 1) <= 0.01
GROUP BY expiration_date
HAVING count() >= 20
)
)
WHERE prev_dte > 0
AND dte > prev_dte
AND dte * iv * iv > prev_dte * prev_iv * prev_iv
ORDER BY expiration_dateSpot implied vol at the Nov 20, 2026 expiry averaged 14.09%, while the forward leg ending there came out at 14.76%. At the back of the 5 expiries shown, Sep 17, 2027, the spot reading was 17.85% and the forward leg 19.61%. Any model fitted to this chain matches those levels.
The forward smile is the part that stays unpinned, and here the two families split:
- Vanilla puts and calls in the calibration set: matched by construction under local vol, with no new information added.
- European payoffs on the terminal distribution at a calibrated maturity: matched, since the surface fixes those marginal distributions.
- Forward-starting payoffs such as cliquets and forward-start calls: model-dependent, and a local vol model's forward smile flattens as the fixing date moves out.
- Barriers and autocallables: model-dependent, since they read the path and the smile at future times.
A one-year cliquet priced on the calibrated local vol surface and the same cliquet priced on a stochastic vol model fitted to identical vanillas return different premiums. The spread between them is model risk, not a quote. No vanilla in the chain can settle it, since both models fit all of them exactly.
Why stochastic local volatility exists
The industry answer is to run both at once. A stochastic local volatility model (SLV) carries a stochastic variance process of the Heston type and multiplies its volatility by a leverage function in spot and time. That leverage function is solved numerically, through the forward equation, until the model's vanilla prices land back on the market's. The exact vanilla fit survives, and the forward smile comes from the stochastic component, where it does not collapse with maturity. A mixing weight sets how much of the dynamics each side contributes, and that weight is the dial a desk marks its exotics against.
The forward smile is still not observable. SLV turns the assumption into a parameter rather than burying it inside a construction, which is the practical reason neither canonical model retired the other.
FAQ
Is local volatility the same as implied volatility?
No. Implied volatility is a single number attached to one quoted option, the volatility that makes Black-Scholes match that quote. Local volatility is a function of spot and time fitted to the entire quoted surface, and the two coincide only in the degenerate case of a perfectly flat surface.
What does Dupire's formula actually do?
It inverts a surface of European call prices into the unique instantaneous volatility function consistent with all of them. The inputs are the sensitivity of call price to maturity and the second sensitivity to strike, and the output is one surface that reprices every vanilla it was built from.
Why does a local volatility model misprice a cliquet?
A cliquet references the smile at future fixing dates. A calibrated local vol model produces forward smiles that flatten as the fixing date moves out, while index smiles observed in the market stay tilted at long maturities, as the expiry-band panel above shows.
If local volatility gets the forward smile wrong, why use it?
It is exact on vanillas by construction, and as a one-factor model it calibrates and prices quickly. Desks also keep it as the reference point for measuring how much of an exotic's value rests on a forward-dynamics assumption, and as the backbone inside stochastic local volatility.
Every panel here carries the SQL that produced it. Open one, swap the ticker or the expiry band, and ask the same question on the Strasmore terminal.