# volsurf
[](https://github.com/volsurf-rs/volsurf/actions/workflows/ci.yml)
[](https://crates.io/crates/volsurf)
[](https://docs.rs/volsurf)
[](LICENSE)
Production-ready volatility surface construction for equity and FX derivatives.
`volsurf` builds implied volatility surfaces from market data, calibrates parametric smile models (SVI, SABR, SSVI), detects butterfly and calendar arbitrage, and provides sub-20ns vol queries suitable for real-time pricing engines.
## Features
**Smile Models**
- **SVI** (Gatheral 2006) -- 5-parameter with quasi-explicit calibration (Zeliade 2009), analytical g-function density, butterfly arbitrage detection
- **SABR** (Hagan 2002) -- 4-parameter with Hagan closed-form, analytic alpha + Nelder-Mead calibration, 12-digit accuracy vs reference values
- **Cubic spline** -- non-parametric on total variance, Thomas algorithm O(n), flat extrapolation
**Surface Construction**
- **SSVI** global parameterization (Gatheral-Jacquier 2014) with two-stage calibration
- **Piecewise** per-tenor surfaces with linear variance interpolation
- **Builder API** with SVI/SABR/spline model selection
- Ragged strike grids -- different strikes per tenor, no rectangular matrix assumption
**Arbitrage Detection**
- Butterfly arbitrage via analytical g-function (SVI) and numerical density scan (SABR)
- Calendar spread arbitrage via cross-tenor variance monotonicity
- Analytical calendar arbitrage for SSVI surfaces
- Combined `SurfaceDiagnostics` report
**Implied Volatility**
- Black (lognormal) implied vol via Jackel rational approximation (3 ULP accuracy)
- Black-Scholes pricing
**Design**
- No global state -- evaluation date is a parameter, not a singleton
- Immutable surfaces -- no observer pattern
- Thread-safe -- all types are `Send + Sync`
- Zero-alloc vol queries after construction
- Newtypes for type safety (`Vol`, `Variance`, `Strike`, `Tenor`)
- Serde serialization on all model structs and value types
## Installation
```toml
[dependencies]
volsurf = "0.2"
```
Optional features:
```toml
volsurf = { version = "0.2", features = ["logging"] }
```
| `logging` | `tracing` instrumentation in calibration and build paths |
| `parallel` | `rayon` support for parallel surface construction (v0.3) |
Requires Rust edition 2024 (rustc 1.85+).
## Quick Start
### Build a surface from market data
```rust
use volsurf::surface::{SurfaceBuilder, VolSurface};
let strikes = vec![80.0, 90.0, 95.0, 100.0, 105.0, 110.0, 120.0];
let vols = vec![0.28, 0.24, 0.22, 0.20, 0.22, 0.24, 0.28];
let surface = SurfaceBuilder::new()
.spot(100.0)
.rate(0.05)
.add_tenor(0.25, &strikes, &vols)
.add_tenor(1.00, &strikes, &vols)
.build()?;
// Query vol at any (expiry, strike) point
let vol = surface.black_vol(0.5, 100.0)?;
```
### Choose a smile model
```rust
use volsurf::surface::{SurfaceBuilder, SmileModel, VolSurface};
let surface = SurfaceBuilder::new()
.spot(100.0)
.rate(0.05)
.model(SmileModel::Sabr { beta: 0.5 })
.add_tenor(0.25, &strikes, &vols)
.add_tenor(1.00, &strikes, &vols)
.build()?;
```
Available models: `SmileModel::Svi` (default, 5+ strikes), `SmileModel::CubicSpline` (3+ strikes), `SmileModel::Sabr { beta }` (4+ strikes).
### SSVI global surface
```rust
use volsurf::surface::{SsviSurface, VolSurface};
let surface = SsviSurface::new(
-0.3, 0.5, 0.5, // rho, eta, gamma
vec![0.25, 0.5, 1.0], // tenors
vec![100.0, 100.0, 100.0], // forwards
vec![0.04, 0.08, 0.16], // thetas (ATM total variance)
)?;
let vol = surface.black_vol(0.5, 100.0)?;
let smile = surface.smile_at(0.5)?;
```
### Check for arbitrage
```rust
use volsurf::smile::{SviSmile, SmileSection};
let smile = SviSmile::new(100.0, 1.0, 0.04, 0.4, -0.4, 0.0, 0.2)?;
let report = smile.is_arbitrage_free()?;
assert!(report.is_free);
// Surface-level diagnostics (butterfly + calendar)
let diagnostics = surface.diagnostics()?;
if !diagnostics.is_free {
for cal in &diagnostics.calendar_violations {
println!("Calendar violation at K={}", cal.strike);
}
}
```
### Extract implied vol from option prices
```rust
use volsurf::implied::BlackImpliedVol;
use volsurf::OptionType;
let vol = BlackImpliedVol::compute(10.45, 100.0, 100.0, 1.0, OptionType::Call)?;
```
## Architecture
Five-layer pipeline following the natural domain flow:
```
Option Prices -> Implied Vol -> Smile -> Surface -> Local Vol
(Layer 1) (Layer 2) (Layer 3) (Layer 5)
Arbitrage Detection
(Layer 4)
```
```
volsurf
├── conventions StickyKind, log_moneyness, forward_price
├── error VolSurfError, Result<T>
├── implied
│ ├── black BlackImpliedVol, black_price
│ ├── normal NormalImpliedVol (v0.3)
│ └── displaced DisplacedImpliedVol (v0.3)
├── smile
│ ├── svi SviSmile (Gatheral 2006)
│ ├── sabr SabrSmile (Hagan 2002)
│ ├── spline SplineSmile (cubic on variance)
│ └── arbitrage ArbitrageReport, ButterflyViolation
├── surface
│ ├── ssvi SsviSurface (Gatheral-Jacquier 2014)
│ ├── essvi EssviSurface (v0.3)
│ ├── piecewise PiecewiseSurface (per-tenor interpolation)
│ ├── builder SurfaceBuilder, SmileModel
│ └── arbitrage SurfaceDiagnostics, CalendarViolation
├── local_vol LocalVol trait, DupireLocalVol (v0.3)
└── types Strike, Tenor, Vol, Variance, OptionType
```
## Benchmarks
Measured with Criterion.rs on Apple Silicon. All performance targets exceeded.
### Vol Queries (single point evaluation)
| SVI vol | 4.7 ns |
| Spline vol | 4.6 ns |
| SSVI slice vol | 11 ns |
| SABR vol | 17 ns |
| Piecewise surface vol | 18 ns |
| SSVI surface vol | 20 ns |
### Calibration
| SABR calibration | 74 us |
| SVI calibration | 107 us |
| SSVI calibration | 266 us |
### Surface Construction
| SABR surface (5 tenors) | 381 us |
| SVI surface (5 tenors) | 553 us |
| SVI surface (20 tenors) | 2.6 ms |
**Targets**: vol query < 100 ns, SABR calibration < 1 ms, 20-tenor surface < 10 ms.
## Roadmap
| v0.1 | First Light | SVI smile, cubic spline, ragged grid surface, builder API |
| **v0.2** | **Market Ready** | **SABR, SSVI, calendar arbitrage, surface diagnostics** |
| v0.3 | Production Grade | eSSVI, Dupire local vol, parallel construction |
| v1.0 | Stable | API stability, PyO3 bindings, WASM target |
## References
- Gatheral, J. *The Volatility Surface: A Practitioner's Guide* (2006)
- Gatheral, J. & Jacquier, A. "Arbitrage-free SVI Volatility Surfaces" (2014)
- Hagan, P. et al. "Managing Smile Risk", *Wilmott* (2002)
- Jackel, P. "Let's Be Rational" (2013)
- Zeliade Systems, "Quasi-Explicit Calibration of Gatheral's SVI Model" (2009)
- Breeden, D.T. & Litzenberger, R.H. "Prices of State-Contingent Claims Implicit in Option Prices" (1978)
## License
Licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for details.