SVI → Transformed PDE → Crank–Nicolson
Complete, single-page walkthrough — now including how the PDE becomes a matrix–vector linear system.
1) Fit the implied-vol surface with SVI
Goal. Replace noisy per-quote implied vols with a smooth, arbitrage-aware surface spanning the pricing domain.
Raw SVI (per maturity)
w(k, T) = a + b · (ρ(k - m) + √{(k - m)² + σ²}), IV(k,T)=√{w/T}.
- x-axis: log-moneyness k=ℓn(K/S), built from delta inversion.
- Symmetric delta grid (e.g., 0.10…0.90) for consistent wings/ATM coverage.
Delta → log-moneyness
- Δc=Φ(d1), Δp=Φ(d1)-1 ⇒ d1=Φ⁻¹(Δc) or Φ⁻¹(Δp+1)
- k=ℓn(K/S)=(r-q-½σ²)T+σ√T·d1
2) Feed the SVI surface into the pricing PDE
| Grid | Represents | How it's built | Role |
|---|---|---|---|
| Delta grid | Smile sampling | Symmetric deltas | Uniform wings & ATM |
| Target grid | (Δ, dte) | Cartesian deltas × maturities | SVI evaluation |
| PDE grid | (x,τ) | x=ℓn S (uniform), τ=T-t (uniform) | σ(x,τ) sampled for solver |
Mapping. Use Δ ↔ d_1 ↔ k=ln K/S to connect Δ to x. Interpolate SVI to get σ(x,τ) on PDE nodes.
3) Transformed PDE in log-price & backward time
Original Black-Scholes PDE
Standard form in forward time t and asset price S:
∂V/∂t + ½σ²(S,t)S²∂²V/∂S² + (r-q)S∂V/∂S - rV = 0
Subject to terminal payoff V(S,T) at expiration and appropriate boundary conditions.
Variable transformation
Apply coordinate transforms to simplify the PDE:
| Variable | Transform | Benefit |
|---|---|---|
| x | x = ln(S) | Eliminates S² term, uniform grid |
| τ | τ = T - t | Natural backward marching |
Transformed PDE
Define time-and-space dependent coefficients:
The transformed PDE becomes:
∂V/∂τ = a(x,τ)∂²V/∂x² + b(x,τ)∂V/∂x - rV
Initial & boundary conditions
Payoff at τ = 0 (expiration, normalized by K)
- Call: V(x,0) = max(ex - 1, 0)
- Put: V(x,0) = max(1 - ex, 0)
Boundary conditions at each time step
- Deep ITM call: V ≈ e-qτex - e-rτ
- Deep OTM: V ≈ 0
- For puts: swap ITM/OTM conditions
All values normalized by strike K for numerical stability. Multiply by K to recover dollar prices.
4) Crank–Nicolson finite differences
Discretization
- Space: xi=xmin+iΔx, i=0..M
- Time: τn=nΔτ, march backward from n=0 (payoff) to valuation time.
Interior coefficients at node i
λi = ai Δτ/Δx², νi = bi Δτ/(2Δx), ai=½σ²(xi,τ), bi=(r-q)-½σ²(xi,τ)
- αi = -½λi + ½νi
- βi = 1 + ½ rΔτ + λi
- γi = -½λi - ½νi
RHSi = (1 - ½ rΔτ - λi) Vin + (½λi + ½νi) Vi-1n + (½λi - ½νi) Vi+1n
Stability & accuracy
- Rannacher start: 1–2 backward-Euler steps to damp payoff kink.
- Vol floor: clamp σ ≥ 0.001.
- Ensure xmin,xmax far enough to minimize boundary influence.
5) How the PDE becomes a matrix–vector linear system
Crank–Nicolson averages the spatial operator between time levels n and n+1. Discretizing interior nodes i=1..M-1 yields a tridiagonal relation:
αi Vi-1n+1 + βi Vin+1 + γi Vi+1n+1 = RHSi(Vn).
Vector notation
Collect interior values into vectors Vn = [V1n,...,VM-1n]T and Vn+1 of the same size. Define three diagonal vectors α,β,γ from the coefficients above.
Left-hand matrix A and right-hand matrix D
Form a tridiagonal matrix A ∈ ℝ(M-1)×(M-1) with bands α,β,γ:
A = tridiag(lower = α2..αM-1,
diag = β1..βM-1,
upper = γ1..γM-2)
Similarly, the RHS can be written as DVn plus boundary contributions bn, where D is another tridiagonal matrix with bands
- α̃i = ½λi + ½νi
- β̃i = 1 - ½ rΔτ - λi
- γ̃i = ½λi - ½νi
D = tridiag(lower = α̃2..α̃M-1,
diag = β̃1..β̃M-1,
upper = γ̃1..γ̃M-2)
Boundary vector bn
The first and last interior equations reference the boundaries V0n+1, VMn+1 (on LHS) and V0n, VMn (on RHS). Move known boundary values to a vector bn:
- Row 1 (i=1) gets -α1 V0n+1 on LHS and +(α̃1 V0n) on RHS.
- Row M−1 (i=M−1) gets -γM-1 VMn+1 on LHS and +(γ̃M-1 VMn) on RHS.
Since boundaries are imposed from asymptotics each step, the terms above are known numbers.
Final linear system
A Vn+1 = D Vn + bn.
Solve for Vn+1 using the Thomas algorithm (tri-diagonal solver). Repeat for each time step, marching backward.
Thomas algorithm (outline)
# Given tridiagonal A with (lower l, diag d, upper u) and RHS y:
# 1) Forward sweep: modify coefficients in-place
for i in 2..N:
w = l[i] / d[i-1]
d[i] = d[i] - w * u[i-1]
y[i] = y[i] - w * y[i-1]
# 2) Back substitution
x[N] = y[N] / d[N]
for i in N-1..1:
x[i] = (y[i] - u[i] * x[i+1]) / d[i]
Matrix assembly summary
- Compute ai, bi at each interior node (often at half time-step).
- Form λi, νi then bands α,β,γ (for A) and α̃,β̃,γ̃ (for D).
- Build bn from boundary values at steps n and n+1.
- Solve AVn+1 = DVn + bn.
For puts, the same construction applies; only payoff and boundary formulas change.
6) Diagnostics & plotting
- spread = ask − bid
- diff = model − mid, abs_diff = |model − mid|
- within_bid_ask flag (model in [bid, ask])
plot_bid_ask_check(df,
price_col="dollar_option_price",
mid_col="mid", bid_col="bid", ask_col="ask",
y_col="spread")
7) Practical notes & pitfalls
- Normalize columns early (
dte,dollar_option_price). - Ensure SVI coverage across the PDE domain; control extrapolation.
- Use a small vol floor; consider Rannacher start if oscillations appear.
- Place x_min,x_max far enough for negligible boundary impact around quoted strikes.
Appendix — key formulas
Black–Scholes
- k = ℓn(K/S)
- d1 = Φ⁻¹(Δc) (calls), or Φ⁻¹(Δp + 1) (puts)
- k = (r - q - ½σ²) T + σ √T · d1
CN coefficients (interior)
- αi = −½ λi + ½ νi
- βi = 1 + ½ r Δτ + λi
- γi = −½ λi − ½ νi
- α̃i = ½ λi + ½ νi, β̃i = 1 − ½ r Δτ − λi, γ̃i = ½ λi − ½ νi
Matrix form: A Vn+1 = D Vn + bn with tridiagonal A,D and boundary vector bn.