Skip to content

Repository files navigation

VolForge

An adaptive options market-making & volatility-surface engine for NSE Nifty50 — a SIMD-vectorized C++17 pricing core, a multi-strike Avellaneda–Stoikov quoter, microstructure-aware toxicity/jump signals, a no-look-ahead tick backtester, and an interactive dashboard.

Price the whole chain. Quote the whole surface. Hedge the risk that's left. VolForge takes an options desk end-to-end: a microsecond C++ pricing core (Black–Scholes, Heston, arbitrage-free SVI) feeds a Greeks-constrained multi-strike market maker, whose quotes are stress-tested on a bitemporal, no-look-ahead backtester over three years of real NSE data — and then the one thing that stays modeled (the fills against our own quotes) is validated on real option microstructure with no broker account.

C++17 Python pybind11 Next.js Plotly Tests License

VolForge — the NIFTY implied-vol surface morphing through 2023–2025

The centerpiece: a real NSE NIFTY implied-vol surface calibrated arbitrage-free across 158 trading days — vol crush, the June-2024 election spike, and the April-2025 tariff shock all show up as skew and term-structure moves.


What VolForge Is

Most "options pricing" projects stop at a Black–Scholes function and a smile plot. Market making is a harder question:

Given a whole chain of correlated strikes, a limited risk budget, and adversaries who trade against you when they know something — where do you place your bid and ask, and how much do you hedge?

VolForge answers that question as a connected system, and then holds itself to the standard that matters for a trading study: could this survive contact with real data? Every layer is either real, or calibrated to real and validated, and the modeling boundary is written down.

Keywords: options market making, Avellaneda–Stoikov, volatility surface, SVI, arbitrage-free calibration, Greeks hedging, VPIN, order-flow toxicity, bipower variation, jump detection, Lee–Mykland, high-frequency econometrics, P&L attribution, SIMD, C++, pybind11, Next.js, quantitative finance.


Why This Is Hard

Sub-problem Why it's non-trivial What VolForge does
Speed A desk reprices hundreds of strikes many times a second; a Python loop can't keep up SIMD-vectorized C++17 core (AVX2/NEON) — a 500-strike chain in ~8 µs
Correlated inventory Strikes aren't independent; a delta in one is a delta in all Inventory is a portfolio-Greeks vector coupled by a factor-risk matrix Q = BΣ_FBᵀ
Risk limits You must cap |Δ|,|Γ|,|V| without killing the spread Closed-form KKT barrier on the quote (no inner QP)
Adverse selection Informed flow picks you off; jumps gap through your quotes VPIN toxicity surface + BN–S bipower jump detector widen quotes in bad regimes
Honest evaluation Look-ahead and invented fills make any backtest look good No-look-ahead bitemporal replay + calibrated, real-data-validated fills
Credibility "Your wiggle / your fills are made up" Real intraday path, real EOD surfaces, real option bars, and a live exchange cross-check

Read This Repo In Layers

Start here What you'll find
Run the dashboarddashboard/ Animated 3D surface, live Greeks book, spread-decision replay
Mathematical Core + core/quoting.cpp, python/volforge/micro/ Multi-strike A-S, VPIN, bipower jumps
core/ + benchmarks/ SIMD tri-path pricer, QuantLib oracle, latency benchmarks
Grounded in real data + python/volforge/backtest/ Bitemporal store, calibrated DGP, P&L attribution
Phase D + python/volforge/backtest/shadow.py, live/ Real option-bar shadow fills + a live no-account NSE check

Results Snapshot

Metric Result Meaning
Chain pricing ~8 µs / 500 strikes (~60 M opts/s) ~64× a vectorized SciPy loop; matched to QuantLib < 1e-5
Quote latency 3.2 µs core / 29.8 µs full loop whole-chain A-S + VPIN + jump, O(n) in strikes
SVI surface 158 days, 100% arbitrage-free butterfly + calendar, real NSE 2023–2025
Vol forecast LSTM R² −0.06 vs GARCH −0.61 OOS 5-day realized vol, strict expanding window
Delta-hedging Sharpe 1.85 → 5.77 on the real 5-min NIFTY path; peak |net Δ| 55 → 0.5
Microstructure lift +₹1.3k/day, t = 3.9 positive out-of-sample every year (t up to 7.3)
Real-fill validation 110k+ shadow fills, 6 expiries net-edge lift positive every month on real option bars
Live pricing check IV matched to 0.55 vol-pt vs NSE's own published IV, live, no account
P&L attribution residual < 1e-6 exact reconciliation; future-shuffle byte-identical
Test suite 984 pytest C++ oracle → SVI → micro → backtest → live

