Use case · Surfaces

Run the canonical smile-panel in one call

surface_smile_risk_metrics returns the standard morning skew panel from one calibrated smile — ATM IV at the effective forward, the 25Δ and 10Δ risk reversals, and the 25Δ / 10Δ butterfly flies — replacing the handful of hand-rolled delta-to-strike lookups a desk would otherwise wire up.

When to use it

  • You have one calibrated parametric smile (SVI / SSVI / SABR) at one expiry and want the full skew panel — ATM IV, RR25, RR10, fly25, fly10 — in one round trip.
  • You want both delta pairs computed against the same effective forward and market context, so the two ATM IVs agree by construction.
  • You need per-wing snap-to-listed-strike output plus bracket-quality diagnostics for readiness / degradation signals.

Example

use ferro_risk::{
    surface_smile_risk_metrics, PricingModel, SurfaceDeltaConvention,
    SurfaceSmileDeltaSelectionPolicy,
};

// `smile` is a calibrated SviSmile / SsviSlice / SabrSmile; `market` is the
// SurfaceMarketContext used to calibrate it. `listed_strikes` is the venue grid.
let metrics = surface_smile_risk_metrics(
    &smile,
    &market,
    SurfaceDeltaConvention::Forward,
    PricingModel::BlackScholesMerton,
    SurfaceSmileDeltaSelectionPolicy::default(),
    &listed_strikes,
)?;

let atm_iv = metrics.atm_iv();              // ATM IV at the effective forward
let rr_25  = metrics.rr_25().risk_reversal(); // call_iv - put_iv at 25Δ
let rr_10  = metrics.rr_10().risk_reversal(); // call_iv - put_iv at 10Δ
let fly_25 = metrics.fly_25();              // 25Δ butterfly fly
let fly_10 = metrics.fly_10();              // 10Δ butterfly fly

// Per-wing bracket diagnostics on the 25Δ put wing.
let put = metrics.rr_25().put_wing();
let snap_distance = put.bracket_delta_distance(); // delta-space snap-to-target gap
let lever_arm     = put.bracket_spread();         // Option<f64>: interpolation width
# Ok::<(), ferro_risk::FerroRiskError>(())

The readout

AccessorDescription
metrics.atm_iv()Smile IV at the effective forward.
metrics.rr_25() / rr_10()The 25Δ / 10Δ risk reversal (each with its own wings, butterfly, and ATM IV).
metrics.fly_25() / fly_10()25Δ / 10Δ butterfly fly.
.risk_reversal()On a risk reversal: call-wing IV minus put-wing IV, in decimal vol.
.put_wing() / .call_wing()The two wings of a risk reversal.
wing.theoretical_strike()Strike from the continuous delta inversion — where IV is read.
wing.selected_strike()Nearest eligible listed strike (for order routing).
wing.bracket_delta_distance()Snap-to-target distance: |Δ|-space gap between the requested target and the selected strike. Zero on an exact listed-strike hit.
wing.bracket_spread()Interpolation lever-arm: the |Δ|-space width of the bracket. None on the continuous parametric path.

Notes

  • SurfaceDeltaConvention has two variants: Forward (undiscounted forward delta — the typical desk choice) and Spot (PV-sensitivity delta, scaled by the discount factor).
  • IVs, RR, and flies are computed at the theoretical strikes, so the numbers track the requested delta rather than the snapped grid; selected_strike() is for routing.
  • The two bracket diagnostics are orthogonal — two wings can both read Interpolated yet differ in trustworthiness. Threshold on both bracket_delta_distance() and bracket_spread() instead of trusting the binary quality flag.
  • The 25Δ RR is computed first and short-circuits on failure — a chain whose 25Δ wings are uninvertible yields no result. Call surface_smile_risk_reversal at |Δ| = 0.10 directly if you need independent tail metrics.
Note

The bundle is a single source of truth: atm_iv(), fly_25(), and fly_10() are accessors over the two risk reversals, not separately stored fields.