Use case · Volatility

Read implied correlation and dispersion from a basket

implied_correlation takes an index implied vol and a slice of typed BasketConstituent weights and IVs on a shared tenor, and returns a DispersionRead — the average pairwise correlation the market is pricing, plus the dispersion premium.

When to use it

  • You need the option-implied average pairwise correlation between an index and its constituents.
  • You want the dispersion premium — the gap between weighted-average constituent vol and the index vol — in variance and vol-point units.
  • You need the intermediate legs (weighted-average variance, uncorrelated index variance) rather than a single opaque number.

Example

use ferro_risk::{implied_correlation, BasketConstituent, SurfaceTenor};

let tenor = SurfaceTenor::new(30.0 / 365.0)?; // 30-day tenor, in years

// Each constituent: implied vol and index weight.
let constituents = vec![
    BasketConstituent::new(0.28, 0.35)?,
    BasketConstituent::new(0.24, 0.40)?,
    BasketConstituent::new(0.31, 0.25)?,
];

// index_iv is the index's own implied vol on the same tenor.
let read = implied_correlation(0.19, &constituents, tenor)?;

println!("implied correlation = {}", read.rho_implied());
println!("dispersion (variance) = {}", read.dispersion_variance());
println!("dispersion (vol pts) = {}", read.dispersion_vol_pts());
println!("weighted-avg vol = {}", read.weighted_avg_vol());
# Ok::<(), ferro_risk::FerroRiskError>(())

The read

DispersionReadDescription
rho_implied()The implied average pairwise correlation — raw and unclamped.
dispersion_variance()Dispersion premium in variance units (weighted-avg variance − index variance).
dispersion_vol_pts()Dispersion premium in volatility points (weighted-avg vol − index vol).
index_iv()The index implied volatility input.
weighted_avg_vol()Weight-weighted average constituent volatility.
weighted_avg_var()Weight-weighted average constituent variance.
uncorrelated_index_var()Index variance implied if constituents were uncorrelated.
weight_sum()Sum of the constituent weights.
constituent_count()Number of constituents in the basket.
tenor()The SurfaceTenor the read is quoted on.

Notes

  • rho_implied() is reported raw and unclamped — a value outside [-1, 1] is surfaced rather than hidden, so you can see when the inputs imply an out-of-range correlation.
  • The index and every constituent IV must be quoted on the same SurfaceTenor — the same type used across the surface and VRP workflows.
  • BasketConstituent::new(iv, weight) validates each constituent up front, so a non-positive weight or a non-finite IV is rejected at construction.
  • A basket needs at least two constituents; degenerate baskets and a zero denominator fail loud with a typed FerroRiskError in the implied_correlation.* namespace.
Related

Dispersion sits beside the variance risk premium and realized volatility in the volatility-analytics layer — all three share the SurfaceTenor contract.