Phase 4 backtest overview


The Dashboard

An interactive Next.js + Plotly front-end — a static app fed by exported JSON, so it deploys to Vercel with no backend.

Screen What it shows
Overview & Performance Equity curve, hedged-vs-naked P&L, robustness sweep, latency, provenance, and the Phase-D real-fill / live-validation panels
3D Vol Surface The 158-day NIFTY IV surface with a play/scrub timeline, term structure, and smile snapshots
Greeks Book Real-time gross-vs-net (hedged) delta, vega, and a P&L attribution waterfall
Spread Replay Bar-by-bar bid/ask band, inventory, spot, and the net-Δ badge — watch each quoting decision
cd dashboard && npm install && npm run dev   # http://localhost:3000

System At A Glance

flowchart LR
    subgraph Data["Real NSE data (free)"]
        A["Bhav copy EOD<br/>(F&O chain)"]
        B["5-min NIFTY path<br/>(EOD-validated vs ^NSEI)"]
        C["1-min option bars<br/>(Hugging Face)"]
        D["Live option-chain JSON<br/>(no account)"]
    end
    subgraph Core["C++17 SIMD core"]
        E["Black-Scholes + Greeks"]
        F["Heston (Carr-Madan FFT)"]
        G["Multi-strike A-S quoting<br/>Q = BΣ_FBᵀ, O(n)"]
    end
    subgraph Signals["Microstructure"]
        H["VPIN toxicity surface"]
        I["BN-S bipower jumps"]
    end
    subgraph Eval["Evaluation"]
        J["No-look-ahead<br/>bitemporal backtester"]
        K["Exact P&L attribution"]
        L["Phase-D real-fill<br/>shadow validation"]
    end
    A --> M["Arbitrage-free SVI surface"]
    M --> G
    E --> G
    F --> M
    B --> J
    H --> G
    I --> G
    G --> J
    J --> K
    C --> L
    D --> L
    K --> N["Next.js + Plotly dashboard"]
    L --> N
Loading

Mathematical Core

Multi-strike Avellaneda–Stoikov

Classic Avellaneda–Stoikov quotes a single asset around a reservation price. VolForge generalizes it to a whole options chain whose strikes share risk. Let q be the vector of positions and B the strike→factor loading (delta/gamma/vega exposures). Inventory risk is the portfolio-Greeks vector G = Bᵀq, and strikes are coupled through the low-rank factor-risk matrix

$$ Q = B,\Sigma_F,B^{\top}. $$

Each strike i is quoted around a risk-adjusted reservation price with a risk-scaled half-spread:

$$ r_i = m_i - \gamma,(T-t),[Qq]_i, \qquad \delta_i = \tfrac{1}{2},\gamma,(T-t),Q_{ii} + \tfrac{1}{\kappa}\ln!\Big(1+\tfrac{\gamma}{\kappa}\Big). $$

Because Q = BΣ_FBᵀ is low-rank, a whole-chain quote never forms the n×n matrix — a factor-space contraction makes it O(n) in strikes (hot-loop-fast, zero-copy, GIL-released). At N = 1 it reduces exactly to scalar Avellaneda–Stoikov (to 1e-12). Delta/gamma/vega budgets |Δ|,|Γ|,|V| are imposed by a closed-form quadratic-barrier KKT multiplier — no inner quadratic program.

Arbitrage-free SVI surface

Per expiry, VolForge fits the raw SVI total-variance smile

$$ w(k) = a + b\big(\rho (k-m) + \sqrt{(k-m)^2 + \sigma^2}\big), $$

then enforces no static arbitrage on the traded moneyness band: Durrleman's butterfly condition g(k) ≥ 0 (with a guaranteed-feasible b-shrink fallback) and calendar monotonicity via monotone rearrangement. A hard lesson baked into the code: enforcing no-arb far out on the extrapolated wings collapses short-dated smiles and fabricates calendar violations — so it's enforced where options actually trade. Result: 100% arbitrage-free across 158 real NSE days.

VPIN toxicity surface

