Skip to main content

svi-py

Stochastic volatility inspired (SVI) parametrizations of the implied volatility surface in Python — plus the SABR stochastic volatility model.

Given a panel of contemporaneous European call and put option prices across strikes and maturities, svi-py calibrates smooth, arbitrage-aware total variance surfaces using the SVI family of models and SABR. It handles the full pipeline: implied vol extraction, forward estimation via put-call parity, OTM leg selection, and per-slice calibration with configurable no-arbitrage constraints.

Installation

pip install svi-py

Requires Python >= 3.13.

Quick start

You need a DataFrame with columns for strike prices, implied volatilities (or raw option prices from which to compute them), time to maturity, and an implied forward price. A typical workflow:

import numpy as np
import pandas as pd
from pysvi import SVI, get_model, calibrate_slice, apply_slice, ArbitrageFreedom

# Suppose df_slice is a single-maturity cross-section with columns:
#   strike, iv, maturity, implied_forward
model = get_model("svi")
params = calibrate_slice(df_slice, model)

# Generate fitted IVs and residuals
fitted = apply_slice(df_slice, params, model)
print(fitted[["strike", "iv", "fitted_iv", "residual_iv"]])

For SSVI/eSSVI, pass the ATM total variance as an extra argument:

model = get_model("ssvi")
theta = float(np.nanmin(df_slice["iv"] ** 2 * df_slice["maturity"]))
params = calibrate_slice(df_slice, model, theta=theta)

For jump-wings, pass the time to expiry:

model = get_model("jw")
T = float(df_slice["maturity"].iloc[0])
params = calibrate_slice(df_slice, model, T=T)

DirectSVI requires no extra arguments — it fits directly from log-moneyness and total variance:

model = get_model("dsvi")
params = calibrate_slice(df_slice, model)

For SABR, pass the time to expiry and the forward, and optionally fix the CEV exponent β (default 0.5):

model = get_model("sabr")
T = float(df_slice["maturity"].iloc[0])
F = float(df_slice["implied_forward"].iloc[0])
params = calibrate_slice(df_slice, model, T=T, F=F, beta=1.0)  # beta=1 for FX/equity

Where do the inputs come from?

svi-py expects you to already have implied volatilities and forward prices. If you're starting from raw option prices, the library provides helpers:

  • compute_ivs_vectorized computes Black-Scholes-Merton implied vols from option mid-prices via py_vollib.
  • calculate_implied_forward estimates the forward price from put-call parity: $F = K + e^{rT}(C - P)$.
  • choose_leg selects the OTM leg (calls for $K \geq F$, puts for $K < F$) for cleaner vol quotes.

You need a panel of contemporaneous call and put option prices across multiple strikes for at least one maturity. The richer the strike grid, the better the calibration.

Parametrizations

All parametrizations work in total variance space: $w(k) = \sigma^2(k) \cdot T$, where $k = \log(K/F)$ is log-moneyness.

Raw SVI

The original Gatheral (2004) parametrization with 5 free parameters:

$$w(k) = a + b\left[\rho(k - m) + \sqrt{(k - m)^2 + \sigma^2}\right]$$

Parameter Meaning Constraint
$a$ overall variance level $a \geq 0$
$b$ slope / curvature scale $b > 0$
$\rho$ skew (correlation) $|\rho| < 1$
$m$ log-moneyness shift unconstrained
$\sigma$ vol-of-vol (smile width) $\sigma > 0$

Maximum flexibility (5 degrees of freedom per slice). No automatic arbitrage guarantees beyond soft parameter bounds.

SSVI (Surface SVI)

Gatheral & Jacquier (2014). Reduces to 2 free parameters per slice by fixing the ATM total variance $\theta = \sigma_{\text{ATM}}^2 T$:

$$w(k;\theta) = \frac{\theta}{2}\left[1 + \rho,\varphi(\theta),k + \sqrt{\left(\varphi(\theta),k + \rho\right)^2 + 1 - \rho^2}\right]$$

where $\varphi(\theta) = \eta / \sqrt{\theta}$ is the curvature function.

Parameter Meaning Constraint
$\theta$ ATM total variance (fixed input) $\theta > 0$
$\rho$ skew $|\rho| < 1$
$\eta$ curvature scale $\eta > 0$

Guarantees no butterfly arbitrage by construction for each fixed $\theta$.

eSSVI (Extended SSVI)

Extends SSVI with maturity-dependent skew via a $\rho(\theta)$ term structure:

$$\rho(\theta) = \text{clip}!\left(\rho_0 + \rho_1 \left(\frac{\theta}{\theta_{\text{ref}}}\right)^\alpha,; -1,; 1\right)$$

The total variance formula is the same as SSVI but with $\rho \to \rho(\theta)$. This adds 4 parameters globally ($\rho_0, \rho_1, \alpha, \eta$) and enables realistic calendar skew evolution across maturities. $\theta_{\text{ref}}$ is a reference ATM total variance (typically the median across slices) that normalises the power law.

DirectSVI

A closed-form SVI calibration method (Schadner, forthcoming) that linearises the SVI equation by rewriting it as a conic section (hyperbola) in $(k, w)$ space:

$$z_0 k^2 + z_1 w^2 + z_2 kw + z_3 k + z_4 w + z_5 = 0$$

The 6 conic coefficients $z$ are found by solving a quadratically constrained eigenvalue problem (hyperbola constraint $z_2^2 - 4z_0 z_1 > 0$):

  1. Build design matrices $D_2 = [k^2,; w^2]$ and $D_1 = [kw,; k,; w,; 1]$
  2. Compute scatter matrices $S_{22}, S_{21}, S_{11}$
  3. Solve $M\mathbf{a}2 = \lambda, C_1\mathbf{a}2$ where $M = S{22} - S{21}S_{11}^{-1}S_{21}^\top$ and $C_1 = \begin{pmatrix}0 & -2\-2 & 0\end{pmatrix}$
  4. Select eigenvector for smallest positive eigenvalue; recover remaining coefficients via $\mathbf{a}1 = -S{11}^{-1}S_{21}^\top\mathbf{a}_2$

Evaluation solves the conic for $w$ given $k$ via the quadratic formula. No iterative optimisation is needed, making this the fastest calibration method in the library.

Parameter Meaning
$z_0$ – $z_5$ Conic section coefficients (normalised so $z_1 = 1$)

Note: DirectSVI does not support penalty-based arbitrage enforcement (NO_BUTTERFLY / NO_CALENDAR). Only ArbitrageFreedom.QUASI is meaningful.

Reference: Schadner, W. "Direct Fit for SVI Implied Volatilities", Journal of Derivatives (forthcoming). See also wol-fi/directSVI.

Jump-Wings

The jump-wings parametrization (Gatheral 2004) re-expresses SVI in terms of financially interpretable quantities:

Parameter Meaning
$v_t$ ATM variance $\sigma_{\text{ATM}}^2$
$\psi_t$ ATM skew
$p_t$ left (put) wing slope, $p_t \geq 0$
$c_t$ right (call) wing slope, $c_t \geq 0$
$\tilde{v}_t$ minimum implied variance, $\tilde{v}_t > 0$

These map to raw SVI $(a, b, \rho, m, \sigma)$ via a bijection:

$$b = \frac{p_t + c_t}{2}, \quad \rho = 1 - \frac{p_t}{b}, \quad \beta = \rho - \frac{2\psi_t\sqrt{T}}{b}$$

$$\alpha = \text{sgn}(\beta)\sqrt{\frac{1}{\beta^2} - 1}, \quad m = \frac{(v_t - \tilde{v}_t),T}{b\left[-\rho + \text{sgn}(\alpha)\sqrt{1 + \alpha^2} - \alpha\sqrt{1 - \rho^2}\right]}$$

$$\sigma = |\alpha \cdot m|, \quad a = \tilde{v}_t \cdot T - b,\sigma\sqrt{1 - \rho^2}$$

Same 5 degrees of freedom as raw SVI but with parameters that have direct market interpretation (wing slopes, ATM level, minimum variance).

SABR

The SABR stochastic volatility model (Hagan, Kumar, Lesniewski & Woodward 2002) — the market standard for interest-rate (swaptions, caps/floors) and FX volatility smiles. Unlike the SVI family, SABR is a dynamic model: it specifies stochastic differential equations for the forward and its volatility,

$$dF = \alpha F^\beta, dW_1, \qquad d\alpha = \nu, \alpha, dW_2, \qquad d\langle W_1, W_2\rangle = \rho, dt$$

Implied volatilities come from the Hagan et al. asymptotic expansion (the "HKLW formula"):

$$\sigma_B(K, F) = \frac{\alpha}{(FK)^{(1-\beta)/2}, D(L)} \cdot \frac{z}{x(z)} \cdot \left{1 + \left[\frac{(1-\beta)^2\alpha^2}{24,(FK)^{1-\beta}} + \frac{\rho\beta\nu\alpha}{4,(FK)^{(1-\beta)/2}} + \frac{2-3\rho^2}{24}\nu^2\right] T\right}$$

where $L = \log(F/K)$, $D(L) = 1 + \frac{(1-\beta)^2}{24}L^2 + \frac{(1-\beta)^4}{1920}L^4$, $z = \frac{\nu}{\alpha}(FK)^{(1-\beta)/2} L$, and $x(z) = \log!\left[\frac{\sqrt{1-2\rho z+z^2}+z-\rho}{1-\rho}\right]$. At the money $z/x(z) \to 1$ (handled via Taylor expansion). Total variance is then $w(k) = \sigma_B^2(k), T$.

Parameter Meaning Constraint
$\alpha$ initial volatility level $\alpha > 0$
$\beta$ CEV exponent (fixed, not fitted) $0 \leq \beta \leq 1$
$\rho$ spot/vol correlation $|\rho| < 1$
$\nu$ vol-of-vol $\nu \geq 0$

Following market practice, $\beta$ is fixed by convention rather than calibrated: $\beta = 1$ (lognormal) for FX and equity, $\beta \approx 0.5$ for interest rates, $\beta = 0$ (normal) for spread-like underlyings. Calibration fits $(\alpha, \rho, \nu)$ per slice given $\beta$, $F$, $T$:

