Use case · Surfaces
Calibrate a vol surface with a fit-quality contract
calibrate_svi_surface (and its SSVI / joint-SSVI / SABR siblings) take normalized chain quotes plus a policy and return a fitted typed surface paired with a SurfaceCalibrationReport whose fit_quality() grades the fit Healthy, Acceptable, Degenerate, or Failed — so downstream code branches deterministically instead of eyeballing RMSE.
When to use it
- You need a parametric, arbitrage-aware vol surface from an option chain and want the calibration itself to tell you whether the fit is trustworthy enough to price.
- You want a typed contract that separates "can I use this surface at all" from "can I price off it" so pricing vs. readout paths are explicit.
- You need cross-tenor regularization on noisy short-DTE front-ends, or robust loss / priors to keep outlier quotes from pulling the fit.
Example
use ferro_risk::{
calibrate_svi_surface, AcceptableReason, DegeneracyReason, FailureReason, FitQuality,
SurfaceCalibrationInput, SurfaceCalibrationSearchPolicy, SviCalibrationPolicy,
};
let input = SurfaceCalibrationInput::new(market, quotes)?;
let search = SurfaceCalibrationSearchPolicy::new(200, 1e-8, 1e-10, 8)?;
let policy = SviCalibrationPolicy::new().with_search(search);
let outcome = calibrate_svi_surface(&input, &policy)?;
let report = outcome.report();
match report.fit_quality() {
FitQuality::Healthy => {
// Strict parametric pricing is OK.
let _surface = outcome.surface();
}
FitQuality::Acceptable { reason: AcceptableReason::NonConvergedRmseAcceptable(rmse) } => {
// Shape readouts only (ATM IV, RR25, term-structure) — not strict pricing.
eprintln!("acceptable: slice IV-RMSE {rmse:.4}");
}
FitQuality::Degenerate { reason } => {
// Shape-model breakdown — fall back to a non-parametric path.
eprintln!("degenerate: {reason:?}");
}
FitQuality::Failed { reason: FailureReason::NonConverged } => {
// Surface unavailable; do not price or read off it.
}
_ => {} // FitQuality and its reason enums are #[non_exhaustive]
}
# Ok::<(), ferro_risk::FerroRiskError>(())Note
FitQuality and the AcceptableReason / DegeneracyReason / FailureReason enums are #[non_exhaustive] — a downstream matchmust carry a wildcard arm or it won't compile against future minor versions.
The fit-quality contract
| FitQuality | Description |
|---|---|
| Healthy | Proven-converged (or non-converged but decisively low IV-RMSE on enough quotes). Use the parametric surface for strict pricing and readouts. |
| Acceptable { reason } | Convergence not proven but residual small enough. Use for non-pricing readouts (ATM IV, RR25, term-structure) only. |
| Degenerate { reason } | Converged to valid but untrustworthy parameters (flat smile, boundary-pinned scale, RMSE over threshold). Fall back to a non-parametric path. |
| Failed { reason } | Surface unavailable — no pricing, no readouts. |
What the calibrator gives you
- SVI / SSVI / SABR entry points, plus a joint cross-tenor Gatheral-Jacquier SSVI fit (
calibrate_joint_ssvi_surface) that shares globals to regularize noisy short-DTE slices. - Pluggable loss —
Mse(default),Huber,TrimmedMse— and per-model Bayesian-smoothing priors viawith_prior. - Quality-filtered prep and a bid-ask feasibility filter (
FeasibilityPolicy) that can penalize or drop infeasible / arbitrageable quotes. - Model-free put-call-parity forward recovery (
estimate_parity_forward/estimate_parity_forward_curve) andQuoteSourceprovenance handling. - Static-arbitrage diagnostics + repair (
diagnose_static_arbitrage, therepair_*functions) and Dupire local-vol extraction over any calibrated surface.
Notes
report.model()returnsSsvifor both per-slice and joint SSVI fits — the authoritative discriminator isreport.joint_ssvi_globals().is_some().- Policy
with_*builders are largely non-validating; full validation is deferred to the calibration entry point (so an invalid prior / parameterization pairing errors atcalibrate_*time, not at build time). - Per-slice quality is available via
SurfaceSliceCalibrationReport::fit_quality(); the surface-level grade is a roll-up across slices.