Skip to content

Sevenson87/VolEngine-X

Repository files navigation

VolEngine-X — Volatility & Risk Engine

A professional-grade options pricer and risk analytics engine built for quantitative finance roles. Implements three independent pricing methods, SVI volatility surface fitting, Gamma Exposure analysis, and portfolio stress testing — all accessible through an interactive Streamlit dashboard.


Architecture

08_VolEngine_X/
├── engine/             Mathematical core (3 independent pricers)
│   ├── pricer_bs.py    Black-Scholes + Newton-Raphson IV solver
│   ├── pricer_fdm.py   Crank-Nicolson Finite Difference Method
│   ├── pricer_mc.py    Vectorized Monte Carlo (Euler / Milstein)
│   └── greeks.py       Analytical + numerical Greeks (bumping)
├── models/
│   └── smile_fit.py    SVI volatility surface + arbitrage detection
├── risk/
│   ├── gex_analyzer.py Gamma Exposure profile + Gamma Flip
│   └── stress_test.py  Portfolio P&L stress scenarios
├── data_feed/
│   ├── polygon_client.py   Polygon.io REST client (with caching)
│   └── yfinance_fallback.py yfinance fallback (no key required)
├── tests/              Pytest test suite (25+ assertions)
├── app.py              Streamlit dashboard (4 tabs)
└── main.py             CLI entry point

Engine Modules

1. pricer_bs.py — Black-Scholes

Closed-form European option pricing:

C = S·N(d₁) − K·e^{−rT}·N(d₂)
d₁ = [ln(S/K) + (r + σ²/2)·T] / (σ√T)
d₂ = d₁ − σ√T

IV Solver — Newton-Raphson with bisection fallback:

σ_{n+1} = σ_n + (V_market − V_BS(σ_n)) / Vega(σ_n)

Initial guess: Brenner-Subrahmanyam approximation σ₀ ≈ √(2π/T) · V/S.

2. pricer_fdm.py — Crank-Nicolson FDM

Solves the Black-Scholes PDE on a discrete (S, t) grid.

The Crank-Nicolson scheme averages the explicit (forward) and implicit (backward) operators:

M_imp · V^{j+1} = M_exp · V^j + boundary_rhs

M_imp = I − 0.5·dt·L
M_exp = I + 0.5·dt·L

where L is the tridiagonal Black-Scholes spatial operator with coefficients:

αᵢ = ¼·dt·(σ²i² − r·i)
βᵢ = −½·dt·(σ²i² + r)
γᵢ = ¼·dt·(σ²i² + r·i)

Uses scipy.sparse tridiagonal matrices — the standard bank implementation (O(N) solve per time step vs O(N³) for dense matrices).

Key properties:

  • Unconditionally stable (no CFL condition)
  • Second-order accurate in both space and time: O(dS² + dt²)
  • Supports American early-exercise constraint

Verified accuracy vs. BS analytical:

Case BS Price FDM Price Rel. Error
ATM Call S=100 K=100 T=1Y σ=20% 10.4506 10.4534 0.027%
OTM Call S=100 K=110 T=1Y σ=20% 5.8594 5.8621 0.046%
ATM Put S=100 K=100 T=1Y σ=20% 5.5735 5.5761 0.047%
High Vol S=100 K=100 T=3M σ=30% 8.9543 8.9575 0.036%

3. pricer_mc.py — Monte Carlo (Milstein + Antithetic)

Milstein scheme (second-order vs. first-order Euler):

S_{T} = S · exp[(r − σ²/2)·T + σ·dW + ½·σ²·(dW² − T)]

Antithetic variates: pairs each path Z with −Z, halving variance without extra computation:

Z_av = np.concatenate([Z, -Z])   # zero extra RNG calls

Fully vectorized — no Python loops. All n_paths paths computed simultaneously as NumPy array operations.

4. greeks.py — Analytical + Bumping

Analytical BS Greeks:

Greek Formula
Δ Delta N(d₁) for calls, N(d₁)−1 for puts
Γ Gamma N'(d₁) / (S·σ·√T)
ν Vega S·N'(d₁)·√T (per 1 vol point)
Θ Theta −(S·N'(d₁)·σ)/(2√T) − r·K·e^{−rT}·N(d₂) (per day)
ρ Rho K·T·e^{−rT}·N(d₂) (per 1%)

Numerical bumping for FDM/MC pricers:

Δ = [V(S+ε) − V(S−ε)] / (2ε)         central difference
Γ = [V(S+ε) − 2V(S) + V(S−ε)] / ε²   second derivative
ν = [V(σ+ε) − V(σ−ε)] / (2ε·100)     per vol point

smile_fit.py — SVI Volatility Surface

Gatheral's Raw SVI parametrization:

w(k) = a + b · [ρ·(k−m) + √((k−m)² + σ²)]

where k = log(K/F) is log-moneyness and w = σ²_IV · T is total variance.

One SVI slice is fitted per expiry via weighted least-squares (ATM-weighted). The surface interpolates linearly in total-variance space between expiries.

Arbitrage detection:

  • Butterfly: w''(k) ≥ 0 everywhere (convexity check)
  • Calendar spread: w(k, T₂) ≥ w(k, T₁) for T₂ > T₁
  • Mispricing scanner: flags options where |IV_market − IV_surface| > threshold

gex_analyzer.py — Gamma Exposure

GEX = Σ [ |Γ| × OI × 100 × S² ]

Dealer sign convention:

  • Short calls → negative GEX (dealers are short gamma, amplify moves)
  • Long puts → positive GEX (dealers are long gamma, dampen moves)

Gamma Flip: the spot level where cumulative GEX crosses zero.

  • Above flip: positive GEX → mean-reversion regime
  • Below flip: negative GEX → trend / reflexive regime

Dashboard (Streamlit)

streamlit run app.py
Tab Content
🌐 Volatility Surface Interactive 3D SVI surface + mispricing scanner
⚡ Option Pricer BS / FDM / MC comparison + Greeks cards + PCP check
📐 GEX Analysis GEX bar chart, Gamma Flip, regime banner, key levels
🔥 Stress Test Portfolio builder, P&L heatmap, max-loss scenario

Tests

pytest tests/ -v
Test Assertion
FDM vs BS Relative error < 0.5% for 7 reference cases
MC vs BS Result within 3σ confidence interval
IV round-trip iv(bs_price(σ)) = σ to 1e-5 precision
Put-call parity Verified for BS, FDM, and MC
Greek accuracy Numerical bumping < 1% error vs. analytical

Quick Start

pip install -r requirements.txt

# Dashboard
streamlit run app.py

# CLI — SPY analysis (yfinance, no key needed)
python main.py SPY

# Run tests
pytest tests/ -v

Dependencies

Library Version Purpose
numpy ≥1.24 Vectorized numerics
scipy ≥1.10 Sparse linear algebra, optimization
pandas ≥2.0 Data manipulation
streamlit ≥1.32 Interactive dashboard
plotly ≥5.18 3D surface, heatmaps
yfinance ≥0.2.36 Free options chain fallback
requests ≥2.31 Polygon.io REST client
pytest ≥7.4 Test suite

Author

Tom Rolland — Quantitative Developer
sevenson506@gmail.com

Built as part of a quantitative finance portfolio project.

About

Options pricing engine: Black-Scholes · FDM · Monte Carlo · SVI

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages