Skip to main content

polars-vol

Black-Scholes pricing, analytical Greeks and implied volatility as Rust-powered Polars expressions — elementwise, columnar, and streaming-parallel.

PyPI version Python versions License: MIT Tests Docs Works with Polars

Installation

From PyPI, with pip or uv:

pip install polars-vol
uv add polars-vol            # in a uv-managed project
uv pip install polars-vol    # with the uv pip interface

From source (requires a Rust toolchain and maturin):

git clone https://github.com/p3i0t/polars_vol && cd polars_vol
pip install maturin          # or: uv pip install maturin
maturin develop --release

Wheels are abi3 (CPython ≥ 3.9) for macOS, Linux and Windows; polars ≥ 1.3 is installed automatically as a dependency.

Features

The following list are implemented as polars.Expr:

  • black_scholes(strike, spot, vol, time_to_expiry, rate, is_call) — European call/put price
  • black_scholes_with_greeks(strike, spot, vol, ...) — price and analytical Greeks (model_price, delta, gamma, vega, theta, rho) in a single pass
  • implied_vol(option_price, ...) — implied volatility from market prices, via bracketed Newton or Halley (method="halley") iteration
  • iv_and_greeks(option_price, ...) — the solved implied volatility plus all Greeks in one expression

Thanks to the polars collect(engine="streaming"), we can easily get >5x speedup than vectorized numpy.

Quick Start

import polars as pl
import polars_vol as pv

df = pl.DataFrame({
  "strike": [100, 105, 110],
  "spot": [100, 100, 100],
  "time_to_expiry": [0.5, 0.5, 0.5]
}).with_columns(rate=pl.lit(0.05), vol=pl.lit(0.2), is_call=pl.lit(True))

df = df.with_columns(
    option_price=pv.black_scholes(
        "strike", "spot", "vol", "time_to_expiry", "rate", "is_call"
    )
)
print(df)

# backfill iv from option price
iv = df.select(pv.implied_vol(
    "option_price", "strike", "spot", "time_to_expiry", "rate", "is_call"
).alias('iv'))
print(iv)

# backfill iv and greeks from option price
df.select(result=pv.iv_and_greeks(
    "option_price", "strike", "spot", "time_to_expiry", "rate", "is_call", method="newton"  # or "halley"
)).unnest("result")

Examples

SPX backfill

You may also want to see a real example on SPX examples/spx_backfill.py, where it fetches the SPX chain from Yahoo, solves the implied volatility of every option from its market mid with implied_vol, and checks the result against Yahoo's own impliedVolatility: correlation ≈ 0.997, median gap ≈ 0.003 vol points. (needs pip install yfinance).

Speed — vs vectorized numpy

Same data, same math — a hand-vectorized numpy/scipy implementation vs the plugin on Polars' streaming engine:

import timeit

import numpy as np
import polars as pl
from scipy.special import ndtr

from polars_vol import black_scholes

vol, t, r = 0.25, 1.0, 0.05
sq = vol * t**0.5

n = 20_000_000
df = pl.select(
    strike=90 + (pl.int_range(n) % 21).cast(pl.Float64),
    spot=(100 + pl.int_range(n) % 40).cast(pl.Float64),
    is_call=(pl.int_range(n) % 2 == 0),
)
k, s, ic = df["strike"].to_numpy(), df["spot"].to_numpy(), df["is_call"].to_numpy()
lf = df.lazy().with_columns(
    price=black_scholes("strike", "spot", pl.lit(vol), pl.lit(t), pl.lit(r), "is_call")
)


def numpy_price():
    d1 = (np.log(s / k) + (r + vol * vol / 2) * t) / sq
    d2 = d1 - sq
    return np.where(
        ic,
        s * ndtr(d1) - k * np.exp(-r * t) * ndtr(d2),
        k * np.exp(-r * t) * ndtr(-d2) - s * ndtr(-d1),
    )


def plugin_price():
    return lf.collect(engine="streaming").get_column("price").to_numpy()


t_np = min(timeit.repeat(numpy_price, number=1, repeat=3))
t_pl = min(timeit.repeat(plugin_price, number=1, repeat=3))
diff = (plugin_price() - numpy_price()).__abs__().max()
print(
    f"numpy {t_np:.2f}s | polars_vol {t_pl:.2f}s | {t_np / t_pl:.0f}x | max diff {diff:.1e}"
)
# -> numpy 0.46s | polars_vol 0.05s | 8x | max diff 1.5e-05  (the A&S 7.1.26 CDF error)

check examples/speed_vs_numpy.py for the full code.

MIT license.

Metadata

Release files for polars-vol 0.1.1

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

Source distribution (sdist)

Source distribution for polars-vol 0.1.1
File Size Uploaded
polars_vol-0.1.1.tar.gz 34.6 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for polars-vol 0.1.1
File
polars_vol-0.1.1-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details
polars_vol-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.9 abi3 Linux glibc 2.17+ x86-64 Details
polars_vol-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.9 abi3 Linux glibc 2.17+ ARM64 Details
polars_vol-0.1.1-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details
polars_vol-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl CPython 3.9 abi3 macOS 10.12+ x86-64 Details

Total release size: 22.4 MB

Release files / polars_vol-0.1.1.tar.gz

Download URL polars_vol-0.1.1.tar.gz
Size 34.6 kB
Tags Source
SHA-256 checksum
How to use checksums
bf4861820204e3af9cf0f0fe3f0365dd7035c30f1a21b824c7a92f82ec014a9a
BLAKE2b-256 checksum
How to use checksums
16dbcb7e0212711d6cd2132f9a4abf0541c85676d46d5f467a6c44b9bfb9bd3e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / polars_vol-0.1.1-cp39-abi3-win_amd64.whl

Download URL polars_vol-0.1.1-cp39-abi3-win_amd64.whl
Size 4.3 MB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
2e1e4af12dfad50df30f1d90ef6a9d6c83112891d5d5b3e1c84f4d6e253b2280
BLAKE2b-256 checksum
How to use checksums
b380ef8796783b86a0023b5a2ab30213c121910688854a439311d4bff2636f9f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / polars_vol-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL polars_vol-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 4.9 MB
Tags CPython 3.9 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
fa0a2e7746f71f00a0baad56ead89384e5ff33394653d0d181988a49adc38788
BLAKE2b-256 checksum
How to use checksums
cf3893208017e96f80b534b1f413fd2f93016db86c8cd6dd4d6bd1922a11e520
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / polars_vol-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL polars_vol-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 4.8 MB
Tags CPython 3.9 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
9149f562efe586798cbbc00cbd0a3a52161b03bb9066323921800b9ce1758cb5
BLAKE2b-256 checksum
How to use checksums
e5acda918137b79d40fa94ef5e0d5c8e69743eeec15271381e27838b4ee3633b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / polars_vol-0.1.1-cp39-abi3-macosx_11_0_arm64.whl

Download URL polars_vol-0.1.1-cp39-abi3-macosx_11_0_arm64.whl
Size 4.1 MB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
baf2cd2a0323f096b0a725a3c4dbc7ca12748946260d1162c336c5f929dfa096
BLAKE2b-256 checksum
How to use checksums
06507049bf60f68823e0ede69b5e45d1314425ad16d40267ce3f35d96f62e167
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / polars_vol-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl

Download URL polars_vol-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl
Size 4.2 MB
Tags CPython 3.9 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
1b552ea82519fbe529ca1d6ea0350c95a883bfa0b5d51a28fad7951079e102bc
BLAKE2b-256 checksum
How to use checksums
d26a3f8a4e89cd50b4a60ec1c245e52ed4a8b0328dd9e818e68e10d49e028402
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release history Release notifications | RSS feed

This release

0.1.1 This release

6 release files

0.1.0

6 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