A high-performance, explainable volatility surface modeling library written in C++20,
with an interactive React/Vite dashboard for real-time calibration visualization.
Inspired by gnsqd/surface (Rust) — reimplemented from scratch in modern C++.
- Overview
- Pipeline Architecture
- Features
- Project Structure
- Getting Started
- Usage
- Interactive Dashboard
- Mathematical Background
- Optimization Engine
- Arbitrage Diagnostics
- Roadmap
- References
- License
Surfotility is a modular, production-grade volatility surface calibration engine that takes raw option chain data and produces arbitrage-free implied volatility surfaces using the Stochastic Volatility Inspired (SVI) parameterization.
The engine features a two-stage global+local hybrid optimizer (CMA-ES → L-BFGS-B), Durrleman-condition arbitrage verification, full analytical Black-Scholes Greeks, and a diagnostic explainability layer — all exposed through both a C++ CLI and a React web dashboard.
Option Chain (CSV/JSON)
↓
Implied Volatility (Newton-Raphson BS Inversion)
↓
Clean / Filter Data (Strike bounds, Vega weighting)
↓
SVI Calibration (per-expiry, CMA-ES → L-BFGS-B)
↓
Arbitrage Checks (Variance, Butterfly, Calendar)
↓
Surface Construction (Multi-slice interpolation)
↓
Greeks (Δ, Γ, V, Θ, ρ, Vanna, Volga)
↓
Explainability Report (Markdown + JSON)
↓
React Dashboard (Real-time visualization)
| Feature | Description |
|---|---|
| SVI Parameterization | Raw SVI model: w(k) = a + b(ρ(k−m) + √((k−m)² + σ²)) with 5 free parameters |
| Two-Stage Optimizer | CMA-ES global search (population-based) → Projected L-BFGS-B local refinement with Armijo line search |
| Optimization Presets | Minimal, Fast, Production, Research — tuneable iterations, population size, tolerances |
| Black-Scholes Pricer | Analytical European option pricing with put-call parity verification |
| Full Greeks Suite | Delta, Gamma, Vega, Theta, Rho, Vanna, Volga — all closed-form |
| IV Solver | Newton-Raphson implied volatility inversion from market prices |
| Arbitrage Detection | Variance positivity, Durrleman butterfly density g(k) ≥ 0, calendar spread dw/dT ≥ 0 |
| Multi-Expiry Surface | Per-expiry SVI calibration with linear interpolation across the time dimension |
| 3D Surface Grid | Dense mesh generation for rendering: (strike × expiry) → implied vol |
| Explainability Engine | Physical interpretation of each SVI parameter + quantitative diagnostics (RMSE, MAE, R²) |
| JSON Export | Structured output for web dashboard consumption |
| CSV Loader | Parse option chain data from CSV files |
| Feature | Description |
|---|---|
| Smile Chart | 2D volatility smile: market IV scatter vs. calibrated SVI curve |
| Arbitrage Density | Durrleman risk-neutral density g(k) with arbitrage pass/fail indicator |
| Parameter Sandbox | Interactive sliders for all 5 SVI parameters with real-time re-rendering |
| Preset Switching | SPX Index and BTC Crypto presets with realistic market data |
| Client-Side Calibration | Grid-search SVI calibration running entirely in the browser |
Surfotility/
├── CMakeLists.txt # Build configuration (C++20, -O3)
├── README.md
│
├── include/surface/ # Public header API
│ ├── surface.hpp # Aggregate include header
│ ├── types.hpp # Core types: SVIParams, MarketDataRow, OptionGreeks, etc.
│ ├── black_scholes.hpp # BS pricing, Greeks, IV solver
│ ├── svi_model.hpp # SVI formula, derivatives, RND, arbitrage validation
│ ├── optimizer.hpp # CMA-ES, L-BFGS-B, hybrid optimizer
│ ├── calibration.hpp # Single-expiry SVI calibration engine
│ ├── calibration_multi.hpp # Multi-expiry per-slice calibration
│ ├── volatility_surface.hpp # 3D surface construction & interpolation
│ ├── explainability.hpp # Diagnostic reports & parameter explanations
│ └── option_chain.hpp # CSV option chain loader
│
├── src/ # Implementation files
│ ├── main.cpp # CLI entry point — full pipeline demo
│ ├── black_scholes.cpp # BS pricing implementation
│ ├── svi_model.cpp # SVI math: w(k), w'(k), w''(k), g(k)
│ ├── optimizer.cpp # CMA-ES + L-BFGS-B optimizer (268 lines)
│ ├── calibration.cpp # Weighted least-squares SVI fitting
│ ├── calibration_multi.cpp # Per-expiry calibration loop
│ ├── volatility_surface.cpp # Surface interpolation & calendar arb checks
│ ├── explainability.cpp # Markdown & JSON report generation
│ ├── option_chain.cpp # CSV parser
│ └── export_multi_json.cpp # Multi-expiry JSON exporter
│
├── tests/
│ └── test_surface.cpp # Unit tests: BS parity, IV recovery, SVI calibration
│
└── web/ # React/Vite interactive dashboard
├── package.json
├── vite.config.js
├── tailwind.config.js
├── index.html
└── src/
├── components/
│ ├── Header.jsx # Dashboard header with preset switcher
│ ├── SmileChart.jsx # 2D volatility smile chart (Chart.js)
│ ├── ArbitrageDensityChart.jsx# Durrleman RND density chart
│ └── ParameterSandbox.jsx # Interactive SVI parameter sliders
└── utils/
├── svi_engine.js # Browser-side SVI math (mirrors C++ core)
└── sample_data.js # SPX & BTC preset market data
| Tool | Version | Purpose |
|---|---|---|
| C++ Compiler | C++20 (GCC 11+, Clang 14+, MSVC 19.30+) | Core engine |
| CMake | ≥ 3.20 | Build system |
| Node.js | ≥ 18 | React dashboard |
| npm | ≥ 9 | Package management |
# Clone the repository
git clone https://github.com/your-username/Surfotility.git
cd Surfotility
# Build with CMake
mkdir -p build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)
# Run the CLI
./surface_clicd build
./surface_testsExpected output:
=========================================================
🧪 Surface-Lib C++ Test Suite
=========================================================
[RUNNING TEST] Black-Scholes Put-Call Parity...
[PASSED] Put-Call Parity holds
[RUNNING TEST] Implied Volatility Recovery...
[PASSED] Implied Volatility recovered: 0.2 vs target 0.2
[RUNNING TEST] SVI Formula & Risk-Neutral Density...
[PASSED] SVI params valid, RND density g(0)=0.847 > 0
[RUNNING TEST] SVI Calibration on Synthetic Smile...
[PASSED] Calibration Converged with RMSE: 0.000124
✅ ALL UNIT TESTS PASSED SUCCESSFULLY!
cd web
npm install
npm run devOpen http://localhost:5173 in your browser.
#include "surface/surface.hpp"
using namespace surface;
int main() {
// 1. Prepare market data
std::vector<MarketDataRow> data = {
{"put", 90.0, 100.0, 0.25, 0.228, 0.92, 0},
{"call", 100.0, 100.0, 0.25, 0.195, 1.15, 0},
{"call", 110.0, 100.0, 0.25, 0.176, 0.62, 0},
};
// 2. Calibrate SVI (one slice)
auto [rmse, params, bounds] = calibrate_svi(
data,
default_configs::fast() // or production(), research()
);
// 3. Price with calibrated model
FixedParameters env{0.02, 0.00};
auto results = price_with_svi(params, data, env);
// 4. Check arbitrage
auto diag = SVIModel::validate_arbitrage(params);
// diag.is_butterfly_arbitrage_free == true ✅
// 5. Build multi-expiry surface
VolatilitySurface surf;
surf.add_slice(0.25, params);
double iv = surf.get_implied_volatility(105.0, 0.30, 100.0);
return 0;
}The CSV loader expects a header row followed by data rows:
option_type,strike,underlying,years_to_exp,market_iv,vega,expiration
put,90.0,100.0,0.25,0.228,0.92,1640995200
call,100.0,100.0,0.25,0.195,1.15,1640995200
call,110.0,100.0,0.25,0.176,0.62,1640995200Open-source data: You can use SPX option chain data from CBOE DataShop (free samples) or Kaggle Options Datasets — reformat to the CSV schema above.
| Preset | Iterations | Population | Objective Tol | Use Case |
|---|---|---|---|---|
Minimal |
100 | 20 | 1e-4 | Quick prototyping |
Fast |
300 | 30 | 1e-6 | Interactive / real-time |
Production |
600 | 50 | 1e-7 | Trading systems |
Research |
1500 | 100 | 1e-9 | Academic / publication |
The React dashboard provides real-time visualization of the calibrated volatility surface:
| Panel | Description |
|---|---|
| Header | Preset selector (SPX / BTC), calibration trigger button |
| Smile Chart | Market IV points (scatter) overlaid with smooth SVI curve w(k) |
| Arbitrage Density | Durrleman RND density g(k) — green if arbitrage-free, red if violated |
| Parameter Sandbox | Drag sliders for a, b, ρ, m, σ and watch the smile update live |
The dashboard runs a browser-side SVI engine (svi_engine.js) that mirrors the C++ mathematical core, enabling instant parameter exploration without recompilation.
The raw SVI parameterization defines total implied variance as a function of log-moneyness k = log(K/F):
| Parameter | Symbol | Range | Interpretation |
|---|---|---|---|
| Base variance | a |
a ≥ 0 |
Vertical shift — overall IV level |
| Slope | b |
b ≥ 0 |
Wing steepness — tail volatility |
| Skew | ρ |
−1 < ρ < 1 |
Asymmetry — equity put skew when ρ < 0 |
| Shift | m |
ℝ | Horizontal displacement of the smile vertex |
| Curvature | σ |
σ > 0 |
Vertex smoothness — small σ = sharp V, large σ = smooth U |
The Durrleman condition ensures absence of butterfly arbitrage:
If g(k) < 0 at any strike, the surface admits static butterfly arbitrage.
For a surface to be free of calendar arbitrage, total variance must be non-decreasing in time:
- Population-based global optimizer over the 5D SVI parameter space
- Diagonal covariance approximation for stability and speed
- Configurable population size, step-size adaptation, and convergence tolerance
- Bounded search with projection into feasible parameter region
- Local refinement seeded from the CMA-ES solution
- Central-difference numerical gradients
- Armijo backtracking line search with projected bounds
- Typically converges in 20–50 iterations for well-conditioned problems
CMA-ES (global exploration) → L-BFGS-B (local polish) → Best of both
The hybrid approach avoids local minima while achieving high numerical precision.
The engine performs three levels of arbitrage validation:
| Check | Condition | Method |
|---|---|---|
| Variance Positivity | w(k) > 0 ∀ k |
Grid scan over [-2, 2] with 200 points |
| Butterfly Arbitrage | g(k) ≥ 0 ∀ k |
Durrleman density formula, 200-point grid |
| Calendar Arbitrage | dw/dT ≥ 0 ∀ k, T |
Pairwise comparison of adjacent expiry slices |
All diagnostics are reported in the ArbitrageDiagnostics struct and rendered in both the CLI markdown report and the React dashboard.
- SVI raw parameterization & calibration
- CMA-ES + L-BFGS-B hybrid optimizer
- Black-Scholes analytical Greeks (7 Greeks)
- Multi-expiry surface construction
- Durrleman butterfly & calendar arbitrage checks
- Explainability engine (Markdown + JSON reports)
- React dashboard with parameter sandbox
- Per-expiry SVI calibration
- SABR model calibration & comparison
- Local volatility (Dupire) extraction
- Delta hedging simulation
- Monte Carlo hedging P&L attribution
- Real market data ingestion (CBOE, Deribit API)
- Raw vs SVI vs SABR vs Local Vol comparison charts
-
Gatheral, J. (2004). A parsimonious arbitrage-free implied volatility parameterization with application to the valuation of volatility derivatives. Presentation at Global Derivatives & Risk Management, Madrid.
-
Gatheral, J. & Jacquier, A. (2014). Arbitrage-free SVI volatility surfaces. Quantitative Finance, 14(1), 59-71.
-
Durrleman, V. (2003). From implied to spot volatilities. PhD thesis, Princeton University.
-
Hansen, N. & Ostermeier, A. (2001). Completely derandomized self-adaptation in evolution strategies. Evolutionary Computation, 9(2), 159-195.
-
gnsqd/surface — Original Rust implementation: github.com/gnsqd/surface
This project is licensed under the MIT License. See LICENSE for details.
Built with ❤️ for quantitative finance research