model = get_model("sabr")
params = calibrate_slice(df_slice, model, T=T, F=F, beta=0.5)

Note: the HKLW expansion is accurate near the money and for moderate maturities, but is known to lose accuracy (and can even imply negative densities) for deep wings or very long maturities. NO_BUTTERFLY performs a numerical density check via finite differences — it is a guard, not a structural guarantee.

Reference: Hagan, P., Kumar, D., Lesniewski, A., Woodward, D. (2002). "Managing Smile Risk", Wilmott Magazine.

Arbitrage freeness

Every parametrization accepts an arbitrage_condition argument controlling how strictly no-arbitrage is enforced during calibration. The options are flags that can be combined with |:

from pysvi import ArbitrageFreedom

# Default: soft parameter bounds only
model = get_model("svi")  # ArbitrageFreedom.QUASI

# Enforce no butterfly arbitrage (non-negative density)
model = get_model("svi", ArbitrageFreedom.NO_BUTTERFLY)

# Enforce no calendar spread arbitrage (non-decreasing total variance in T)
model = get_model("ssvi", ArbitrageFreedom.NO_CALENDAR)

# Enforce both
model = get_model("svi", ArbitrageFreedom.NO_BUTTERFLY | ArbitrageFreedom.NO_CALENDAR)

QUASI (default)

Soft parameter-bound constraints only: $b > 0$, $|\rho| < 1$, $\sigma > 0$. Enforced via bounded optimisation and penalty terms. Fast, and usually sufficient for liquid underlyings.

NO_BUTTERFLY

Enforces non-negative call price density $g(k) \geq 0$ across strikes, where:

$$g(k) = \left(1 - \frac{k,w'(k)}{2,w(k)}\right)^2 - \frac{w'(k)^2}{4}\left(\frac{1}{w(k)} + \frac{1}{4}\right) + \frac{w''(k)}{2}$$

Butterfly arbitrage exists whenever $g(k) < 0$ for some $k$. The calibrator evaluates $g$ on a fine grid and penalises violations. Note that SSVI and eSSVI already guarantee $g(k) \geq 0$ by their functional form; this flag adds an explicit numerical check.

NO_CALENDAR

Enforces non-decreasing total variance in maturity: $w(k, T_2) \geq w(k, T_1)$ for $T_2 > T_1$ at every $k$. This is a cross-slice condition. Pass the prior (shorter-maturity) slice's total variance via the w_prev keyword argument to calibrate:

# After calibrating the first slice:
w_prev = model.total_variance(k_grid, params_first_slice)

# Calibrate the next slice with calendar constraint:
params_next = model.calibrate(k, w_target, w_prev=w_prev)

Calibration details

All models calibrate via L-BFGS-B (bounded quasi-Newton) with automatic Nelder-Mead fallback. The pipeline for a single maturity slice is:

  1. prepare_slice: extracts $T$, $F$, computes $k = \log(K/F)$ and $w = \sigma_{\text{mkt}}^2 T$, filters invalid data, clips extreme moneyness.
  2. model.calibrate: minimises MSE$(w_{\text{model}}, w_{\text{target}})$ plus penalty terms.
  3. apply_slice: evaluates the fitted surface, computes $\sigma_{\text{fit}} = \sqrt{w/T}$ and residuals.

The factory function get_model(name) accepts "svi", "ssvi", "essvi", "jumpwings" (or "jw"), "directsvi" (or "dsvi"), and "sabr".

Contributing

Contributions, bug reports, and feature requests are welcome. Open an issue or submit a PR on GitHub.

Wanted: the original Gamma-Vanna-Volga paper. The Gamma-Vanna-Volga parametrization is something of a holy grail in the quant vol surface literature and would be a great addition to this library. If you have a copy of the original paper, please send it to marwin.steiner@gmail.com.

License

MIT

Release files for svi-py 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for svi-py 0.4.0
File Size Uploaded
svi_py-0.4.0.tar.gz 73.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for svi-py 0.4.0
File Interpreter ABI Platform
svi_py-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 95.8 kB

Release files / svi_py-0.4.0.tar.gz

Download URL svi_py-0.4.0.tar.gz
Size 73.8 kB
Tags Source
SHA-256 checksum
How to use checksums
fadb5855fad4bece3e75733dba5f8eb42bf47b35dccbfa5bffbcd2b14a5034c5
BLAKE2b-256 checksum
How to use checksums
98159c46b84fd15bc805a41fd71d6280bd0696cf4e647ac7207f2f64d6974234
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 29, 2026.

Transparency log

Release files / svi_py-0.4.0-py3-none-any.whl

Download URL svi_py-0.4.0-py3-none-any.whl
Size 22.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
df0a12030b6d6eb65b45368156a5083ccf7b9e0f28df486d4b5493b59007c79d
BLAKE2b-256 checksum
How to use checksums
6398f76bbb555ac9a1782c3c373e5a8e735a29e885df68448a6ee9a9ac8f98f2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 29, 2026.

Transparency log

Release history Release notifications | RSS feed

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.1

2 release files

This release

0.4.0 This release

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page