use volsurf::surface::{EssviSlice, SsviSlice};
use volsurf::{SmileSection, Strike};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let slice = EssviSlice::new(100.0, 1.0, -0.4, 0.6, 0.5, 0.04)?;
println!("=== eSSVI Slice ===");
println!(
"Forward: {:.0} Expiry: {:.2}Y θ: {:.4}",
slice.forward(),
slice.expiry(),
slice.theta()
);
println!(
"ρ(θ): {:.2} η: {:.1} γ: {:.1}",
slice.rho(),
slice.eta(),
slice.gamma()
);
println!();
println!("{:<10} {:>10} {:>12}", "Strike", "Vol (%)", "Variance");
println!("{:-<10} {:-<10} {:-<12}", "", "", "");
for &k in &[80.0, 85.0, 90.0, 95.0, 100.0, 105.0, 110.0, 115.0, 120.0] {
let vol = slice.vol(Strike(k))?;
let var = slice.variance(Strike(k))?;
println!("{:<10.0} {:>10.2} {:>12.6}", k, vol.0 * 100.0, var.0);
}
println!();
let ssvi = SsviSlice::new(100.0, 1.0, -0.4, 0.6, 0.5, 0.04)?;
println!("=== Equivalence Check (eSSVI vs SSVI, same ρ) ===");
let mut max_diff = 0.0_f64;
for &k in &[70.0, 80.0, 90.0, 100.0, 110.0, 120.0, 130.0] {
let v1 = slice.vol(Strike(k))?.0;
let v2 = ssvi.vol(Strike(k))?.0;
let diff = (v1 - v2).abs();
max_diff = max_diff.max(diff);
}
println!("Max vol difference across 7 strikes: {:.1e}", max_diff);
println!();
let report = slice.is_arbitrage_free()?;
println!("=== Arbitrage Check ===");
println!("Butterfly arb-free: {}", report.is_free());
if !report.butterfly_violations.is_empty() {
println!("Violations: {}", report.butterfly_violations.len());
}
println!();
let json = serde_json::to_string_pretty(&slice)?;
println!("=== Serde ===");
println!("{json}");
let restored: EssviSlice = serde_json::from_str(&json)?;
println!(
"Round-trip ATM vol: {:.6} → {:.6}",
slice.vol(Strike(100.0))?.0,
restored.vol(Strike(100.0))?.0
);
println!();
println!("=== Short vs Long Tenor (different ρ) ===");
let short = EssviSlice::new(100.0, 0.05, -0.7, 0.6, 0.5, 0.002)?;
let long = EssviSlice::new(100.0, 2.0, -0.3, 0.6, 0.5, 0.08)?;
println!(
"1M (ρ=-0.70): ATM vol = {:.2}%",
short.vol(Strike(100.0))?.0 * 100.0
);
println!(
"2Y (ρ=-0.30): ATM vol = {:.2}%",
long.vol(Strike(100.0))?.0 * 100.0
);
let skew_short = short.vol(Strike(95.0))?.0 - short.vol(Strike(105.0))?.0;
let skew_long = long.vol(Strike(95.0))?.0 - long.vol(Strike(105.0))?.0;
println!("1M skew (95-105): {:.2} vol pts", skew_short * 100.0);
println!("2Y skew (95-105): {:.2} vol pts", skew_long * 100.0);
Ok(())
}