1. Compute market-implied probability distributions of future asset prices.
- While markets don't predict the future with certainty, under the efficient market view, these market expectations represent the best available estimate of what might happen.
2. Fit arbitrage-free volatility smiles and surfaces for pricing and risk analysis.
- Fitting a vol surface well is a complex and expensive process, with the leading software provider costing $50k USD/month/seat. OIPD open-sources the entire pipeline fairly rigorously, with further improvements in the roadmap.
|
|
See the full documentation site for details.
pip install oipdTip
For non-technical users, you can safely skip this section and jump to Section 3 to compute future market-implied probabilities.
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.)
This quickstart will cover the functionality in (1) computing market-implied probabilities. See the included jupyter notebook for a full example on using the automated yfinance connection to download options data and compute market-implied probabilities for Palantir.
For a more technical tutorial including the functionality of (2) volatility fitting, see the additional jupyter notebooks in the examples directory, as well as the full documentation.
import matplotlib.pyplot as plt
from oipd import MarketInputs, ProbCurve, sources
# 1. we download data using the built-in yfinance connection
ticker = "PLTR" # specify the stock ticker
expiries = sources.list_expiry_dates(ticker) # see all expiry dates
single_expiry = expiries[1] # select one of the expiry dates you're interested in
chain, snapshot = sources.fetch_chain(ticker, expiries=single_expiry) # download the options chain data, and a snapshot at the time of download
# 2. fill in the parameters
market = MarketInputs(
valuation_date=snapshot.date, # date on which the options data was downloaded
underlying_price=snapshot.underlying_price, # the price of the underlying stock at the time when the options data was downloaded
risk_free_rate=0.04, # the risk-free rate of return. Use the US Fed or Treasury yields that are closest to the horizon of the expiry date
)
# 3. compute the future probability distribution using the data and parameters
prob = ProbCurve.from_chain(chain, market)
# 4. query the computed result to understand market-implied probabilities and other statistics
prob.plot()
plt.show()
prob_below = prob.prob_below(100) # P(price < 100)
prob_above = prob.prob_above(120) # P(price >= 120)
q50 = prob.quantile(0.50) # median implied price
skew = prob.skew() # skewimport matplotlib.pyplot as plt
from oipd import MarketInputs, ProbSurface, sources
# 1. download multi-expiry data using the built-in yfinance connection
ticker = "PLTR"
chain_surface, snapshot_surface = sources.fetch_chain(
ticker,
horizon="12m", # auto-fetch all listed expiries inside the horizon
)
# 2. fill in the parameters
surface_market = MarketInputs(
valuation_date=snapshot_surface.date, # date on which the options data was downloaded
underlying_price=snapshot_surface.underlying_price, # price of the underlying stock at download time
risk_free_rate=0.04, # risk-free rate for the horizon
)
# 3. compute the probability surface using the data and parameters
surface = ProbSurface.from_chain(chain_surface, surface_market)
# 4. query and visualize the surface
surface.plot_fan() # Plot a fan chart of price probability over time
plt.show()
# 5. query at arbitrary maturities directly from ProbSurface
pdf_45d = surface.pdf(100, t=45/365) # density at K=100, 45 days
cdf_45d = surface.cdf(100, t="2025-02-15") # equivalent date-style maturity input
q50_45d = surface.quantile(0.50, t=45/365) # median at 45 days
# 6. "slice" the surface to get a ProbCurve, and query its statistical properties in the same manner as in example A
surface.expiries # list all the expiry dates that were captured
curve = surface.slice(surface.expiries[0]) # get a slice on the first expiry
curve.prob_below(100) # query probabilities and statistics
curve.kurtosis() OIPD also supports manual CSV or DataFrame uploads.
See more examples for demos.
Pull requests welcome! Reach out on GitHub issues to discuss design choices.
Join the Discord community to share ideas, discuss strategies, and get support. Message me with your feature requests, and let me know how you use this.
Thanks to everyone who has contributed code:
And special thanks for support on theory, implementation, or advisory:
- integral-alpha.com
- Jannic H., Chun H. H., and Melanie C.
- and others who prefer to go unnamed