Order-flow toxicity is estimated per strike: adaptive volume buckets V_k = ADV_k / B, bulk-volume classification (own-price + delta-aware, reusing the C++ SIMD norm_cdf), and Nadaraya–Watson smoothing across moneyness. An elevated VPIN_k widens that strike's quote; a single strike reduces to canonical VPIN.

BN–S bipower jump detection

A Barndorff-Nielsen–Shephard realized-vs-bipower variation Z-test (RV/BV/TQ, overnight excluded) flags jump days on 5-min bars, and Lee–Mykland localizes the exact bar online. A detected jump widens all spreads by an exponentially-decaying premium. Measured size 0.85% @ α = 0.1%, power 99% at a ~13σ bar.


How Every Claim Is Checked

VolForge is checked at the numerical level, the statistical level, and the trading level.

Check What it verifies
QuantLib oracle Black–Scholes prices + Greeks and Heston FFT match QuantLib to < 1e-5
Scalar-limit test Multi-strike A-S at N=1 equals scalar Avellaneda–Stoikov to 1e-12
SVI round-trips Raw-SVI parameter recovery to ~1e-9; price→IV round-trip to 6e-7
No-arbitrage Butterfly g(k) ≥ 0 + calendar monotonicity on all 158 days
Future-shuffle Corrupting every row dated ≥ a cutoff leaves the prior replay byte-identical (zero look-ahead, demonstrated)
P&L reconciliation spread + theta + jump + diffusion + hedge − fees − hedge_cost matches realized equity, residual < 1e-6
DGP calibration Simulated vs real high-frequency stylized facts agree (KS p = 0.25, kurtosis 1.28 vs 1.42, jump-rate 10% vs 11%)
Real EOD cross-check Option-bar closes vs our own Bhav copy at log-corr 0.999–1.000
Live exchange check Our C++ implied vol reproduces NSE's published IV to 0.55 vol-pt

Grounded In Real Data — And Honest About The Boundary

A market-making backtest is only as honest as its inputs. VolForge is built on free, no-fee, mostly no-account data, and it states exactly what is real vs modeled.

Layer Source (free) Status
Intraday underlying path Real 5-min NIFTY (Kaggle dump; EOD-validated vs ^NSEI, corr 1.00000, median |Δ| 0.05%) Real
EOD option chain → surfaces NSE Bhav copy → 158 arbitrage-free SVI surfaces Real
Intraday per-option marks Hugging Face thetrademarkk/india-index-options-1m (1-min OHLCV) Real
Live L1 bid/ask (forward) Public NSE option-chain JSON (option-chain-v3, cookies only) Real (forward)
Order flow / fills vs our quotes Counterfactual — our quotes never existed Modeled → calibrated & validated

What remains modeled — and why that's defensible

Still modeled Why it can't be "downloaded" Mitigation
Fills vs. our own quotes Our quotes never existed in the tape A-S intensity calibrated to Bhav-copy volume (A = 12.9) + a sign-stable (A, κ) sensitivity grid + Phase-D bar-level shadow fills on real option 1-min bars + a tier-1 volume reality check
Intraday L1 depth / queue Free feeds give OHLCV bars, not order-book depth OHLC-range shadow fills approximate a touch; the live NSE chain captures forward L1 snapshots

Phases A–D: closing the honesty gap

  • Phase A — real path. Each backtest day is replayed on the realized 5-min NIFTY path. The full-stack microstructure lift survives on real data (smaller than on the engineered bridge, as expected).
  • Phase B — calibrated DGP. Where a synthetic path is still needed (warm-up, gaps, Monte-Carlo flow), it's an AR(1)-SV bridge calibrated to real bars and validated with KS / moment tests (p = 0.25).
  • Phase C — data-grounded fills. The A-S arrival scale A is anchored to real near-ATM Bhav-copy volume; the lift stays positive across a (A, κ, informed_gain, toxicity, hedge_band) sweep — it's a property of the quoting logic, not a tuned point.
  • Phase D — real-fill validation (the standout). Replaying our exact quoting and letting the real option bar decide each fill (a trade hits our quote when the bar [low, high] brackets it): across 110k+ shadow fills / 45 days / 6 monthly expiries, the microstructure book beats naïve A-S on net edge every month (full +₹0.806 vs naïve +₹0.780 /contract) and dodges toxic jump fills. It also surfaces a genuine limitation — the carry-forward monthly surface can't reprice the expiry-week vol spike (mark error ~18% → 35% into expiry) — which is exactly why shadow fills anchor to the real contemporaneous mid ± our own spread.
  • Phase D tier-3-lite — run live. A no-account poller of the public NSE option-chain JSON (15 one-minute snapshots of the NIFTY weekly): our C++ pricer reproduced NSE's own published IV to 0.55 vol-pt, the real ATM half-spread was ~15 bps, a naked 1-min quote faced ~20× its spread in directional risk, and delta-hedging removed ~43% of the 1-min ATM P&L variance. Baked into a static report (no frontend polling).

