Overview

Pricing models

Seven models dispatch through one PricingModel enum — European to American, lognormal to normal, deterministic to stochastic vol, with jumps. The model is always named explicitly at the call site.

The seven models

PricingModelDescription
BlackScholesMertonEuropean — equity-style spot options with continuous carry/dividend yield. The default workhorse.
Black76European — options on forwards and futures. Set dividend_yield = 0.0; spot is the forward.
BachelierEuropean — normal-vol options on forwards/futures. Admits zero and negative spot/strike (rates, spreads).
DisplacedBlack { displacement }European — shifted-lognormal pricing for shifted forward markets.
Heston { parameters }European — stochastic-volatility pricing via the Fang-Oosterlee COS method. volatility is sqrt(v0).
JumpDiffusion { parameters }European — Merton (1976) lognormal jump-diffusion with explicit Poisson intensity, jump-mean, and jump-std parameters.
BjerksundStenslandAmerican — the Bjerksund-Stensland 2002 two-stage exercise boundary. The production American path.

Naming a model

Unit-variant models are named directly; parameterized models carry their configuration in the variant (with const constructors for convenience):

use ferro_risk::{price, PricingInputs, PricingModel};

// unit variants
price(&inputs, PricingModel::BlackScholesMerton)?;
price(&inputs, PricingModel::Black76)?;
price(&inputs, PricingModel::BjerksundStensland)?;

// parameterized variants
price(&inputs, PricingModel::displaced_black(0.03))?;
// PricingModel::heston(...), PricingModel::jump_diffusion(...)
# Ok::<(), ferro_risk::FerroRiskError>(())

Discrete cash dividends

The PricingModel variants all take carry as a continuous dividend_yield. For listed equity options, where the underlying pays discrete cash amounts on known ex-dates, the American path accepts a DividendSchedule instead: it prices the escrowed spot S − Σ Dᵢ·e^(−r·tᵢ) through the unchanged Bjerksund-Stensland kernel.

use ferro_risk::{american_price_with_dividends, DividendEvent, DividendSchedule};

let schedule = DividendSchedule::new(vec![
    DividendEvent::new(38.0 / 365.0, 0.96)?,
])?;
let premium = american_price_with_dividends(&pricing, &schedule)?;

// The empty schedule is the exact no-dividend identity.
assert_eq!(
    american_price_with_dividends(&pricing, &DividendSchedule::empty())?.to_bits(),
    ferro_risk::american_price(&pricing)?.to_bits(),
);
# Ok::<(), ferro_risk::FerroRiskError>(())

The same schedule rides on IvSolveInputs.dividends, so implied_vol, contract_analytics, and de_americanize_quote all invert on the escrowed process. See dividends & de-Americanization.

Scope

A non-empty schedule off the BS2002 American path fails loud with UnsupportedModelExerciseCombination — the dividends are never silently dropped.

American CRR reference

Alongside the production BjerksundStensland path, an opt-in high-fidelity Cox-Ross-Rubinstein binomial reference is available for validation workflows via american_reference_price / american_reference_report. It is intentionally slower and is not a PricingModel variant — use it to check the fast approximation, not to price in production.

Accuracy

The Bjerksund-Stensland 2002 boundary used in production is a higher-fidelity approximation than common single-boundary engines; the CRR reference (run to a high step count) is the oracle it is validated against.

Dupire local volatility

Beyond the parametric models, FerroRisk extracts a Dupire local-vol surface from any calibrated surface and reprices over it with backward Crank-Nicolson PDE, forward Dupire-strip PDE, and Monte-Carlo kernels. See surface calibration.