Use case · Pricing

Solve IV, forward, and Greeks in one call

When a workload needs solved implied volatility AND the explicit forward AND the full Greek set on the same contract, contract_analytics fuses them on one internal evaluation path — the Greeks reuse the solved price rather than recomputing a base point.

When to use it

  • You have an observed market price and contract terms (no volatility) and need solved IV, the forward, and the Greeks computed together.
  • High-throughput per-contract analytics — option-chain rows, spread legs — where reusing the solved price for the Greek base point matters.
  • The IV solve is driven by Jaeckel's Let's-Be-Rational rational-cubic solver to machine precision (bisection fallback on the European Black paths).

Example

use ferro_risk::{contract_analytics, ExerciseStyle, IvSolveInputs, OptionType, PricingModel};

// Contract terms WITHOUT volatility — volatility is what we solve for.
let inputs = IvSolveInputs {
    option_type: OptionType::Call,
    exercise_style: ExerciseStyle::European,
    spot: 100.0,
    strike: 100.0,
    time_to_expiry: 0.5,
    rate: 0.03,
    dividend_yield: 0.01,
};

let market_price = 6.10; // observed option price

let analytics = contract_analytics(&inputs, market_price, PricingModel::BlackScholesMerton)?;

let implied_vol = analytics.iv.iv;        // solved sigma
let forward     = analytics.forward;      // undiscounted forward / futures
let model_price = analytics.greeks.price; // price at the solved IV
let delta       = analytics.greeks.delta;
let converged   = !analytics.iv.used_fallback;
# Ok::<(), ferro_risk::FerroRiskError>(())

The result

ContractAnalyticsResult bundles three things:

FieldDescription
forwardUndiscounted forward / futures price implied by the contract; collapses to spot at exact expiry.
ivAn IvResult: iv (solved sigma), iterations, used_fallback, price_residual, price_residual_unit.
greeksThe full Greeks set evaluated at the solved IV; greeks.price differs from the market price by the IV residual.

Notes

  • IvSolveInputs has no volatility field — that is the unknown. Use with_volatility(σ) to convert it to a PricingInputs.
  • used_fallback is true only when the rational solver falls back to bisection. For Bachelier it is always false (bisection over normal vol is canonical); for American Bjerksund-Stensland it is true on every live non-exact solve.
  • Residual units differ by model family — check iv.price_residual_unit (ForwardNormalisedPrice vs ModelPrice) before comparing residuals across models.
Batch

contract_analytics_batch(&[(IvSolveInputs, f64, PricingModel)]) -> Vec<Result<ContractAnalyticsResult, FerroRiskError>> runs each contract in parallel via Rayon, preserves order, and isolates per-contract failures.