Master's Thesis Project — МФТИ ФПМИ, Кафедра БИТ, 2026 Нейронные сети в ценообразовании производных финансовых инструментов
An end-to-end GPU-accelerated system for real-time calibration of the Rough Heston stochastic volatility model (El Euch, Gatheral & Rosenbaum 2019). The core idea: replace an expensive Fourier-COS pricer (seconds per surface) with a FiLM-conditioned Fourier Neural Operator (FNO) surrogate that prices a full 8×11 implied-volatility surface in under 1 ms — enabling Gauss-Newton calibration at interactive speed.
The project covers the full quant stack: mathematical foundations → GPU pricing → neural surrogate → real-time calibration → REST API → live market data integration.
| Experiment | Result |
|---|---|
| FNO v2 surrogate accuracy | R² = 0.9991, MAE = 0.058% (5.8 bp) |
| FNO v3 (learnable H ∈ [0.04, 0.15]) | R² = 0.9981, MAE = 0.264% |
| Inference speed | ~4 ms (batch 1024) vs 5.6 s direct COS — 1400× speedup |
| Newton calibration — SPX synthetic (NB01) | 8.9 bps RMSE, converged in 12 iters |
| Batch calibration — 5 dates (NB06) | 12.8 bps median RMSE, 5/5 converged, H=0.108 |
| Joint SPX + VIX calibration (NB07) | SPX 198.9 bps, VIX error 0.362, converged |
| BTC live Deribit calibration (NB05) | 1547 bps RMSE, v2 model, 548 contracts |
| Streaming p95 latency (20 ticks) | 668 ms < 1000 ms real-time threshold |
| FIM reparameterization | Condition number 1301× lower (κ ≈ 770) |
| Delta hedging variance reduction | +5.1% vs flat Black-Scholes Δ |
| NaN rate (exponential midpoint integrator) | 2.76% (was 70.4% with Euler) |
| Neural SDE Adjoint Calibration (NB12) | 8.1 bps final option price RMSE |
| Signature Vol martingale error (NB13) | 0.11 bps (well within 10 bps limit) |
| Recurrent Deep Hedging (NB14-15) | 0.4388 European, 0.4349 Barrier P&L std |
| Minimax GAN market generation (NB16) | 0.0003 final tracking error |
| FastAPI Deep Hedging throughput | 132.91 RPS (p50 = 6.57 ms) on GPU |
| FastAPI FNO Calibration throughput | 353.42 RPS (p50 = 80.01 ms) |
| PI-M-FNO online crisis adaptation speed | ~3.5 ms (2 inner-gradient steps, PDE loss < 10⁻⁴) |
| D-XVA gradient flow differentiability |
Non-zero, non-NaN ( |
| Grey Rough Bergomi MC path simulation | < 15 ms on GPU (4096 paths, 100 steps) |
| Sobolev FNO gRB Validation accuracy | MAE = 0.76 bp, MSE = 7.69e-5 (Active Learning) |
- Mathematical Background
- DeepVol Model Zoo
- Monte Carlo Risk Engine (VaR/ES)
- Architecture
- Installation
- Quick Start
- Notebooks
- REST API
- Benchmarks
- Test Suite
- Models & Weights
- Project Structure
- Thesis & Publications
- License
The Rough Heston model (El Euch & Rosenbaum 2019) is a stochastic volatility
model where the variance process
The spot price follows:
where
Parameters (6 total):
| Symbol | Name | Range | Role |
|---|---|---|---|
| Mean reversion speed | How fast variance reverts to |
||
| Long-run variance | Equilibrium variance level | ||
| Vol-of-vol | Volatility of the variance process | ||
| Correlation | Spot-vol correlation (leverage effect) | ||
| Initial variance | Variance at |
||
| Hurst exponent | Roughness (empirically |
The fractional kernel makes exact simulation expensive. The Lifted Heston model
(Abi Jaber 2019) approximates the fractional integral with
With
The Rough Heston model has a semi-analytical characteristic function:
where
with
The 5-parameter Heston system is poorly identified — the FIM condition number exceeds
The DeepVol framework contains a diverse "Zoo" of 13 volatility and derivatives models, implemented with high-performance CPU/GPU solvers and integrated with real-time calibration:
- Classic Heston Model: Traditional stochastic volatility model where variance follows a Cox-Ingersoll-Ross (CIR) process. Option pricing is performed using the exact Fourier-COS series expansion method.
- SABR Model (Hagan/Displaced): Industry-standard smile model for FX and interest rates. Supports normal (Bachelier) and lognormal (Black) implied volatility via Hagan (2002) asymptotic expansions with displacement shifts.
- SSVI (Surface SVI) Model: Parameterizes the entire volatility surface using Gatheral's SVI slices under strict calendar and butterfly no-arbitrage guarantees.
-
Local Volatility (Dupire SVI) Model: Extract state-dependent local volatility
$\sigma_{\text{loc}}(T, K)$ by applying Dupire's formula via finite differences to a calibrated SVI surface. -
Rough Bergomi (rBergomi) Model: SOTA rough volatility model where variance is driven by a fractional Brownian motion (
$H < 0.5$ ). Simulated on GPU using the Bennedsen-Lunde-Pakkanen (2017) hybrid convolution scheme. - Neural SDE: Data-driven generative pricing model where drift and diffusion coefficients of the SDE are parameterized by neural networks and calibrated via adjoint sensitivity.
- Signature Volatility: Model path-dependency using rough path theory, where the asset volatility is represented as a linear function of the signature of historical prices.
- McKean-Vlasov SDE (MLSV) Model: Local stochastic volatility model where the volatility coefficient depends on the probability distribution (marginal laws) of the spot process.
- Schwartz-Smith (2-Factor Commodity) Model: Captures short-term mean-reverting deviations and long-term equilibrium price factors to model commodity futures curves and options.
- LMM-SABR Model: Combines the Libor Market Model (LMM) with SABR stochastic volatility to model the evolution of interest rate forward curves and swaption cubes.
- Physics-Informed Meta-Learning FNO (PI-M-FNO): Physics-informed neural operator designed to price options under extreme, out-of-distribution market conditions with fast online GPU adaptation (< 10 ms).
- End-to-End Differentiable Calibration & Hedging (D-XVA): Unifies option pricing, implied volatility inversion (PIVOT), and recurrent deep hedging into a single computational graph trained directly on hedging variance.
- Grey Rough Bergomi (gRB) Model: Generalizes rough Bergomi by replacing fractional Brownian motion with generalized grey Brownian motion, implemented via custom double-precision Mittag-Leffler and Wood-Chan circulant embedding CUDA kernels.
DeepVol includes a high-performance GPU-accelerated Monte Carlo Risk Engine to compute portfolio-level risk metrics:
-
Value-at-Risk (VaR): The maximum expected loss at a given confidence level
$\alpha$ (e.g.,$95%$ or$99%$ ) over a time horizon$\Delta t$ . -
Expected Shortfall (ES): Also known as Conditional VaR (CVaR), measuring the average loss in the worst
$(1-\alpha)%$ tail scenarios.
-
Scenario Generation: Jointly simulate spot and variance paths under the Heston model using a stable full-truncation Euler-Maruyama scheme (Lord, Koekkoek & van Dijk 2010) on GPU to ensure non-negative variance:
$$dX_t = (r - \tfrac{1}{2} V^+_t) dt + \sqrt{V^+_t} dW_1, \qquad dV_t = \kappa(\theta - V^+_t) dt + \sigma \sqrt{V^+_t} dW_2$$ -
Accelerated Revaluation: For each simulated path, the entire option portfolio is revalued using the fast FiLM-FNO pricing surrogate and 2D bilinear interpolation, enabling
$10^7$ portfolio valuations per second. - Loss Aggregation: Compute the portfolio loss distribution, sorting to extract the VaR and Expected Shortfall at the targeted quantiles.
θ = (κ, θ, σ, ρ, V₀, H)
│
▼
ParameterNormalizer (z-score to unit hypercube)
│
▼
FiLM MLP: θ → (γ₁,β₁, γ₂,β₂, γ₃,β₃, γ₄,β₄) [scale+shift per layer]
│
▼
(T, K) grid (8×11) ──→ Mirror-pad (16×22) ──→ Lifting Conv (1→40 channels)
│
┌─────── 4 × FourierLayer ────────┤
│ Spectral truncation (modes=8,11)│
│ FiLM(γ_i, β_i) modulation │
└───────────────────────────────────┘
│
Projection (40→1)
│
IV surface (8×11)
│
IVSurfaceNormalizer⁻¹
│
σ_IV(T, K) in vol units
Key design decisions:
- Mirror padding on the T-axis: enforces put-call parity / calendar spread symmetry. Surface is padded from (8×11) to (16×22) before spectral convolution.
- FiLM conditioning (Perez et al. 2018): parameters θ control scale/shift of every Fourier layer, giving better generalization than concatenation.
-
Channels-last format: grid is
(B, T, K, C)— all modules expect this. -
Martingale prior: training loss penalizes surfaces that violate
$E[e^{-rT}S_T] = S_0$ , keeping the network in the no-arbitrage subspace. - ATM-weighted Huber loss: down-weights OTM/deep ITM strikes where IV data is sparse and noisy.
Market IV surface (8×11)
│
▼
IVSurfaceNormalizer.normalize()
│
┌─────▼──────────────────────────────────┐
│ Gauss-Newton loop (max 20 iters) │
│ θ_new = θ - (JᵀJ + λI)⁻¹ Jᵀ r │
│ J = jacfwd(FNO, θ) [exact, GPU] │
│ r = FNO(θ) - σ_market │
└─────┬──────────────────────────────────┘
│ converged when RMSE < 50 bps
▼
ParameterNormalizer.denormalize()
│
▼
θ* = (κ*, θ*, σ*, ρ*, V₀*, H*)
- Python 3.9+
- CUDA 12.8+ and a compatible GPU (tested: RTX 3060/3080/4090, A100)
- PyTorch 2.8+ with CUDA support
uvPython package manager (highly recommended)- ~4 GB disk space (model weights + datasets)
Using uv (fastest & recommended):
# 1. Clone the repository
git clone <repo-url>
cd derivatives
# 2. Sync dependencies and build virtual environment automatically
uv sync
# 3. (Optional) Build the CUDA extension for direct kernel access
uv run python setup.py build_ext --inplace
# 4. Verify installation
uv run python -c "import torch; print('CUDA:', torch.cuda.is_available())"
uv run pytest tests/test_pricing_engine.py -qchmod +x setup_and_run.sh
./setup_and_run.sh
# Creates .venv, installs deps, launches Streamlit on port 8501-
Main Calibration Dashboard:
source .venv/bin/activate streamlit run src/deepvol/app/app_v2.py # Opens http://localhost:8501
The calibration dashboard has three tabs:
- IV Surface: Adjust sliders for all 6 parameters, see the real-time FNO-predicted implied-volatility surface update in < 1 ms.
- Newton Calibration: Upload or paste a market IV surface, run Gauss-Newton calibration, watch the parameter trajectory converge.
- Greeks: Compute portfolio delta/gamma/vega for a set of positions.
-
Risk Management Dashboard:
source .venv/bin/activate streamlit run src/deepvol/app/app_v3_risk.py # Opens http://localhost:8501
The risk dashboard provides:
- Live Risk Telemetry: Streaming Greeks, latency timelines, and spot updates.
- Scenario Stress Testing: Stress testing spot/vol shocks on 3D Greeks grids.
- Audit Logs: Scrolling historical telemetry reports and CSV downloads.
import sys; sys.path.insert(0, 'src')
import torch
import numpy as np
from deepvol.surrogates.fno_model import MirrorPaddedFNO2d
from deepvol.calibration.calibrate_bfgs import _load_normalizers, _fno_predict_real_iv, _make_spatial_input
from deepvol.market.spx_data import T_GRID, K_GRID
# Load model and normalizers
device = "cuda" if torch.cuda.is_available() else "cpu"
model = MirrorPaddedFNO2d(param_dim=6).to(device)
model.load_state_dict(torch.load("artifacts/weights/fno_v3_final_prod.pth", map_location=device, weights_only=True))
model.eval()
_load_normalizers("v3") # must be called before any forward pass
# Parameters: κ=2.0, θ=0.04, σ=0.5, ρ=-0.7, V₀=0.04, H=0.1
theta = torch.tensor([[2.0, 0.04, 0.5, -0.7, 0.04, 0.1]], dtype=torch.float32, device=device)
spatial = _make_spatial_input(T_GRID, K_GRID, device)
with torch.no_grad():
iv_surface = _fno_predict_real_iv(model, theta, spatial).squeeze().cpu().numpy()
print(iv_surface.shape) # (8, 11) — implied vol in decimal (0.20 = 20%)
print(f"ATM 6M: {iv_surface[2, 5]*100:.1f}%") # roughly 20-25% for typical paramsimport sys; sys.path.insert(0, 'src')
import torch
from deepvol.surrogates.fno_model import MirrorPaddedFNO2d
from deepvol.calibration.calibrate_newton import calibrate_newton_h
from deepvol.market.spx_data import T_GRID, K_GRID
device = "cuda" if torch.cuda.is_available() else "cpu"
model = MirrorPaddedFNO2d(param_dim=6).to(device)
model.load_state_dict(torch.load("artifacts/weights/fno_v3_final_prod.pth", map_location=device, weights_only=True))
model.eval()
# Market IV surface: 8 maturities × 11 strikes (in decimal vol, e.g. 0.20 = 20%)
from deepvol.market.spx_data import download_spx_chain, clean_chain, to_iv_surface
from datetime import date
# Fetch or load market IV surface
df = download_spx_chain(date(2024, 1, 2))
cleaned = clean_chain(df)
S0 = 4700.0
r = 0.05
q = 0.015
market_iv = to_iv_surface(cleaned, S0, r, q) # (8, 11) array
# Gauss-Newton calibration in (v₀, ζ=σρ, λ=σ√(1-ρ²), H) space
result = calibrate_newton_h(model, market_iv, T_GRID, K_GRID, max_iter=20, verbose=True)
print(f"RMSE: {result['rmse'] * 1e4:.1f} bps")
print(f"v0={result['v0']:.4f} σ={result['sigma']:.3f} ρ={result['rho']:.3f} H={result['H']:.3f}")
print(f"converged: {result['converged']}")Forty-four self-contained Jupyter notebooks demonstrate the full pipeline end-to-end. They are located in the notebooks/ directory.
Run them in order:
source .venv/bin/activate
cd notebooks
jupyter lab # or: jupyter nbconvert --to notebook --execute --inplace *.ipynb| Notebook | Purpose | Key Output |
|---|---|---|
01_spx_calibration.ipynb |
Full SPX calibration pipeline | RMSE=8.9 bps, H=0.113 |
02_surface_completion.ipynb |
SVI fit + arbitrage enforcement | Clean IV surface |
03_vix_analysis.ipynb |
VIX term structure from Rough Heston | Model vs market curve |
04_greeks_portfolio.ipynb |
Delta/gamma/vega/vanna/volga | Hedge portfolio |
05_crypto_calibration.ipynb |
Live BTC/ETH from Deribit | RMSE=1547 bps (v2) |
06_batch_calibration.ipynb |
Multi-date SPX batch + H dynamics | 12.8 bps median |
07_joint_calibration.ipynb |
Joint SPX+VIX calibration | converged=True |
08_heston_vs_rheston.ipynb |
Classic Heston vs Rough Heston pricing | Hurst parameter influence |
09_sabr_ssvi_calibration.ipynb |
SABR & SSVI calibration | Synthetic smiles |
10_local_vol_dupire.ipynb |
SVI-to-Dupire Local Volatility mapping | Clean LV surface |
11_rbergomi_calibration.ipynb |
Rough Bergomi HMC calibration | Model vs COS comparison |
12_neural_sde_calibration.ipynb |
SDE Adjoint calibration | SDE drift/diffusion prior |
13_signature_forecasting.ipynb |
Signature Volatility Forecasting | Out-of-sample smile forecast |
14_deep_hedging_european.ipynb |
Recurrent European Deep Hedging | Delta hedging variance reduction |
15_barrier_hedging_costs.ipynb |
Recurrent Barrier Deep Hedging | Optimal rebalancing corridors |
16_adversarial_market_gen.ipynb |
WGAN-GP and stylized facts alignment | Minimax robust generation |
Calibrate Rough Heston to multiple historical dates in parallel. Results are saved incrementally and the run is resume-capable.
import sys; sys.path.insert(0, 'src')
from deepvol.calibration.batch_calibration import calibrate_batch, results_to_dataframe
# Calibrate SPX on 3 dates (fetches from yfinance, falls back to cached parquet)
results = calibrate_batch(
dates=["2024-01-02", "2024-01-03", "2024-01-04"],
currency="SPX", # or "BTC", "ETH" (via Deribit)
device="auto", # "cuda" if available, else "cpu"
max_workers=4, # parallel data-fetch threads
verbose=True,
)
# Output: [1/3] 2024-01-02 — RMSE=18.3 bps (541 ms)
df = results_to_dataframe(results)
print(df[["date", "kappa", "theta", "H", "rmse_bps", "converged"]])Fit Rough Heston parameters to match both the SPX IV surface and the VIX futures term structure simultaneously:
import sys; sys.path.insert(0, 'src')
from deepvol.calibration.joint_calibration import calibrate_joint
from datetime import date
result = calibrate_joint(
val_date=date(2024, 1, 2),
w_spx=0.7, # weight on SPX RMSE
w_vix=0.3, # weight on VIX curve MSE
)
print(f"SPX RMSE: {result['spx_rmse_bps']:.1f} bps")
print(f"VIX RMSE: {result['vix_rmse']:.4f}")
print(f"θ* = {result['params']}")Model the VIX futures curve from Rough Heston parameters:
import sys; sys.path.insert(0, 'src')
from deepvol.market.vix_futures import fetch_vix_futures
from deepvol.market.vix_pricing import compute_vix_term_structure
from datetime import date
import numpy as np
# Fetch the VIX futures curve for a date (8 contracts)
df = fetch_vix_futures(date(2024, 1, 2))
print(df)
# expiry tenor_months settle_vix
# 0 2024-01-17 1 13.2
# 1 2024-02-14 2 14.1
# ...
# Or compute model VIX from calibrated parameters
theta = np.array([2.0, 0.04, 0.5, -0.7, 0.04, 0.1]) # (κ,θ,σ,ρ,V₀,H)
vix_curve = compute_vix_term_structure(theta)Fill gaps in a sparse IV surface and enforce no-arbitrage constraints:
import sys; sys.path.insert(0, 'src')
import numpy as np
from deepvol.arbitrage.surface_completion import (
complete_sparse_surface,
make_arbitrage_free,
fit_svi_slice,
)
# Sparse surface: (T, K) grid with NaN where data is missing
sparse_iv = np.full((8, 11), np.nan)
sparse_iv[2, 4:8] = [0.18, 0.17, 0.19, 0.20] # some observed strikes at T=0.6
# Complete the surface and enforce butterfly + calendar spread constraints
dense_iv = complete_sparse_surface(sparse_iv)
af_iv = make_arbitrage_free(dense_iv)
print("Max butterfly violation after:", np.max(np.diff(np.diff(af_iv, axis=1), axis=1)))Compute delta, gamma, vega, vanna, volga for a portfolio of options and the delta-hedging contracts needed:
import sys; sys.path.insert(0, 'src')
import numpy as np
import torch
from deepvol.surrogates.fno_model import MirrorPaddedFNO2d
from deepvol.surrogates.normalizers import ParameterNormalizer, IVSurfaceNormalizer
from deepvol.greeks.portfolio_greeks import portfolio_greeks
# Load model (same as pricing above)
device = "cuda" if torch.cuda.is_available() else "cpu"
model = MirrorPaddedFNO2d(param_dim=6).to(device)
model.load_state_dict(torch.load("artifacts/weights/fno_v3_final_prod.pth", map_location=device))
model.eval()
pn = ParameterNormalizer.load("artifacts/models/param_normalizer_v3.npz")
yn = IVSurfaceNormalizer.load("artifacts/models/iv_normalizer_v3.npz")
# Define a portfolio of options
positions = [
{"K": 100.0, "T": 0.5, "type": "call", "quantity": 10.0},
{"K": 95.0, "T": 0.5, "type": "put", "quantity": -20.0},
{"K": 105.0, "T": 1.0, "type": "call", "quantity": 5.0},
]
# Calibrated parameters
theta = np.array([2.0, 0.04, 0.5, -0.7, 0.04, 0.1])
greeks = portfolio_greeks(positions, model, theta, pn, yn, S=100.0)
print(f"Portfolio Delta: {greeks['total_delta']:.4f}")
print(f"Portfolio Gamma: {greeks['total_gamma']:.6f}")
print(f"Hedge: sell {greeks['hedge_contracts']} ES futures")
print(f"Vega bucket (by maturity):\n{greeks['vega_bucket']}")Break down realized P&L into Greek components:
import sys; sys.path.insert(0, 'src')
from deepvol.greeks.pnl_attribution import pnl_attribution
# Greeks computed before the move
greeks_before = {
"total_delta": 0.45,
"total_gamma": 0.012,
"total_vanna": -0.003,
"total_volga": 0.008,
"vega_bucket": [0.5, 0.3, 0.2, 0.1, 0.0, 0.0, 0.0, 0.0],
}
# Market move: spot 100→102, vol 20%→21%
breakdown = pnl_attribution(
S_before=100.0, S_after=102.0,
sigma_before=0.20, sigma_after=0.21,
greeks=greeks_before,
)
print(f"Delta P&L: {breakdown['delta_pnl']:.4f}")
print(f"Gamma P&L: {breakdown['gamma_pnl']:.4f}")
print(f"Vega P&L: {breakdown['vega_pnl']:.4f}")
print(f"Unexplained:{breakdown['residual_pnl']:.4f}")Run a historical calibration study to track how H changes over time:
import sys; sys.path.insert(0, 'src')
from deepvol.analysis.hurst_dynamics import run_historical_study
# Resume-capable: already-calibrated dates are skipped
df = run_historical_study(
start="2024-01-01",
end="2024-03-31",
currency="SPX",
chunk_size=5, # save every 5 dates
device="auto",
)
# Results saved to results/hurst_dynamics/SPX_hurst_study.json
print(df[["date", "H", "kappa", "rmse_bps", "converged"]].head(10))
print(f"Mean H: {df['H'].mean():.4f}") # typically ~0.08-0.10 for SPXStream real-time BTC/ETH IV surfaces from Deribit via WebSocket:
import asyncio
import sys; sys.path.insert(0, 'src')
from deepvol.market.deribit_ws import DeribitWebSocket
async def main():
async with DeribitWebSocket(currency="BTC") as ws:
async for surface in ws.stream_iv_surface():
print(f"BTC ATM IV (1M): {surface['iv_1m']:.4f}")
# Calibrate here in real-time...
asyncio.run(main())Start the FastAPI server and use it to calibrate from any language:
source .venv/bin/activate
cd /path/to/derivatives
uvicorn deepvol.api.server:app --reload --port 8000 --app-dir src
# OpenAPI docs → http://localhost:8000/docs| Method | Endpoint | Description |
|---|---|---|
GET |
/health |
Server health, model version, device |
POST |
/iv_surface |
FNO inference: θ → IV surface |
POST |
/greeks |
Portfolio Greeks for a set of positions |
GET |
/vix |
VIX futures term structure for a date |
GET |
/deribit/snapshot |
Live BTC/ETH IV surface snapshot |
POST |
/calibrate |
Full calibration: market IV → θ* |
POST |
/calibrate_neural_sde |
Adjoint calibration of non-parametric Neural SDE prior |
POST |
/predict/signature_vol |
Signature Volatility weekly options smile forecasting |
POST |
/hedge/simulate |
Recurrent Deep Hedging delta-hedging simulation |
curl -X POST http://localhost:8000/iv_surface \
-H "Content-Type: application/json" \
-d '{
"kappa": 2.0, "theta": 0.04, "sigma": 0.5,
"rho": -0.7, "v0": 0.04, "H": 0.1
}'
# Response: {"iv_surface": [[0.195, 0.182, ...], ...], "shape": [8, 11]}curl -X POST http://localhost:8000/greeks \
-H "Content-Type: application/json" \
-d '{
"positions": [{"K": 100.0, "T": 0.5, "type": "call", "quantity": 10}],
"theta": [2.0, 0.04, 0.5, -0.7, 0.04, 0.1],
"S": 100.0
}'
# Response: {"total_delta": 5.42, "total_gamma": 0.12, "hedge_contracts": -5, ...}All benchmarks are in benchmarks/. Run them from the repo root:
source .venv/bin/activate
# FNO v2 accuracy validation (MAE, R², NaN rate)
python benchmarks/validate_fno_v2.py
# FNO vs CUDA Monte Carlo speed comparison
python benchmarks/vs_cuda_mc.py
# Newton vs L-BFGS noise robustness
python benchmarks/noise_robustness.py
# Delta hedging backtest
python benchmarks/greeks_hedge_backtest.py
# Streaming calibration throughput demo
python benchmarks/streaming_calibration_demo.py| Benchmark | Result | File |
|---|---|---|
| FNO v2 accuracy | R²=0.9991, MAE=5.8bp, NaN=0.04% | validate_fno_v2.py |
| Inference speed | 4ms/batch vs 5600ms COS | vs_cuda_mc.py |
| Newton convergence | 15 iters, 541ms, RMSE < 50bp | noise_robustness.py |
| Streaming p95 | 668ms for 20 ticks | streaming_calibration_demo.py |
| Delta hedge | +5.1% variance reduction vs B-S | greeks_hedge_backtest.py |
| H convergence | N=40 factors → < 1bp surface error | convergence_N_factors.py |
1008 tests passing, 0 failing, 2 skipped (integration only).
# Full suite (~8 min)
uv run pytest tests/ -q
# By module
pytest tests/test_pricing_engine.py -v # Fourier-COS pricer
pytest tests/test_normalizers.py -v # Normalizer roundtrips
pytest tests/test_calibrate_newton.py -v # Newton calibrator
pytest tests/test_calibrate_newton_h.py -v # Learnable-H calibrator
pytest tests/test_batch_calibration.py -v # Multi-date batch
pytest tests/test_joint_calibration.py -v # Joint SPX+VIX
pytest tests/test_surface_completion.py -v # SVI + arbitrage
pytest tests/test_spx_data.py -v # SPX market data
pytest tests/test_vix_pricing.py -v # VIX model
pytest tests/test_vix_term_structure.py -v # VIX futures curve
pytest tests/test_vix_pricing_stress.py -v # VIX adversarial
pytest tests/test_deribit_data.py -v # Deribit REST
pytest tests/test_deribit_ws.py -v # Deribit WebSocket
pytest tests/test_variance_swaps.py -v # Variance/vol swaps
pytest tests/test_portfolio_greeks.py -v # Greeks accuracy
pytest tests/test_portfolio_greeks_adversarial.py -v # Greeks robustness
pytest tests/test_portfolio_greeks_stress.py -v # Greeks large portfolios
pytest tests/test_pnl_attribution.py -v # P&L breakdown
pytest tests/test_greeks_benchmark.py -v # Greeks timing
pytest tests/test_api.py -v # FastAPI endpoints
pytest tests/test_hurst_dynamics.py -v # Hurst study (2 skipped)
# Integration tests (require live yfinance data)
INTEGRATION=1 pytest tests/test_hurst_dynamics.py -v -k "convergence"| Model | Weights | Params | R² | MAE | Notes |
|---|---|---|---|---|---|
| FNO v2 | artifacts/weights/fno_v2_final_prod.pth |
2.2M | 0.9991 | 0.058% | H fixed=0.08 |
| FNO v3 | artifacts/weights/fno_v3_final_prod.pth |
2.2M | 0.9981 | 0.264% | H learnable |
Normalizers:
artifacts/models/param_normalizer_v2.npz # 5-parameter (κ,θ,σ,ρ,V₀)
artifacts/models/param_normalizer_v3.npz # 6-parameter (adds H)
artifacts/models/iv_normalizer_v2.npz
artifacts/models/iv_normalizer_v3.npz
Legacy weights (v1, diff-FNO, LSTM) are in artifacts/legacy/ — not used in
production but kept for reproducibility.
derivatives/
├── src/ Core library
│ └── deepvol/ Main module package
│ ├── surrogates/ FiLM-FNO model, EGNO, Signature SDE, Greeks, etc.
│ ├── models/ Stochastic vol models (Classic Heston, SABR, SSVI, Dupire, rBergomi, MLSV, etc.)
│ ├── calibration/ Autograd Newton, Joint, RKHS MLSV calibrators
│ ├── market/ Data integration (spx_data.py, deribit_ws.py, etc.)
│ ├── arbitrage/ SVI & arbitrage completion (surface_completion.py)
│ ├── greeks/ Greeks & PnL attribution (portfolio_greeks.py, pnl_attribution.py)
│ ├── analysis/ Hurst dynamics & research (hurst_dynamics.py, cross_asset_roughness.py)
│ ├── api/ FastAPI REST server (server.py, websocket.py)
│ ├── app/ Streamlit dashboards (app_v2.py, app_v3_risk.py, etc.)
│ ├── mrm/ Model Risk Guardian and particle fallbacks
│ ├── deploy/ TensorRT compilation and K8s configuration
│ └── utils/ Common utilities (strikes.py, etc.)
│
├── notebooks/ Jupyter notebooks (end-to-end demos)
├── tests/ pytest suite (955+ passing)
├── benchmarks/ Performance and accuracy studies
├── scripts/ Utility scripts (batch VIX, plot generation)
├── data/ Training datasets and market cache (gitignored)
├── artifacts/
│ ├── weights/ Production model weights (.pth)
│ └── models/ Normalizer files (.npz)
├── tex/
│ ├── thesis/main.pdf 51-page LaTeX thesis
│ └── presentation/presentation.pdf Defence slides
├── results/ Saved calibration outputs (JSON)
├── research/ Research notes, PDFs, SOTA survey
└── articles/ Reference academic papers (PDF)
The full 51-page thesis is at tex/thesis/main.pdf.
Chapters:
- Introduction — rough volatility motivation, related work
- Mathematical foundations — fBm, Rough Heston, Riccati ODE, Lifted Heston
- GPU Fourier-COS pricing — Bernstein weights, exponential midpoint integrator
- FiLM-FNO architecture — operator learning, mirror padding, training
- Experiments — 7 sections: accuracy, speed, calibration, FIM, Newton, streaming, delta hedging
- Conclusion and future work
Build the thesis:
cd tex/thesis
pdflatex -interaction=nonstopmode main.tex
biber main
pdflatex -interaction=nonstopmode main.tex
pdflatex -interaction=nonstopmode main.tex
# PDF written to tex/thesis/main.pdfPresentation slides: tex/presentation/presentation.pdf
| Phase | Status | Key Results |
|---|---|---|
| P1: FNO Surrogate | Complete | FNO v1/v2/v3, FIM reparameterization, Newton calibrator, Streamlit |
| P2: Market Extensions | Complete | FastAPI, VIX futures, Deribit streaming, variance swaps, batch calibration |
| P3: GPU-Native | Complete | GPU Gauss-Newton, SVI arbitrage enforcement, portfolio Greeks, P&L attribution |
| P4: Model Zoo | Complete | Classic Heston, SABR & SSVI, Local Volatility, and Rough Bergomi on GPU |
| P5: Neural SDE & Signature | Complete | Lifted Heston factor study, Neural SDE prior + adjoint, and Signature smile forecasting |
| P6: Recurrent Deep Hedging | Complete | Recurrent Deep Hedging (European/DOBC Barrier LSTM) and Minimax GAN market generation |
| P7: Quant Hardening | Complete | Stability fixes, call-put parity checks, boundary constraints, Feller tests |
| P8: Production Orchestration | Complete | High-throughput FastAPI, multi-model dispatch layer, unified configuration |
| P9: Differentiable FNO | Complete | JVP pricing loss, calendar/butterfly hard-constrained projection layers |
| P10: Model Risk Governance | Complete | Greek Adjoints VRAM optimization, Model Risk Guardian particle fallbacks, PSI drift logs |
| P11: Backtesting & Costs | Complete | Frictional env trading cost loops, Whalley-Wilmott delta hedging corridor |
| P12: Production Deployment | Complete | TensorRT compilation, Kubernetes Helm deployments, 3D Streamlit visualizer |
| P13: Advanced Vol Modeling | Complete | EGNO multi-asset graph surrogates, Joint SPX/VIX signature SDEs, RKHS Landmark MLSV |
| P14: Meta-Adaptation | Complete | Physics-Informed Meta-Learning FNO, Reptile/FOMAML online GPU adaptation, Model Risk Guardian |
| P15: Differentiable Hedging | Complete | Recurrent Deep Hedging (LSTM/GRU), D-XVA loss, PIVOT implied vol solver, low-vega gating |
| P16: Grey Rough Bergomi | Complete | C++/CUDA gRB path simulator, Mittag-Leffler CUDA kernel, uncertainty-guided active learning, Sobolev FNO |
Research code — МФТИ ФПМИ Master's thesis project, 2026. Contact author for usage permissions.
Key references:
- El Euch & Rosenbaum (2019) — The characteristic function of rough Heston models
- Abi Jaber (2019) — Lifting the Heston model
- Horvath, Muguruza & Tomas (2021) — Deep Learning Volatility
- Fang & Oosterlee (2008) — A novel pricing method for European options
- Perez et al. (2018) — FiLM: Visual Reasoning with a General Conditioning Layer