Use case · Volatility

Take the variance risk premium and split it into legs

variance_risk_premium turns implied and realized volatility on a shared tenor into a typed VrpRead; a JumpDiffusionFit then decomposes the premium into diffusive and jump/tail legs, and vrp_zscore normalizes it against a rolling baseline.

When to use it

  • You need the premium between implied and realized variance as a typed read, in both vol-point and variance units.
  • You want to know how much of the premium is diffusive carry versus compensation for jump/tail risk.
  • You want a normalized, tradable signal — a z-score against a baseline mean and standard deviation.

Example

use ferro_risk::{
    variance_risk_premium, vrp_decomposition, vrp_zscore,
    JumpDiffusionFit, JumpDiffusionParameters, RvMethod, SurfaceTenor,
};

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

// implied 22 vol, realized 18 vol, both on the same tenor and estimator.
let vrp = variance_risk_premium(0.22, 0.18, tenor, RvMethod::YangZhang)?;
println!("premium (vol pts) = {}", vrp.premium_vol_pts());
println!("premium (variance) = {}", vrp.premium_variance());

// Decompose using a Merton jump-diffusion fit of the implied dynamics.
let params = JumpDiffusionParameters::new(0.9, -0.02, 0.08); // intensity, jump-mean, jump-std
let fit = JumpDiffusionFit::new(0.18, params)?;
let split = vrp_decomposition(fit, vrp);
println!("diffusive VRP = {}  jump VRP = {}", split.diffusive_vrp(), split.jump_vrp());
println!("jump variance share = {}", split.jump_variance_share());

// Normalize against a rolling baseline (mean, std of the premium).
let z = vrp_zscore(vrp.premium_variance(), 0.010, 0.004)?;
println!("z-score = {}", z);
# Ok::<(), ferro_risk::FerroRiskError>(())

The reads

VrpReadDescription
premium_vol_pts()Premium expressed in volatility points (implied − realized vol).
premium_variance()Premium expressed in variance units (implied − realized variance).
implied_vol()The implied volatility input.
realized_vol()The realized volatility input.
tenor()The SurfaceTenor the premium is quoted on.
method()The RvMethod used for the realized leg.
VrpSplitDescription
diffusive_vrp()The diffusive component of the premium.
jump_vrp()The jump/tail component of the premium.
jump_variance_share()Jump share of implied variance from the fit, in [0, 1].
jump_share_of_premium()Option<f64> — literal jump fraction of the premium; None when realized ≥ implied.
premium_variance()The premium in variance units (carried from the read).

Notes

  • The realized leg must be measured with the same RvMethod and tenor the premium is quoted against — see realized volatility.
  • jump_variance_share() comes from the fit and is always in [0, 1]; jump_share_of_premium() is the literal premium fraction and can exceed 1 (or be None) when the diffusive leg is negative or realized exceeds implied.
  • The fit reuses JumpDiffusionParameters — the same Merton (1976) intensity / jump-mean / jump-std bundle the pricing engine exposes.
  • Non-finite or degenerate inputs (a zero baseline std, an overflowed jump moment) fail loud with a typed FerroRiskError in the vrp.* namespace.
Signal

vrp_zscore(premium, baseline_mean, baseline_std) is a plain standardization — pair it with your own rolling baseline to turn the premium level into a comparable signal across regimes.