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.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 polars-vol 0.1.0
File Size Uploaded
polars_vol-0.1.0.tar.gz 34.6 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for polars-vol 0.1.0
File
polars_vol-0.1.0-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details
polars_vol-0.1.0-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.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.9 abi3 Linux glibc 2.17+ ARM64 Details
polars_vol-0.1.0-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details
polars_vol-0.1.0-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.0.tar.gz

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

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

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

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

Download URL polars_vol-0.1.0-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
fc418ff8a27d602bbaa1b6c0db1abef450557b65ef061cfab227996ba5306edc
BLAKE2b-256 checksum
How to use checksums
3523a567376df186c8a4cd0e7edaba39ef369124813bb8e17d9617c1f4f91f0d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

Download URL polars_vol-0.1.0-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
aac060eaac47b4acfcc90a9c30e5189ba839ea1f987ad773466832e03b7f3006
BLAKE2b-256 checksum
How to use checksums
8939fbd0c16d60bb232da3325dd9821446484b02cdcb176b3cf096e056c2e0b5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

Download URL polars_vol-0.1.0-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
6cbae126806657cc6a91d439239fd6a46e9a091fd13e029431a6d9b47f451742
BLAKE2b-256 checksum
How to use checksums
0970abc228a733043e75c68aa27c309dcd80b86994c430cceb848062a5de1aa0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

Download URL polars_vol-0.1.0-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
472d587f3b9bf955160b5eea7f4c0bb620e3c88648a753c5f78dbfa53080321d
BLAKE2b-256 checksum
How to use checksums
ed7d269cb4993fbe3f84dfcb43ea456f12c419939a894bf701d33689b1884196
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release history Release notifications | RSS feed

0.1.1

6 release files

This release

0.1.0 This release

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