Skip to content

markrichardson/qsmile

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

49 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

qsmile

Quantitative Smile Modelling

License: MIT Python versions

Github Linux macOS Code style: ruff uv Hatch project

CI PRE-COMMIT DEPTRY MARIMO

Volatility smile fitting for quantitative finance


Overview

qsmile is a Python library for fitting parametric volatility smile models to option chain data. It provides bid/ask-aware data containers, Black76 pricing, forward/discount-factor calibration, and least-squares SVI calibration out of the box.

Key capabilities

  • Bid/ask option pricesOptionChain stores bid/ask call and put prices, and automatically calibrates the forward and discount factor from put-call parity using quasi-delta weighted least squares.
  • Coordinate transformsSmileData is a unified container with .transform(x, y) to freely convert between any combination of X-coordinates (Strike, Moneyness, Log-Moneyness, Standardised) and Y-coordinates (Price, Volatility, Variance, Total Variance) via composable, invertible maps.
  • SVI fitting — Fit the SVI raw parameterisation to SmileData:

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

where $k = \ln(K/F)$ is log-moneyness and $w$ is total implied variance.

  • Black76 pricing — Vectorised call/put pricing and implied vol inversion via black76_call, black76_put, and black76_implied_vol.
  • Plotting — All chain types have a .plot() method for bid/ask error-bar charts (requires qsmile[plot]).

Installation

pip install qsmile            # core
pip install "qsmile[plot]"    # with matplotlib plotting

For development:

git clone https://github.com/markrichardson/qsmile.git
cd qsmile
make install

Quick Start

From bid/ask prices (full pipeline)

import numpy as np
from qsmile import OptionChain, SmileData, SVIModel, XCoord, YCoord, fit

# Bid/ask prices — forward and DF are calibrated automatically
prices = OptionChain(
    strikes=np.array([80, 90, 95, 100, 105, 110, 120], dtype=float),
    call_bid=np.array([20.5, 11.8, 7.5, 4.2, 2.0, 0.8, 0.1]),
    call_ask=np.array([21.5, 12.4, 8.0, 4.6, 2.3, 1.0, 0.2]),
    put_bid=np.array([0.1, 0.6, 1.5, 3.1, 5.8, 9.6, 18.8]),
    put_ask=np.array([0.2, 0.8, 1.8, 3.5, 6.2, 10.2, 19.6]),
    expiry=0.5,
)
print(prices.forward)          # Calibrated forward
print(prices.discount_factor)  # Calibrated discount factor

# Enter the coordinate transform framework
sd = prices.to_smile_data()                                      # (FixedStrike, Price)
sd_vols = sd.transform(XCoord.FixedStrike, YCoord.Volatility)    # → implied vols
sd_unit = sd_vols.transform(XCoord.StandardisedStrike, YCoord.TotalVariance)  # → unitised

# Fit SVI directly from SmileData
result = fit(sd_vols, model=SVIModel)
print(result.params)   # Fitted SVIModel
print(result.rmse)     # Root mean square error

From mid implied vols

import numpy as np
from qsmile import SmileData, SVIModel, fit

sd = SmileData.from_mid_vols(
    strikes=np.array([80, 90, 100, 110, 120], dtype=float),
    ivs=np.array([0.28, 0.22, 0.18, 0.17, 0.19]),
    forward=100.0,
    expiry=0.5,
)

result = fit(sd, model=SVIModel)
print(result.params)   # Fitted SVIModel
print(result.rmse)     # Root mean square error

API Reference

Data containers

Class Description
OptionChain Bid/ask call and put prices with automatic forward/DF calibration
SmileData Unified coordinate-labelled container with .transform(x, y) and .from_mid_vols() factory

Coordinate transforms

OptionChain ─── .to_smile_data() ──→ SmileData ─── .transform(x, y) ──→ SmileData
SmileData.from_mid_vols(...)            ──→ SmileData ───────────────────────────┘
Coordinate type Values
X-coordinates FixedStrike, MoneynessStrike, LogMoneynessStrike, StandardisedStrike
Y-coordinates Price, Volatility, Variance, TotalVariance

Smile fitting

Function / Class Description
fit(chain, model) Fit any SmileModel to SmileData — generic entry point
SmileModel Protocol for pluggable smile models (native coords, bounds, evaluate, etc.)
AbstractSmileModel Abstract base dataclass with default to_array()/from_array() derived from param_names
SmileResult Fitted result with .params, .residuals, .rmse, .success, .evaluate(x)
SVIModel SVI model and parameter values (a, b, rho, m, sigma) with .evaluate(k) and .implied_vol(k, T)
SABRModel SABR model (alpha, beta, rho, nu) with Hagan (2002) lognormal implied vol .evaluate(k)

Black76 pricing

Function Description
black76_call(F, K, D, σ, T) Vectorised Black76 call price
black76_put(F, K, D, σ, T) Vectorised Black76 put price
black76_implied_vol(price, F, K, D, T) Implied vol inversion via Brent's method

Development

make install   # Set up environment
make test      # Run tests with coverage
make fmt       # Format and lint
make marimo    # Launch interactive notebooks

License

MIT — see LICENSE for details.

About

Volatility Smile Modelling

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors