Skip to main content

Volatility Smile Modelling

Project description

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
import pandas as pd
from qsmile import OptionChain, SmileData, SmileMetadata, StrikeArray, SVIModel, XCoord, YCoord, fit

# Bid/ask prices — forward and DF are calibrated automatically
strikes = np.array([80, 90, 95, 100, 105, 110, 120], dtype=float)
idx = pd.Index(strikes, dtype=np.float64)
sa = StrikeArray()
sa.set(("call", "bid"), pd.Series([20.5, 11.8, 7.5, 4.2, 2.0, 0.8, 0.1], index=idx))
sa.set(("call", "ask"), pd.Series([21.5, 12.4, 8.0, 4.6, 2.3, 1.0, 0.2], index=idx))
sa.set(("put", "bid"), pd.Series([0.1, 0.6, 1.5, 3.1, 5.8, 9.6, 18.8], index=idx))
sa.set(("put", "ask"), pd.Series([0.2, 0.8, 1.8, 3.5, 6.2, 10.2, 19.6], index=idx))

prices = OptionChain(
    strikedata=sa,
    metadata=SmileMetadata(date=pd.Timestamp("2024-01-01"), expiry=pd.Timestamp("2024-07-01")),
)
print(prices.metadata.forward)          # Calibrated forward
print(prices.metadata.discount_factor)  # Calibrated discount factor

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

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

From mid implied vols

import numpy as np
import pandas as pd
from qsmile import SmileData, SmileMetadata, SVIModel, fit

meta = SmileMetadata(
    date=pd.Timestamp("2024-01-01"),
    expiry=pd.Timestamp("2024-07-01"),
    forward=100.0,
)

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]),
    metadata=meta,
)

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

qsmile-0.0.1rc4.tar.gz (536.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

qsmile-0.0.1rc4-py3-none-any.whl (31.2 kB view details)

Uploaded Python 3

File details

Details for the file qsmile-0.0.1rc4.tar.gz.

File metadata

  • Download URL: qsmile-0.0.1rc4.tar.gz
  • Upload date:
  • Size: 536.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for qsmile-0.0.1rc4.tar.gz
Algorithm Hash digest
SHA256 b1f74c1202c394e5238a056fdaed3cb3089cf1702e48f7d2dc54544914832e7b
MD5 beb2d3807dd7eee6bfbb5d58cd5cae29
BLAKE2b-256 e1eaab5caf28675d554d57461b38bdd4d817d52101ea90089696f645c397d550

See more details on using hashes here.

Provenance

The following attestation bundles were made for qsmile-0.0.1rc4.tar.gz:

Publisher: rhiza_release.yml on markrichardson/qsmile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file qsmile-0.0.1rc4-py3-none-any.whl.

File metadata

  • Download URL: qsmile-0.0.1rc4-py3-none-any.whl
  • Upload date:
  • Size: 31.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for qsmile-0.0.1rc4-py3-none-any.whl
Algorithm Hash digest
SHA256 d11305f03a6adf920cddc2212f4d677be6797405b044f605017a04f05fe866ee
MD5 0a651532164b79ceed95c52ae2247bc2
BLAKE2b-256 17f8c05672031e10ce47ea7014af8930fddc18cb6197b0d2912572fdd26861bb

See more details on using hashes here.

Provenance

The following attestation bundles were made for qsmile-0.0.1rc4-py3-none-any.whl:

Publisher: rhiza_release.yml on markrichardson/qsmile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page