use regit_svi::arbitrage::butterfly_scan;
use regit_svi::calibration::ssvi::{PhiFamily, SsviMaturity, calibrate as calibrate_ssvi};
use regit_svi::calibration::{calibrate_slice, quasi_explicit};
use regit_svi::convert::{jw_to_raw, raw_to_jw};
use regit_svi::density::density_report;
use regit_svi::ssvi::{Phi, Ssvi};
use regit_svi::surface::Surface;
use regit_svi::types::Quote;
fn main() {
let quotes = [
Quote::new(-0.20, 0.0512, 1.0).unwrap(),
Quote::new(-0.10, 0.0432, 1.0).unwrap(),
Quote::new(0.00, 0.0400, 1.0).unwrap(),
Quote::new(0.10, 0.0420, 1.0).unwrap(),
Quote::new(0.20, 0.0480, 1.0).unwrap(),
];
let fit = calibrate_slice("es).expect("calibration");
let svi = fit.slice;
println!("Calibrated raw SVI slice");
println!(" a = {:.6} b = {:.6} rho = {:.6}", svi.a, svi.b, svi.rho);
println!(" m = {:.6} sigma = {:.6}", svi.m, svi.sigma);
println!(" RMSE = {:.3e}", fit.rmse);
println!(" butterfly-free = {}", fit.butterfly_free);
let qe = quasi_explicit::calibrate("es).expect("quasi-explicit");
println!(" quasi-explicit RMSE = {:.3e}", qe.rmse);
let w = svi.total_variance(0.05);
let vol = svi.implied_vol(0.05, 1.0).expect("vol"); println!("\nAt k = 0.05: w = {w:.6}, implied vol = {vol:.4}");
println!("ATM variance = {:.6}", svi.atm_total_variance());
println!("ATM skew = {:.6}", svi.atm_skew());
let jw = raw_to_jw(&svi, 1.0).expect("raw -> JW");
println!("\nJump-Wings view (t = 1y)");
println!(" v_t = {:.6} psi_t = {:.6}", jw.v_t, jw.psi_t);
println!(" p_t = {:.6} c_t = {:.6}", jw.p_t, jw.c_t);
let back = jw_to_raw(&jw).expect("JW -> raw");
println!(
" round-trip max param error: {:.2e}",
(back.a - svi.a).abs()
);
let report = butterfly_scan(&svi, -0.5, 0.5);
println!("\nButterfly scan");
println!(" is_free = {}", report.is_free);
println!(
" min g(k) = {:.6} at k = {:.4}",
report.min_g, report.worst_k
);
let density = density_report(&svi, -6.0, 6.0, 2000);
println!("\nRisk-neutral density");
println!(" integral over [-6, 6] = {:.6}", density.integral);
println!(" non-negative = {}", density.is_non_negative);
let truth = Ssvi::new(-0.3, Phi::power_law(0.5, 0.5).unwrap()).unwrap();
let ks = [-0.3, -0.15, 0.0, 0.15, 0.3];
let maturities: Vec<SsviMaturity> = [(0.5, 0.02), (1.0, 0.04), (2.0, 0.07)]
.iter()
.map(|&(t, theta)| SsviMaturity {
t,
theta,
quotes: ks
.iter()
.map(|&k| Quote::new(k, truth.total_variance(k, theta), 1.0).unwrap())
.collect(),
})
.collect();
let ssvi_fit = calibrate_ssvi(&maturities, PhiFamily::PowerLaw).expect("SSVI calibration");
println!("\nSSVI surface calibration");
println!(" rho = {:.6}", ssvi_fit.ssvi.rho);
println!(" RMSE = {:.3e}", ssvi_fit.rmse);
println!(" arbitrage-free = {}", ssvi_fit.arbitrage_free);
let surface = Surface::from_ssvi(
ssvi_fit.ssvi,
maturities.iter().map(|m| (m.t, m.theta)).collect(),
)
.expect("surface");
let w_interp = surface.total_variance(0.05, 1.5);
let vol_interp = surface.implied_vol(0.05, 1.5).expect("surface vol");
println!("\nSurface at (k = 0.05, T = 1.5y)");
println!(" w = {w_interp:.6}, implied vol = {vol_interp:.4}");
println!(" calendar-free = {}", surface.is_calendar_free(-0.4, 0.4));
}