User Guide
This page gives a practical map of how to use OIPD.
1. High-Level Mental Model
OIPD has four core objects.
A simple way to understand the package is by use case: fitting at a single future date vs over time, and working in implied volatility vs probabilities.
| Scope | Volatility Layer | Probability Layer |
|---|---|---|
| Single future date | VolCurve | ProbCurve |
| Future time horizon | VolSurface | ProbSurface |
You can think about the lifecycle in three steps:
- Initialize the estimator object with configuration.
- Call
.fit(chain, market)to calibrate. - Query/plot the fitted object, or convert from vol to probability via
.implied_distribution().
If you’re familiar with scikit-learn, this is the same mental model: configure an estimator, call fit, then inspect outputs.
Conceptual flow:
Step 1: Fit volatility
Initialize VolCurve / VolSurface object
+ options chain + market inputs
-> .fit(...)
-> fitted VolCurve / VolSurface object (inspect IV, prices, greeks, etc.)
Step 2: Convert fitted volatility to probability
Use fitted VolCurve / VolSurface
-> .implied_distribution()
-> ProbCurve / ProbSurface object (inspect PDF, CDF, quantiles, moments, etc.)
Shortcut for computing probabilities:
If you only care about probability and do not want to manually manage the volatility step, use the convenience constructors shown in README.md (ProbCurve.from_chain(...) and ProbSurface.from_chain(...)): OIPD will run the volatility fitting and probability distribution conversion in the background.
2. How To Call fit In Practice
2.1 Load option data
Local CSV/DataFrame route:
from oipd import sources
COLUMN_MAPPING = {
"strike": "strike",
"last_price": "last_price",
"bid": "bid",
"ask": "ask",
"expiration": "expiry",
"type": "option_type",
}
chain = sources.from_csv("data/AAPL_data.csv", column_mapping=COLUMN_MAPPING)
Vendor route (automated yfinance fetch via sources):
from oipd import sources
# choose one: explicit expiries or horizon
chain, snapshot = sources.fetch_chain(
ticker="AAPL",
horizon="3m",
vendor="yfinance",
)
2.2 Define MarketInputs
MarketInputs stores the required parameters for the Black-Scholes formula. It always needs:
risk_free_ratevaluation_dateunderlying_price
Example:
from oipd import MarketInputs
market = MarketInputs(
risk_free_rate=0.04,
valuation_date=snapshot.date, # or a fixed date
underlying_price=snapshot.underlying_price, # set explicitly if snapshot is unavailable
# optional:
# risk_free_rate_mode="annualized", # default
# dividend_yield=0.01,
)
2.3 Fit single-expiry (VolCurve) or multi-expiry (VolSurface)
Single-expiry example:
from oipd import VolCurve
expiry = "2026-01-16"
chain_one_expiry = chain[chain["expiry"] == expiry].copy()
vol_curve = VolCurve()
vol_curve.fit(chain_one_expiry, market)
# optional downstream conversion to probability
prob_curve = vol_curve.implied_distribution()
Multi-expiry example:
from oipd import VolSurface
vol_surface = VolSurface()
vol_surface.fit(chain, market) # chain contains multiple expiries
# optional downstream conversion to probability
prob_surface = vol_surface.implied_distribution()
3. Surface Objects and slice(...)
Both surface objects support slicing:
VolSurface.slice(expiry)returns aVolCurve.ProbSurface.slice(expiry)returns aProbCurve.
After slicing, you can use the same methods you would use on regular curve objects (implied_vol, price, greeks, iv_results for volatility curves; pdf, prob_below, quantile, plot for probability curves).
# volatility surface -> volatility curve snapshot
vol_curve_slice = vol_surface.slice("2026-01-16")
iv_at_250 = vol_curve_slice.implied_vol(250)
# probability surface -> probability curve snapshot
prob_curve_slice = prob_surface.slice("2026-01-16")
p_below_240 = prob_curve_slice.prob_below(240)
4. Overview of all API methods
Volatility API Methods Comparison
| Feature / Action | VolCurve (Single Expiry) | Description (Curve) | VolSurface (Multi Expiry) | Description (Surface) |
|---|---|---|---|---|
| Calibration | fit(chain, market) | Calibrate model to one expiry. | fit(chain, market) | Calibrate multiple expiries. |
| Implied Volatility | implied_vol(K) | Get $\sigma$ for strike $K$. | implied_vol(K, t) | Get $\sigma$ for strike $K$ and time $t$. |
| Total Variance | total_variance(K) | Get $w = \sigma^2 t$. | total_variance(K, t) | Get $w = \sigma^2 t$ (interpolated). |
| Option Pricing | price(K, call_put) | Theoretical option price. | price(K, t, call_put) | Price at arbitrary time $t$. |
| ATM Volatility | atm_vol (property) | ATM Vol level. | atm_vol(t) | ATM Vol term structure at $t$. |
| Forward Price | forward_price (property) | Parity-implied forward $F$. | forward_price(t) | Interpolated forward $F(t)$. |
| Greeks (Bulk) | greeks(K) | DataFrame of all Greeks. | greeks(K, t) | DataFrame of interpolated Greeks. |
| Individual Greeks | delta, gamma, vega… | Partials w.r.t $S, \sigma, t, r$. | delta, gamma, vega… | Interpolated Greeks at $(K, t)$. |
| Calibration Data | iv_results() | DataFrame of fitted vs market. | iv_results() | Long-format DataFrame of all fits. |
| Parameters | params | Fitted coeffs (SVI a, b...). | params (dict) | Dict of {expiry: params}. |
| Slicing | slice(expiry) | Extract a VolCurve snapshot. | ||
| Expiries | expiries (1-tuple) | Single expiry date. | expiries (list) | List of fitted expiry dates. |
| Distributions | implied_distribution() | Get ProbCurve (RND). | implied_distribution() | Get ProbSurface (RND Surface). |
| Visualization (2D curve) | plot() | Plot fitted smile vs market. | plot() | Overlayed IV smiles. |
| Visualization (3D surface) | plot_3d() | Isometric 3D volatility surface. | ||
| Term Structure | plot_term_structure() | Interpolated ATM-forward IV term structure vs days to expiry. |
Probability API Methods Comparison
| Feature / Action | ProbCurve (Single Expiry) | Description (Curve) | ProbSurface (Multi Expiry) | Description (Surface) |
|---|---|---|---|---|
| Construction (Convenience) | from_chain(chain, market, ...) | One-line constructor: fits SVI on a single-expiry chain, then builds ProbCurve. | from_chain(chain, market, ...) | One-line constructor: fits SVI across expiries, then builds ProbSurface. |
| Construction (From Vol) | via VolCurve.implied_distribution() | Build a ProbCurve from a fitted VolCurve. | via VolSurface.implied_distribution() | Build a ProbSurface from a fitted VolSurface. |
| Density (PDF) | pdf(S) | Probability density at price $S$. | pdf(S, t) | Probability density at price $S$ for a given maturity t. |
| Callable Alias | __call__(S) | Alias for pdf(S). | __call__(S, t) | Alias for pdf(S, t). |
| CDF | prob_below(S) | Cumulative distribution function at price $S$. | cdf(S, t) | CDF at price $S$ for maturity t. |
| Tail Probabilities | prob_above(S), prob_between(L, H) | Upper tail and interval probabilities. | slice(expiry).prob_above(S), slice(expiry).prob_between(L, H) | Tail methods are exposed on the sliced ProbCurve. |
| Quantile | quantile(q) | Inverse CDF (price at probability $q$). | quantile(q, t) | Direct surface quantile query at maturity t (also available via slice(expiry).quantile(q)). |
| Moments | mean(), variance(), skew(), kurtosis() | Distribution moments. | slice(expiry).mean() etc. | Moments for a selected expiry. |
| Grid Access | prices, pdf_values, cdf_values | Cached evaluation grid for plots and queries. | slice(expiry).prices etc. | Grid for a selected expiry. |
| Visualization (2D) | plot(kind=...) | PDF/CDF plot for one expiry. | plot_fan() | Fan chart of quantile bands over expiries. |
| Metadata / Expiries | resolved_market, metadata | Market snapshot + fit metadata. | expiries | Available expiry dates. |
| Slicing | slice(expiry) | Extract a ProbCurve snapshot. |