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 pricesOptionChainPrices 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 OptionChainPrices, SmileData, XCoord, YCoord, fit_svi

# Bid/ask prices — forward and DF are calibrated automatically
prices = OptionChainPrices(
    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_svi(sd_vols)
print(result.params)   # Fitted SVIParams
print(result.rmse)     # Root mean square error

From mid implied vols

import numpy as np
from qsmile import SmileData, fit_svi

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_svi(sd)
print(result.params)   # Fitted SVIParams
print(result.rmse)     # Root mean square error

API Reference

Data containers

Class Description
OptionChainPrices 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

OptionChainPrices ─── .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

SVI fitting

Function / Class Description
fit_svi(chain) Fit SVI params from SmileData
SmileResult Fitted result with .params, .rmse, .fitted_vols
SVIParams SVI parameters (a, b, rho, m, sigma)
svi_total_variance(k, params) Evaluate SVI total variance at log-moneyness k
svi_implied_vol(k, params, expiry) Evaluate SVI implied vol at log-moneyness 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.1rc3.tar.gz (417.0 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.1rc3-py3-none-any.whl (17.4 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for qsmile-0.0.1rc3.tar.gz
Algorithm Hash digest
SHA256 d8a75f0e1065f497a9c3480f78209b9d807d9e9571f070c900c12dca100df361
MD5 3da2443ab2d640c204f524a3345d6c9d
BLAKE2b-256 e7efa92872c399d7607e8f05f9845b7f70dde71ce21fecc7646ad45396dfc605

See more details on using hashes here.

Provenance

The following attestation bundles were made for qsmile-0.0.1rc3.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.1rc3-py3-none-any.whl.

File metadata

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

File hashes

Hashes for qsmile-0.0.1rc3-py3-none-any.whl
Algorithm Hash digest
SHA256 cede35f58e24fcc4cbb022e5f02415ab94dca2a628b87c9568256cb84e95dd23
MD5 f8bd2b6a50bd1902ccf2176800d0d49e
BLAKE2b-256 d596e154ea67dc1271adf5f37644d0266c0cb2ae68a34c5831708317512a9e2f

See more details on using hashes here.

Provenance

The following attestation bundles were made for qsmile-0.0.1rc3-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