Skip to main content
ProbCurve represents the risk-neutral probability distribution implied by a single-expiry option chain. You can build one directly from an option chain, or derive one from a fitted VolCurve when you want to inspect the volatility fit first. You can then query probabilities, moments, and quantiles, export a DataFrame, or render a plot.

Constructors

You normally build a ProbCurve in one of two ways:
  • Use ProbCurve.from_chain(...) when you want OIPD to fit the volatility smile and derive the probability curve in one step.
  • Use VolCurve.implied_distribution(...) when you already have a fitted VolCurve and want to reuse it.

ProbCurve.from_chain

The one-step constructor. Accepts a single-expiry option chain DataFrame and market inputs, fits an SVI smile, and derives the risk-neutral distribution.
pd.DataFrame
required
Option chain DataFrame for a single expiry. Must contain an expiry column and at least one supported price column (last_price, or bid/ask).
MarketInputs
required
Market inputs providing the risk-free rate, valuation date, and underlying price.
dict[str, str] | None
default:"None"
Optional mapping in the form {"dataframe_column": "oipd_column"}. For example, {"type": "option_type"} means your DataFrame has a type column and OIPD should treat it as option_type. See Standard columns for the target names.
int
default:"3"
Maximum age of option quotes in calendar days, relative to the valuation date. Rows older than this threshold are filtered out before fitting.
Literal['warn', 'raise']
default:"warn"
Policy for handling CDF monotonicity violations during materialization. "warn" repairs the CDF and records a diagnostic warning; "raise" raises a CalculationError on material violations.
Raises: ValueError if the chain contains multiple expiries. CalculationError if volatility calibration fails.

From a fitted VolCurve

If you have already fitted a VolCurve, call implied_distribution() on that object:
See VolCurve.implied_distribution.

Methods

Evaluate the Probability Density Function at one or more price levels.
float | np.ndarray
required
Price level or array of price levels to evaluate.
float | np.ndarray
PDF value(s). Returns a scalar float when price is a scalar, or an ndarray otherwise. Values outside the fitted domain return 0.0.
ProbCurve is also callable: prob(price) is an alias for prob.pdf(price).
Probability that the asset price at expiry is strictly below price.
float
required
Upper bound price level.
float
P(S < price), interpolated from the CDF. Returns 0.0 below the domain and 1.0 above.
Probability that the asset price at expiry is at or above price.
float
required
Lower bound price level.
float
P(S >= price). Computed as 1 - prob_below(price).
Probability that the asset price at expiry falls in the interval [low, high).
float
required
Lower bound of the interval.
float
required
Upper bound of the interval. Must be greater than or equal to low.
float
P(low <= S < high).
Raises: ValueError if low > high.
Expected value of the asset price under the fitted PDF.
float
E[S], computed by numerical integration of price × pdf over the domain.
Variance of the asset price under the fitted PDF.
float
Var[S] = E[(S - mean)²].
Skewness (third standardized moment) of the fitted PDF.
float
Skew = E[(S - μ)³] / σ³. Negative values indicate a fat left tail, which is typical for equity distributions.
Excess kurtosis (fourth standardized moment minus 3) of the fitted PDF.
float
Excess kurtosis = E[(S - μ)⁴] / σ⁴ - 3. Zero implies a normal distribution; positive values indicate fat tails.
Inverse CDF: returns the price level at which the cumulative probability equals q.
float
required
Target probability level. Must be in the open interval (0, 1).
float
Price S such that P(Asset < S) = q.
Raises: ValueError if q is not in (0, 1).
Export the fitted distribution as a DataFrame for analysis or custom plotting.
tuple[float, float] | None
default:"None"
Optional explicit export domain as (min_price, max_price). When provided, the native distribution is resampled onto this range. Takes precedence over full_domain.
int
default:"200"
Number of output rows when resampling to a compact or explicit domain. Ignored when full_domain=True and no domain is specified.
bool
default:"False"
When True and domain is not set, returns the full native distribution arrays without resampling.
pd.DataFrame
DataFrame with columns price, pdf, and cdf.
Render the risk-neutral probability distribution as a matplotlib figure.
Literal['pdf', 'cdf', 'both']
default:"both"
Which distribution curve(s) to render.
tuple[float, float]
default:"(10, 5)"
Figure size as (width, height) in inches.
str | None
default:"None"
Custom title. Auto-generated from market metadata when omitted.
tuple[float, float] | None
default:"None"
Optional explicit x-axis (price) limits.
tuple[float, float] | None
default:"None"
Optional explicit y-axis limits.
int
default:"800"
Number of display points for plot resampling.
bool
default:"False"
When True and xlim is not set, plots across the full native probability domain instead of the compact default view domain.
matplotlib.figure.Figure
The rendered matplotlib figure.

Properties

np.ndarray
The default price grid used for standard visualization. Accessing this property triggers lazy distribution materialization on first call.
np.ndarray
Probability densities over the stored price grid, in decimal form.
np.ndarray
Cumulative probabilities over the stored price grid, in decimal form.
WarningDiagnostics
Structured diagnostic events recorded during fitting and materialization. Inspect .warning_diagnostics.events for details on data-quality issues, model-risk warnings, or CDF repairs.
ResolvedMarket
Immutable snapshot of the market inputs used during calibration, including the resolved underlying price, risk-free rate, and valuation date.
dict[str, Any]
Metadata captured during estimation, including the expiry timestamp, time to expiry in years, diagnostics, and domain information.

Example