Phase D tier-2 shadow-fill validation on real option bars Phase D tier-3-lite live NSE validation

Caveats: shadow quotes don't sit in the real queue (no queue-priority truth); OHLC-range fills assume a touch = a fill; tier-3-lite is forward-only, minute-cadence, single-L1, and ToS-bound.


Repository Map

VolForge/
├── core/                    # C++17 pricing core
│   ├── pricer.{h,cpp}       # Black-Scholes (+IV), Heston (Carr-Madan FFT), SVI eval
│   ├── greeks.{h,cpp}       # 7 Greeks incl. Vanna/Volga; fused SoA SIMD batch
│   ├── quoting.{h,cpp}      # multi-strike Avellaneda-Stoikov (Q=BΣ_FBᵀ, O(n) hot path)
│   ├── fft.{h,cpp}          # dependency-free radix-2 FFT (Carr-Madan chain)
│   └── simd/                # AVX2/NEON/scalar exp + West-2009 normal CDF
├── bindings/                # pybind11 module -> volforge._core
├── python/volforge/
│   ├── data/                # Bhav copy, bitemporal store, calendar, real 5-min path,
│   │                        #   option_intraday (Phase-D 1-min option bars)
│   ├── vol/                 # SVI (calibration + no-arb), GARCH, LSTM, 158-day history, viz
│   ├── micro/               # vpin (toxicity surface), jumps (BN-S + Lee-Mykland)
│   ├── mm/                  # quoting wrapper, engine (the closed loop)
│   ├── live/                # Phase-D tier-3-lite: no-account NSE option-chain snapshots
│   └── backtest/            # fills, book, pnl, surface, simulator, strategies,
│                            #   realpath (real path), calibrate (DGP), shadow (real fills)
├── dashboard/               # Next.js + Plotly (3D surface · Greeks book · spread replay)
├── scripts/                 # reproducible Phase 1-4 + Phase A-D pipelines
├── benchmarks/              # C++ + Python latency / accuracy benchmarks
├── tests/                   # 984 pytest (QuantLib oracle → SVI → micro → backtest → live)
├── docs/figures/            # generated surface / backtest / validation figures
├── requirements.txt         # arm64 / M-series deps
└── CMakeLists.txt           # feature-probed -O3/-march/-mavx2/-mfma, pybind11

Run Locally

Prereqs: a C++17 compiler + CMake, Python 3.13 (Homebrew CPython on macOS for full arm64 wheels), and Node 18+ for the dashboard.

git clone https://github.com/PratyushGupta7/VolForge.git
cd VolForge

# Python + native core
/opt/homebrew/bin/python3.13 -m venv .venv      # or any CPython 3.11+
source .venv/bin/activate
pip install -r requirements.txt

# Build + import + execute the C++ core (GATE 0)
python tests/smoke_test.py

Then run any of the reproducible pipelines:

python scripts/phase2_deliverables.py                       # 3D surface + GARCH figures
python scripts/build_surface_history.py --mode weekly       # 158-day cube + ANIMATED 3D surface
python scripts/lstm_vs_garch.py                             # LSTM vs GARCH OOS (5d RV)
python scripts/phase3_demo.py                               # closed-loop quoting on real NIFTY
python scripts/phase4_backtest.py                           # no-look-ahead backtest + P&L lift + dashboard export
python scripts/shadow_validate.py                           # Phase D t1/t2: real-fill validation on 1-min option bars
# Phase D t3-lite (market hours only): live NSE chain -> static report
python scripts/capture_nse_chain.py --duration-min 15 && python scripts/live_validate.py

Dashboard:

cd dashboard && npm install && npm run dev   # http://localhost:3000

Verify

