Fitting the Volatility Curve: SVI, Splines, and No-Arbitrage
1. Why volatility is a curve
The previous note established that of BSM’s five inputs, the only invisible one is volatility $\sigma$. The market quotes in reverse — each listed option, at each strike and expiry, backs out its own implied volatility. If BSM’s assumptions held exactly, all these IVs would be a single number. Plot IV against strike for a fixed expiry and reality looks like:
- Wings up, middle down — the volatility smile
- Equity-index options usually tilt left-high-right-low — skew: deep OTM puts are far more expensive than deep OTM calls
The causes are fat tails in the return distribution, the negative price–volatility correlation (leverage effect), and the plainest supply-and-demand fact: everyone wants crash insurance.
The problem thus becomes: given a sparse, noisy set of $(K_i, \mathrm{IV}_i)$ quotes, fit a smooth curve defined on the whole strike axis that also survives scrutiny. That is volatility curve fitting.
2. Three hard constraints on any fit
- Fit the data: keep the weighted sum of squared residuals small — weights usually proportional to vega or to the inverse bid–ask spread.
- Smoothness: the curve must be differentiable, because every Greek and every local volatility is a derivative of it.
- No arbitrage — the lifeline, with two clauses:
- Butterfly: for a fixed expiry, call prices as a function of strike must satisfy $\partial^2 C/\partial K^2 \geq 0$ (equivalently, a non-negative risk-neutral density). Violate it and the market offers a free lunch of buying and selling the same risk at different prices.
- Calendar: if $T_1 < T_2$ then total variance $W(T_2,k) \geq W(T_1,k)$.
A standard trick: fit total variance $W(k) = \sigma^2(k),T$ rather than IV, where $k = \ln(K/F)$ is log-moneyness and $F$ is the forward. Only in total-variance terms does the calendar condition take a clean form.
3. Lee’s moments: the grammar of the wings
As strikes run to infinity, implied volatility cannot do as it pleases. Lee (2004) proved that as $|k| \to \infty$, total variance must grow linearly, with asymptotic slopes inside a determined band. In plain words:
The wings of the smile may only rise roughly linearly, with bounded slopes — no exponential blow-up, no flattening into negative slopes.
This boundary is the ceiling on extrapolation for every fitting method. Spline-type methods die here most often: the data cover only the middle segment, the wings are extrapolated, and one careless step breaks the no-arbitrage boundary — or swings wildly with a day’s quotes, leaving the Greeks of deep-OTM options unrecognizable.
4. Method 1: splines / interpolation
Idea: fit a cubic spline to $W(k)$ (or IV) with knots at the quotes.
- Pros: locally flexible, passes through points naturally, easy to implement.
- Cons: endpoint behavior is uncontrolled (a natural spline forces the second derivative to zero at the ends, of dubious economic meaning) and convexity is not guaranteed — butterfly arbitrage may break.
- Practical patches: convexity penalty terms + Lee-boundary caps + joint smoothing across neighboring expiries.
Suitable for quick internal interpolation (valuing between existing quotes); not suitable as the full curve you quote externally.
5. Method 2: SVI — the de facto industry standard
Stochastic Volatility Inspired (Gatheral, 2004). Parameterize total variance:
$$W(k) = a + b\left[\rho,(k - m) + \sqrt{(k-m)^2 + \sigma^2}\right]$$
The five parameters each have a clean geometric meaning:
| Parameter | Meaning | How to guess an initial value |
|---|---|---|
| $a$ | Overall level of total variance | ATM total variance minus half the tilt contribution |
| $b \geq 0$ | Tilt magnitude (how wide the smile opens) | Half the sum of the two wing slopes |
| $\rho \in (-1,1)$ | Tilt direction (negative = left-high skew) | From the difference/sum of wing slopes |
| $m$ | Horizontal shift of the smile center | The ATM $k$ (near 0) |
| $\sigma > 0$ | Roundedness near the ATM point | Inverted from local curvature at ATM |
Sufficient conditions for no-arbitrage (Gatheral–Jacquier, 2014) reduce to simple constraints on the parameters:
$$0 \leq b \leq \frac{4}{T}, \qquad |\rho| < 1, \qquad a \geq -b,\sigma\sqrt{1-\rho^2}, \qquad \sigma > 0$$
The beauty of this set: “the whole curve is arbitrage-free” collapses into box constraints on five scalars — hand them straight to a constrained solver.
SVI also ships with the jump-wing parameterization: re-express in market language — ATM total variance $\nu$, left/right asymptotic slopes, ATM skew — convenient for time-series smoothing of parameters across expiries.
6. Method 3: SABR
The king of interest-rate markets (Hagan et al., 2002). The model is stochastic volatility: the volatility itself has a volatility (vol-of-vol $\nu$), correlated with the underlying via $\rho$, with CEV elasticity $\beta$ controlling smile symmetry. The IV approximation is explicit, and the four parameters $(\alpha, \beta, \nu, \rho)$ map directly onto shape language.
Two cautions: in low-rate environments the Hagan approximation can introduce arbitrage (arbitrage-free SABR is the patched version); and equity markets generally favor SVI, while rates (especially caps/swaptions) default to SABR.
7. A production pipeline (SVI example)
1. Clean Drop: no two-sided quotes, time-to-expiry < 3–5 trading days,
|k| outside the data band, outliers far from neighbors
2. Transform F = S·e^{rT} (or the futures price directly), k = ln(K/F), W = IV²·T
3. Weights w_i ∝ Vega(K_i) or 1/(ask−bid)
4. Objective min Σ w_i · [W(k_i; θ) − W_i]²
5. Constraints Gatheral–Jacquier domain (the box constraints above)
6. Initial values by the geometric guesses in the table; ρ = −0.3, σ = 0.1
are robust starting points
7. Verify pointwise butterfly (∂²C/∂K² > 0, finite differences) + calendar
against neighboring expiries
8. Smooth parameters across expiries and across days to avoid jumpy Greeks
A minimal working skeleton:
import numpy as np
from scipy.optimize import minimize
def svi_w(k, a, b, rho, m, sig):
"""Total variance W(k)."""
return a + b * (rho * (k - m) + np.sqrt((k - m)**2 + sig**2))
def fit_svi(k, iv, T, w=None):
W = iv**2 * T # work in total variance
if w is None:
w = np.ones_like(W)
def obj(p): # weighted sum of squared residuals
return np.sum(w * (svi_w(k, *p) - W)**2)
cons = [ # Gatheral–Jacquier box constraints
dict(type='ineq', fun=lambda p: p[1]), # b >= 0
dict(type='ineq', fun=lambda p: 4/T - p[1]), # b <= 4/T
dict(type='ineq', fun=lambda p: 1 - abs(p[2])), # |rho| < 1
dict(type='ineq', fun=lambda p: p[4]), # sig > 0
dict(type='ineq', fun=lambda p: p[0] + p[1]*p[4]), # a + b·sig >= 0 (simplified)
]
x0 = [np.median(W), 0.1, -0.3, 0.0, 0.1] # geometric initial guess
return minimize(obj, x0, constraints=cons, method='SLSQP').x
# After fitting, always check d²C/dK² > 0 pointwise (butterfly no-arbitrage)
8. Common pitfalls
- Smoothing IV instead of total variance: the calendar condition has no clean form in IV terms; comparing IVs directly across expiries is wrong.
- Free spline extrapolation: one deep-OTM quote moves and the endpoints jump, and hedging signals jump with them.
- Misweighted points: deep-ITM quotes have tiny vega and almost no information; equal-weight fits get dragged by them.
- Day-to-day parameter jitter: a fit that is allergic to single-day noise raises the “invisible transaction cost” of your Greeks. Cross-expiry and cross-day parameter smoothing is mandatory in production.
9. Summary
When fitting a volatility curve, “does it look like the data” is secondary; “is it arbitrage-free, and is it stable” is the lifeline — only a curve that breathes without crossing the boundaries can carry portfolio pricing, hedging, and risk. SVI, with five parameters and one box of constraints, hits the engineering sweet spot.
The next note: once single curves are assembled into a full surface, how to price and hedge options at arbitrary strikes and dates.