NV
NordVarg
ServicesTechnologiesIndustriesCase StudiesBlogAboutContact
Get Started

Footer

NV
NordVarg

Software Development & Consulting

GitHubLinkedInTwitter

Services

  • Product Development
  • Quantitative Finance
  • Financial Systems
  • ML & AI

Technologies

  • C++
  • Python
  • Rust
  • OCaml
  • TypeScript
  • React

Company

  • About
  • Case Studies
  • Blog
  • Contact

© 2025 NordVarg. All rights reserved.

November 11, 2025
•
NordVarg Team
•

Derman–Kani (Dupire) Local Volatility: Theory and Practical Calibration

Derivation and practical guide to extracting a local volatility surface from market implied volatilities (Derman–Kani / Dupire), with implementation notes and a Python example.

Generalquantitativeoptionslocal-volatilitypythonfinance
13 min read
Share:

Derman–Kani (Dupire) Local Volatility: Theory and Practical Calibration#

Local volatility models are a cornerstone of modern option pricing and risk management. They answer the question: what instantaneous volatility function σ_loc(S,t) applied to a diffusion process dS_t = μS_t dt + σ_loc(S_t,t) S_t dW_t produces the same European option prices (or implied volatilities) that we observe in the market today?

This article explains the theory behind the Derman–Kani / Dupire local volatility approach, the practical challenges of calibrating a stable surface from discrete, noisy market implied vols, and a concise Python example that walks through a minimal implementation.

Summary — Quick takeaways#

  • Dupire's formula gives a direct mapping from the implied volatility surface (or option prices across strikes & maturities) to a local volatility function.
  • In practice we must smooth and interpolate the implied vol surface, enforce arbitrage constraints, and compute robust numerical derivatives.
  • Common artifacts include negative local variances from bad differentiation, arbitrage in the implied vol surface, and unstable extrapolation.

1 — Background and motivation#

Implied volatility (IV) is the volatility parameter that, when plugged into Black–Scholes, yields the observed market price for an option. The IV surface σ_imp(K,T) (strike K, maturity T) is a compact representation of market option prices.

A local volatility model assumes that the underlying follows a time- and state-dependent diffusion

plaintext
1\frac{dS_t}{S_t} = r(t) dt + \sigma_{loc}(S_t, t) dW_t,
2

and prices European claims by taking expectations under that diffusion. The Derman–Kani / Dupire result tells us there exists a σ_loc(S,t) that reproduces the marginal distributions (hence European option prices for all strikes) implied by the market (ignoring dividends / interest-rate complications). It's a model calibrated to the entire implied-vol surface — perfect for pricing path-dependent exotics when one trusts today's option smiles to encode forward-looking risk.

Use-cases:

  • Pricing certain exotics consistently with vanilla quotes.
  • Scenario generation and local risk analysis.
  • Building a model consistent with observed vanilla prices.

Limitations:

  • A local vol model enforces perfect fit to European prices, but it may fail to replicate realistic dynamics for forward-looking implied vol evolution (it often underestimates skew dynamics compared to stochastic-vol models).
  • Calibration is numerically fragile: derivatives of a noisy IV surface amplify error.

2 — Dupire formula (high level)#

Dupire derived a closed-form expression for the local variance function in terms of the call price surface C(K,T). In plain form:

sigma_loc^2(K, T) = 2 * ∂_T C(K,T) / (K^2 * ∂^2 C(K,T)/∂K^2).

Here C(K,T) is the price of a European call with strike K and maturity T (forward or undiscounted versions are commonly used to simplify the formula). The symbol ∂^2C/∂K^2 denotes the second partial derivative of the call price with respect to strike — by Breeden–Litzenberger, for forward (undiscounted) calls this equals the risk‑neutral density f_{S_T}(K). Written in terms of implied vol σ_imp(K,T) the same expression can be expanded (but is algebraically heavier) by differentiating Black–Scholes formulas w.r.t. K and T.

Important points:

  • The denominator uses the second derivative of call price w.r.t. strike — this is related to the risk-neutral density and must be positive (if not, the implied surface has arbitrage).
  • The numerator involves the time derivative of the call price: markets with sparse maturities require careful interpolation in T.

In practice we evaluate Dupire on a grid of strikes and maturities and then transform to the local volatility function in (S,t) coordinates (mapping from strike K to spot/forward levels or log-moneyness). Many implementations work directly with moneyness (k = ln(K/F)) because it is numerically more stable.

3 — Practical concerns: discrete data, arbitrage, smoothing#

Real market data is discrete, noisy, and sometimes inconsistent. To apply Dupire robustly you must address:

  • Surface interpolation: you need continuous C(K,T) or σ_imp(K,T) to differentiate. Use a smooth but arbitrage-free parameterization (e.g., SVI, spline with monotonicity constraints, or arbitrage-safe RBF) or conservative splines.
  • Arbitrage checks: the surface must respect calendar arbitrage (∂_T C ≥ 0) and butterfly arbitrage (∂^2 C/∂K^2 ≥ 0). If the raw data violates these, smoothing must enforce constraints or you'll get negative denominators.
  • Numerical differentiation: finite differences amplify noise. Use analytic derivatives from parametric fits (e.g., SVI) where possible or smoothing splines whose derivatives are stable.
  • Extrapolation: Dupire requires values off the observed strike range. Choose sensible tails (e.g., linear extrapolation of total implied variance in log-strike, or use the extreme-strike tail behavior implied by models).

4 — Interpolation and parameterizations (recommended patterns)#

  • SVI (Stochastic Volatility Inspired) parameterization: a widely-used 5-parameter fit for total implied variance as a function of log-moneyness. Fit SVI slice-by-slice or use a time-dependent SVI to produce a smooth surface. Advantages: parsimonious, well-studied, allows tail control.
  • Cubic splines on total implied variance vs strike/moneyness with monotonicity constraints: convenient, but derivatives require care.
  • Bivariate splines or smoothly interpolated surfaces with penalty terms for curvature: flexible but heavier.
  • Local regression (LOESS) or Gaussian process smoothing: powerful but computationally expensive for large option sets.

A pragmatic pipeline is to fit SVI for each maturity, smooth the time dimension with monotone cubic Hermite interpolating polynomials (PCHIP) on total variance, and compute analytic derivatives for strike using SVI formulas. This avoids finite-difference noise in strike derivatives.

5 — Numerical differentiation: best practices#

Main derivatives needed:

  • ∂_T C(K,T): time derivative. Avoid simple finite differences on noisy points — instead smooth in T (e.g., fit total implied variance as a function of T and differentiate analytically or apply a smooth kernel).
  • ∂^2 C/∂K^2 (K,T): second strike derivative. This relates to the risk-neutral density: poor approximations produce negative densities.

Techniques:

  • Use analytic derivatives if the parameterization supports them (SVI has closed-form derivatives for total implied variance; combined with Black–Scholes derivatives you can compute ∂^2 C/∂K^2 analytically).
  • If using splines, compute derivatives directly from spline basis derivatives (they're much more stable than finite-difference approximations on raw data).
  • Apply Tikhonov regularization or penalty terms to control oscillatory behavior in derivatives.

Edge-cases to watch:

  • Sparse maturities: if only a few maturities exist (e.g., weekly and quarterly), interpolation in T needs care. Consider using calendar smoothing on total variance.
  • Short maturities: prices may be close to intrinsic and contain discretization noise; use local averaging or robust smoothing.

6 — Implementation: step-by-step algorithm#

Contract: inputs and outputs

  • Inputs: market quotes (option prices or implied vols) for a set of strikes K_i and maturities T_j; spot price S0; interest rate curve r(t) and dividend yield q(t) or forward prices F(t).
  • Output: local volatility grid σ_loc(S,t) on a chosen grid of (S,t) or a callable function for interpolation.

High-level steps:

  1. Preprocess quotes: convert market implied vols to Black price C(K,T) or to forward undiscounted calls; compute forwards F(T) using r and q.
  2. Choose coordinate system: strike K or log-moneyness k = ln(K/F). Working in k is common.
  3. Parameterize and fit the implied vol surface. Examples: slice-wise SVI + time-smoothing; or 2D cubic spline with arbitrage constraints.
  4. Compute analytic or spline derivatives: ∂_T C and ∂^2 C/∂K^2 (or compute from implied vol via Black derivatives; see Breeden–Litzenberger for the density interpretation).
  5. Evaluate Dupire formula on the grid; guard against negative denominator or tiny values by applying small-floor or adjusting smoothing.
  6. Map local volatility from K,T coordinates to S,t grid (K maps to forward strike at t; set K= S if you want σ_loc(S,t) at spot level).
  7. Validate: check positivity, boundedness, and comparison of prices: re-price vanilla options from local vol via finite difference or Monte Carlo and compare to original market prices.

7 — Dupire in implied-vol terms (practical formula)#

Because markets quote implied vol, many implementations transform Dupire into an expression in terms of σ_imp(K,T). Let w = σ_imp^2(K,T) T denote total implied variance. With some algebra the Dupire formula becomes (in log-moneyness coordinates) a formula involving partial derivatives of w w.r.t. T and k. A commonly used form (for forward price frame) is:

plaintext
1\sigma_{loc}^2(k,T) = \frac{\partial_T w(k,T)}{1 - \frac{k}{w} \partial_k w(k,T) + \frac{1}{4}\left(-\frac{1}{4} - \frac{1}{w} + \frac{k^2}{w^2} \right) (\partial_k w(k,T))^2 + \frac{1}{2} \partial_{kk} w(k,T)}.
2

This expression shows why total variance parameterizations (w) are convenient: derivatives of w are smoother and better behaved than derivatives of implied vol directly. Many practitioners fit w(k,T) and differentiate it analytically.

8 — Python example: simple pipeline (SVI per-slice + time smoothing)#

Below is a compact Python example that sketches the main steps. This is intentionally minimal — production code must include robust calibration, constraints, logging, and tests.

Note: dependencies — numpy, scipy, and optionally matplotlib. For SVI fits a small routine is included.

python
1# minimal_local_vol.py
2import numpy as np
3from scipy.optimize import minimize
4from scipy.interpolate import PchipInterpolator
5from math import log, sqrt
6
7# Black-Scholes helpers (undiscounted forward prices assumed)
8from scipy.stats import norm
9
10def bs_call_price(F, K, T, sigma):
11    if T <= 0 or sigma <= 0:
12        return max(F - K, 0.0)
13    d1 = (np.log(F / K) + 0.5 * sigma * sigma * T) / (sigma * np.sqrt(T))
14    d2 = d1 - sigma * np.sqrt(T)
15    return F * norm.cdf(d1) - K * norm.cdf(d2)
16
17# SVI total variance function (raw parametrization)
18def svi_total_var(params, k):
19    a, b, rho, m, sigma = params
20    return a + b * (rho * (k - m) + np.sqrt((k - m)**2 + sigma**2))
21
22# Fit SVI to market total variance (per maturity)
23def fit_svi(k, w_market, initial=None):
24    if initial is None:
25        initial = np.array([0.1, 0.1, 0.0, 0.0, 0.1])
26    bounds = [(-1, 5), (1e-6, 5), (-0.999, 0.999), (-5, 5), (1e-6, 5)]
27    def obj(p):
28        w = svi_total_var(p, k)
29        return np.sum((w - w_market)**2)
30    res = minimize(obj, initial, bounds=bounds)
31    return res.x
32
33# Example usage (synthetic data)
34if __name__ == '__main__':
35    # Synthetic market: expiries and strikes
36    expiries = np.array([0.1, 0.25, 0.5, 1.0])
37    strikes = np.linspace(-0.6, 0.6, 31)  # log-moneyness k = ln(K/F)
38    F = 100.0
39
40    # Create synthetic total variance surface (w = sigma_imp^2 * T)
41    # For demo we'll fabricate an implied vol surface
42    w_surface = {}
43    for T in expiries:
44        # simple smile: base variance grows with T, add smile curvature
45        base_var = 0.04 + 0.02 * T
46        w = base_var + 0.02 * np.exp(-strikes**2 / 0.1)  # total variance
47        w_surface[T] = w
48
49    # Fit SVI per slice
50    svi_params = {}
51    for T in expiries:
52        p = fit_svi(strikes, w_surface[T])
53        svi_params[T] = p
54
55    # Time smoothing: for each strike (k) we have w(T); interpolate w in T with PCHIP
56    # Prepare grid for evaluation
57    T_grid = np.linspace(expiries.min(), expiries.max(), 40)
58    K_grid = np.exp(strikes) * F
59    w_grid = np.zeros((len(T_grid), len(strikes)))
60
61    for i, k in enumerate(strikes):
62        w_by_T = np.array([svi_total_var(svi_params[T], k) for T in expiries])
63        interp = PchipInterpolator(expiries, w_by_T)  # monotone in T
64        w_grid[:, i] = interp(T_grid)
65
66    # Compute derivatives with finite-differences on smooth w_grid (careful in production)
67    dT = T_grid[1] - T_grid[0]
68    dk = strikes[1] - strikes[0]
69    dwdT = np.gradient(w_grid, dT, axis=0)
70    dwdK2 = np.gradient(np.gradient(w_grid, dk, axis=1), dk, axis=1)
71
72    # Compute local variance (simplified expression assuming forward frame)
73    local_var = np.zeros_like(w_grid)
74    for i in range(len(T_grid)):
75        for j in range(len(strikes)):
76            w = w_grid[i, j]
77            wT = dwdT[i, j]
78            wKK = dwdK2[i, j]
79            denom = 1 - (strikes[j] / w) * (np.gradient(w_grid[i,:], dk)[j]) + 0.25 * ((-0.25 - 1/w + (strikes[j]**2)/(w**2)) * (np.gradient(w_grid[i,:], dk)[j]**2)) + 0.5 * wKK
80            if denom <= 1e-12 or wT <= 0:
81                local_var[i,j] = np.nan
82            else:
83                local_var[i,j] = wT / denom
84
85    # local_sigma = sqrt(local_var)
86    local_sigma = np.sqrt(np.abs(local_var))
87
88    print('Computed local vol grid shape:', local_sigma.shape)
89
90

Notes on the sample above:

  • This is a pedagogical sketch. The finite differences on the smoothed w_grid are acceptable here, but in production you'd prefer analytic derivatives from SVI or other parametric forms.
  • The denominator expression used is a simplified form of the full formula; please consult a reference for exact algebra if you implement for production.

9 — Validation and diagnostics#

After producing a candidate local volatility grid, validate it:

  • Positivity: ensure σ_loc^2 ≥ 0 across the grid. Negative values often indicate numerical differentiation noise or arbitrage in the implied vol surface.
  • Repricing: run a PDE finite-difference or Monte Carlo using the local vol field and reprice a representative set of vanillas—prices should match market within tolerance.
  • Noisy tails: inspect the tails (deep OTM strikes and very short maturities) carefully; they are the usual trouble spots.
  • Stability: test small perturbations in input quotes and verify that local vols behave smoothly.

Typical fixes when things go wrong:

  • Increase smoothing (fit a smoother SVI or add regularization).
  • Enforce arbitrage constraints when fitting (e.g., convexity in strike).
  • Floor local variance to a small positive value where numerical issues arise, but document the floor and monitor its prevalence.

10 — Edge cases and pitfalls#

  • Calendar arbitrage: if ∂_T C < 0 for some strikes, the implied vol surface allows arbitrage and Dupire can break. Use time-smoothing and impose monotone-in-time constraints.
  • Negative density: if ∂^2 C/∂K^2 ≤ 0, the risk-neutral density is invalid. Check butterfly arbitrage.
  • Short-dated quotes: when T→0 the formulas become sensitive; prefer analytic forms or special short-time asymptotics.
  • Discrete dividends: adjust to forward prices if dividends are present.
  • Data sparsity: if strikes or maturities are sparse, reduce ambition — compute local vol only where you have confident data and design sensible extrapolators.

11 — Practical tips and heuristics#

  • Work in total variance w = σ_imp^2 T rather than implied vol directly — it's smoother and better behaved for differentiation.
  • Use parametric fits (SVI) where possible. They reduce degrees of freedom and produce analytic derivatives.
  • When fitting SVI per-slice, regularize or penalize rapid changes in parameters across maturities.
  • Keep a small positive floor on local variance when running PDEs to avoid numerical instability — but monitor how often you hit the floor.
  • Instrument your pipeline: produce diagnostic plots (implied vol smiles, total variance vs time, local vol slices) automatically.

12 — Quick references#

  • Derman, E., & Kani, I. (1994). Riding on a Smile. Risk Magazine.
  • Dupire, B. (1994). Pricing with a Smile. Risk Magazine.
  • Gatheral, J. (2004). The Volatility Surface: A Practitioner's Guide.

13 — Try it: minimal checklist and next steps#

If you want to reproduce a working pipeline quickly:

  1. Start with market quotes in implied vol; convert them to total variance w(k,T).
  2. Fit SVI per maturity, visually check fits, and ensure no butterfly arbitrage on slices.
  3. Smooth w in time with PCHIP or another monotone interpolator.
  4. Differentiate analytically if you have closed-form SVI derivatives; otherwise use spline derivatives.
  5. Apply Dupire, inspect and floor negative values, then reprice via finite-difference to validate.
NT

NordVarg Team

Technical Writer

NordVarg Team is a software engineer at NordVarg specializing in high-performance financial systems and type-safe programming.

quantitativeoptionslocal-volatilitypythonfinance

Join 1,000+ Engineers

Get weekly insights on building high-performance financial systems, latest industry trends, and expert tips delivered straight to your inbox.

✓Weekly articles
✓Industry insights
✓No spam, ever

Related Posts

Nov 25, 2025•17 min read
Stress Testing and Scenario Analysis for Portfolios
Generalrisk-managementstress-testing
Nov 25, 2025•14 min read
News-Based Trading with NLP and LLMs
Generalalgorithmic-tradingnlp
Nov 25, 2025•18 min read
Mean Reversion Strategies: From Pairs Trading to Baskets
Generalalgorithmic-tradingmean-reversion

Interested in working together?