python tests/smoke_test.py     # configure + build + import + execute  -> GATE 0
pytest                         # full suite (984 passing)
python benchmarks/benchmark.py # C++ SIMD vs NumPy/scipy
python benchmarks/bench_svi.py # full-surface SVI calibration latency
./build/bench_pricer 500 5000  # standalone C++ latency (SIMD vs scalar)

Dashboard checks:

cd dashboard && npm run build   # type-check + lint + static export

Performance Notes

The dev machine is arm64 (Apple Silicon, NEON); the AVX2 benchmark target is x86-64. Every SIMD kernel ships three implementations behind one signature, selected at compile time — CMake only adds -mavx2/-mfma where the compiler accepts them, so the same source is fast on both. Published speedups are reported against the host CPU string. The compiled core is built into the package as python/volforge/_core*.so; import volforge re-exports it alongside volforge.data / volforge.vol.

  • 500-strike chain (price + 7 Greeks) in ~8 µs — ~120× inside a < 1 ms budget; ~60 M options/s.
  • Vectorized normal CDF (West 2009): 4× vs scipy, max error 2.2e-16.
  • Heston whole-chain FFT (4096-pt): ~0.47 ms, matches QuantLib to < 1e-5.
  • Closed-loop quote latency: 3.2 µs (C++ A-S core) / 29.8 µs (full VPIN + jump loop).

Design Principles

  • Make the math visible. From the KKT barrier to the SVI no-arb band, the derivations live in the code, not just in charts.
  • Document the modeling boundary. It's a table in the README, and the limitation Phase D surfaced (expiry-week mark error) is written down next to the results it affects.
  • Never look ahead. Bitemporal surfaces + a byte-identical future-shuffle test make the no-look-ahead claim testable, not asserted.
  • Calibrate, then validate. Whatever can't be downloaded is calibrated to real data and checked with statistical tests.
  • Relative lift is the robust result. Under shared, calibrated flow, the lift of microstructure-aware quoting over naïve A-S is what generalizes — and it does, out-of-sample, every year.

Roadmap

  • Deploy the static dashboard to a custom domain.
  • Second underlying (BANKNIFTY) via the same free pipeline → external validity.
  • Block-bootstrap confidence intervals for the lift over real paths.
  • Regime split (2023 calm / 2024 election / 2025 tariff) on the real intraday path.
  • Optional live L1/tick feed (broker websocket) for true queue-aware fills.

FAQ

Is this financial advice or a live trading system? No. It's a research and engineering project — a backtest and a live measurement tool, not an order router.

Why not just buy a paid data feed? A paid feed would make historical option marks real, but it would not fix the counterfactual fills (our quotes never existed). Grounding + honest calibration is a better use of ₹0 than a feed that doesn't close the actual gap.

Why is the reported real-path lift smaller than on the simulated path? Because the simulated path injected its own jumps and clustering. On the real path the lift is smaller but honest — and it's still positive and significant out-of-sample in every year.

Can I reproduce the numbers? Yes — every figure and JSON is produced by a script in scripts/, from cached parquet. The C++ core is validated against QuantLib in the test suite.


Disclaimer

This repository is for research and educational use only. It is not financial advice, an offer to buy or sell securities, or a recommendation to deploy capital. Market data can be delayed, incomplete, or unavailable; backtests are historical simulations; and live captures depend on external, rate-limited, ToS-bound public endpoints.


Citation

If you reference this project, please cite:

Gupta, P. (2026). VolForge: An Adaptive Options Market-Making & Volatility-Surface Engine. GitHub. https://github.com/PratyushGupta7/VolForge

A companion research abstract, "Microstructure-Aware Options Market Making: A Greeks-Constrained Multi-Strike Avellaneda–Stoikov Engine," was submitted to CFE-CMStatistics 2026.


License

MIT License — see LICENSE.

Author

Built by Pratyush Gupta.

If VolForge made you think differently about how a desk prices, quotes, and hedges an options chain, star the repository and open the dashboard.

About

Adaptive options market-making & volatility-surface engine for NSE Nifty50: a SIMD C++17 core (Black-Scholes, Heston FFT, arbitrage-free SVI) + a Greeks-constrained multi-strike Avellaneda-Stoikov quoter with VPIN toxicity & jump detection, validated on a no-look-ahead backtester on real 2023-25 data.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages