SPX implied-volatility surfaces from listed option chains: parity-implied forwards, Black-76 inversion, quasi-explicit SVI calibration, and static no-arbitrage diagnostics. Full report with figures →
- Chain ingestion (
volsurf/chain.py) — CBOE delayed SPX quotes, OCC symbology parsing, two-sided markets only. SPX because it is European and cash-settled: Black-76 IVs need no early-exercise model (SPY would). - Parity-implied forwards (
volsurf/parity.py) — per expiry, regress C−P on strike: slope = −df, intercept = df·F. Both the forward and the discount factor come from option prices alone; no rate or dividend assumptions anywhere in the pipeline. - Implied vol (
volsurf/bs.py) — Newton with analytic vega inside a bisection safeguard; rejects quotes outside no-arbitrage price bounds instead of forcing a number. - SVI calibration (
volsurf/svi.py) — raw SVI per expiry via the quasi-explicit (Zeliade) decomposition: for fixed (m, σ) the problem is linear in three reduced parameters, so only a 2-D outer search is nonlinear (multistart Nelder-Mead). Constraints b ≥ 0, |ρ| ≤ 1 enforced by construction. - No-arbitrage diagnostics (
volsurf/noarb.py) — Gatheral–Jacquier butterfly function g(k) (negative g = negative implied density) and calendar monotonicity of total variance, both evaluated on the observed strike range — raw SVI extrapolates wildly outside it, and a violation there is a fitting artifact, not a market statement.
- SVI fits SPX smiles to 0.2–0.4 vol points RMSE per expiry with 5 parameters — from 3 weeks out to 2.4 years.
- ATM skew decays as ≈ T^−0.44 across two orders of magnitude of maturity — the classic ~T^−1/2 stylized fact, measured not assumed.
- Zero butterfly violations on observed strike ranges; 7 small calendar crossings between adjacent daily expiries in weekend-stale quotes — quantified in the report rather than smoothed away.
pytest — Black-76 values against hand-computed numbers, IV round-trips
across a σ/K/T grid, parity recovery on synthetic books to machine
precision, SVI parameter recovery from known slices, and the classic Axel
Vogt SVI parameters (Gatheral & Jacquier 2014) correctly detected as
butterfly-arbitrageable.
pip install -e .
python scripts/fetch_chain.py _SPX # new snapshot (or use the committed one)
python scripts/fit_report.py # docs/report.md + figures
pytest
- Gatheral, "A parsimonious arbitrage-free implied volatility parameterization" (2004)
- Zeliade Systems, "Quasi-Explicit Calibration of Gatheral's SVI model" (2009)
- Gatheral & Jacquier, "Arbitrage-free SVI volatility surfaces" (2014)
Delayed public quotes; snapshot study, not a trading system.
