vol-surface: an arbitrage-free volatility surface you can break
An implied-volatility slice is a claim about the risk-neutral distribution of
the terminal price. Push the parameters far enough and the claim becomes incoherent:
negative density, and a static arbitrage. SVI and SABR calibration with the
Gatheral-Jacquier conditions screened on every fit, computed in this tab.
00 The surface01 The inversion02 Break it03 Calibrate04 SABR
What the numbers are. Nobody quotes an option's price in dollars for
long. They quote the implied volatility: the single number you would have to feed
Black-Scholes to make it return the price actually being paid. It's a change of units, in
the way a bond's yield is a change of units on its price, and it makes options with
different strikes and dates comparable.
Where on the x-axis. Strike is written as log-moneyness,
k = log(K / F), the strike over the forward price. So
k = 0 is at-the-money, negative k is a
downside put, and k = -0.4 is a strike about a third below the
forward. Using a ratio rather than a dollar strike lets one picture serve any
underlying.
Why it's a shape and not a number. If Black-Scholes were true, every
strike would imply the same volatility and the plot would be flat. It never is. Plot
implied vol against k for one expiry and you get a curve. In FX it
is roughly symmetric and genuinely earns the name smile; in equity index options
it's monotone decreasing across most of the traded range, so skew or
smirk is the accurate word and the one used below, because downside puts are
persistently bid for crash protection. Both are slices of the same object. Stack them
across expiries and you have a surface. Fitting one
means choosing a function that passes near every quote, and this library uses
SVI, Gatheral's stochastic-volatility-inspired parameterisation, in raw
form w(k) = a + b(ρ(k-m) + √((k-m)² + σ²)).
Five numbers per expiry, working in total implied variancew = σ²BST rather than volatility, because
total variance is the quantity that must be monotone in maturity for the surface to be
free of calendar arbitrage. Slices are fitted quasi-explicitly: with
m and σ held fixed the problem is
linear in the other three, so the search is two-dimensional rather than five.
00
The surface · fitted from quotes
Five expiries, one surface
Twenty-one strikes at each of five expiries, quoted with noise, fitted
slice by slice and then asked for a vol nobody quoted.
Log-moneyness runs across, expiry runs back, and the height of the sheet is the implied
volatility the fitted surface returns there. The ridges picked out in dark are the five
expiries that were actually quoted; everything between them is the surface interpolating,
which is the whole point of fitting one. A desk needs a vol for a strike and a date nobody
printed, and the surface is the object that supplies it.
The left edge rises because downside puts trade at higher implied vol than upside calls,
which is the equity skew. The sheet flattens going back because uncertainty about the next
month is more concentrated than uncertainty about the next two years, once both are
expressed as an annualised rate.
Three handles reshape it, and each one refits all five slices from scratch rather than
redrawing a formula. Level scales total variance, lifting the whole
sheet. Skew leans SVI's rho toward the downside, steepening the left
wing against the right. Wings steepens b, lifting both wings away
from the money. Drag the sheet itself to turn it.
checking
Vol level1.00×
Skew1.00×
Wings1.00×
waiting
01
The inversion · where every quoted vol comes from
Price in, volatility out
Before there is a surface there is one option, one price, and the number
you have to solve for to explain it.
That surface is built out of numbers that have to be extracted from prices first, so it
is worth going back a step. Black-Scholes maps a volatility to a price in closed form, and
that direction is easy. The direction a desk actually needs is the other one: a price is on
the screen, and the volatility that produced it has to be solved for, because the formula
can't be inverted algebraically. This library uses Brent's method, bracketed between the
no-arbitrage bounds on the price.
Below, a volatility is turned into a price at every strike and then recovered back out of
that price. If the two halves disagree, nothing further up the page means anything, so the
round trip is the first thing worth checking:
checking
Volatility in20.0%
Maturity1.00y
Quote noise for the screen25 bp
waiting
Finding · experiment 01
02
Break it · the arbitrage check
Break the density
Five numbers describe one slice. Two of them, pushed far enough, produce a
slice that admits static arbitrage, and the library says so instead of
handing it back quietly.
A slice isn't only a curve. It's a complete statement about the risk-neutral
distribution of the terminal price. Breeden and Litzenberger showed in 1978 that
∂²C/∂K², the second derivative of the
undiscounted call price with respect to strike, is the risk-neutral density: the
market's odds on every outcome are already implied by the prices it quotes, and you
recover them by differentiating twice. A slice and a distribution are the same object
written two ways, and a slice with the wrong convexity in strike describes a measure that
isn't a probability measure.
That's what makes this a trade rather than a modelling complaint. Buy one call at
K-d, sell two at K, buy one at
K+d, and you own a butterfly. It pays out only if the stock
lands near K, so it can never be worth less than nothing, and its
price is the implied density around K times the width. If that
density goes negative the butterfly costs less than nothing: somebody is paid to hold a
position that can't lose. That's the arbitrage, and it's why a fitter that ignores the
check is worse than useless.
Below is one slice shown three ways. The smile is what a desk publishes.
g(k) is the function Gatheral and Jacquier derived in 2014 from
w and its first two derivatives in k. Its
sign is the condition itself: g(k) ≥ 0 across the strip is
equivalent to a non-negative density, and it's far cheaper than differentiating prices,
which is why the library checks it rather than the density. The density is the same failure seen literally, as
a probability below zero.
The five handles are SVI's parameters. a shifts total variance up
and down, b sets how steeply both wings rise,
rho tilts the curve so one wing outruns the other,
m slides the smile sideways, and sigma
controls how rounded the bottom is. Raise b and drop
sigma, which is to say make the wings steep and the base sharp, and
all three panels turn over together:
checking
a level0.021
b wing slope0.075
rho skew-0.60
m shift0.00
sigma curvature0.200
Finding · experiment 02
03
Calibrate · noisy quotes
Fitting marks that aren't clean
Real quotes aren't a curve. They are a curve plus whatever the market was
doing when you took the snapshot.
Volatility is measured in basis points here, a hundredth of a percentage point,
so 25 bp of noise nudges each quote by up to a quarter of a vol
point either way. That's roughly what a screen looks like once bid-ask and stale marks are
accounted for. The dots below are the perturbed quotes the fitter was handed, the lines are
what it returned, RMS err in the table is the root-mean-square gap
between them in basis points of vol, and ATM vol is the fitted value
at k = 0.
The fit also has to pass two separate no-arbitrage tests. Butterfly is the
within-expiry one from the last section: the density along a single smile must stay
positive. Calendar is the across-expiry one: total implied variance at fixed
k must be non-decreasing in maturity, since a calendar spread has a
non-negative payoff, so quoting less total variance for more time is a static arbitrage in
the other direction. Together the two are what "free of static arbitrage" means for a
surface.
Drag the noise up and watch the residuals grow:
Quote noise25 bp
Expiry
a
b
rho
m
sigma
ATM vol
RMS err
waiting
Finding · experiment 03
04
SABR · the other model
A second opinion on the same quotes
SVI is a shape fitted to a slice. SABR is a stochastic-volatility model
whose smile comes out of an expansion. Both get pointed at the same marks here.
SABR writes down a story instead of a shape. The forward is assumed to diffuse with a
volatility that's itself random, and four numbers govern it.
alpha is the starting volatility and sets the level.
beta is the backbone: at 1 the forward moves
in percentage terms as in Black-Scholes, at 0 it moves in absolute
terms, and 0.5 is the usual compromise. Alpha means different things
at different betas, because it's the volatility of the forward raised to beta rather than
of the forward itself, so moving beta alone throws the level off.
rho is the correlation between the forward and its own volatility,
and it's what produces skew. nu is the volatility of volatility,
and it's what produces curvature.
Hagan's formula turns those four into a smile through an asymptotic expansion, accurate
when nu²T is small and drifting when it isn't. That's a known
property rather than a bug, and
validation.md
measures the drift against a Monte Carlo of the SABR SDE instead of taking the formula's
word for it: at the money, agreement to 1.5 bp when
nu²T = 0.16, and a 393 bp gap when
nu²T = 3.2. Here both models fit the one-year slice:
alpha level1.884
beta backbone0.50
rho correlation-0.25
nu vol of vol0.585
waiting
Finding · experiment 04
Five sections, one library, and every number above computed while you
read. The same code is scored against Hagan, Gatheral and a Monte Carlo of the SABR SDE
in validation.md,
including the place where it disagrees with the reference by 393 basis points and says
so.