Skip to content

feat(diffusion): add HestonProcess — stochastic volatility model with vectorised MC and analytical pricing - #82

Open
hass-nation wants to merge 1 commit into
crflynn:masterfrom
hass-nation:feat/heston-stochastic-volatility
Open

feat(diffusion): add HestonProcess — stochastic volatility model with vectorised MC and analytical pricing#82
hass-nation wants to merge 1 commit into
crflynn:masterfrom
hass-nation:feat/heston-stochastic-volatility

Conversation

@hass-nation

Copy link
Copy Markdown

Summary

This PR adds the Heston (1993) stochastic volatility model to the diffusion process collection and addresses two long-standing issues:

  • Closes Add type annotations #62 — adds Python type annotations to the entire stochastic.processes.diffusion module.
  • Partially addresses NumPy 2.0 compat? #79 — the new code uses only stable NumPy APIs; no deprecated type aliases anywhere in the diffusion module.

Why Heston?

The Heston model is the industry-standard stochastic volatility model for options pricing and risk management:

  • It cannot be expressed as a 1-D DiffusionProcess (bivariate, correlated).
  • Users currently have to re-implement it from scratch each time.
  • Adding it makes stochastic useful for the full options-pricing workflow.
dS_t = μ S_t dt + √V_t S_t dW_t^S
dV_t = κ(θ − V_t) dt + σ √V_t dW_t^V
Corr(dW_t^S, dW_t^V) = ρ dt

New Public API

from stochastic.processes.diffusion import HestonProcess

proc = HestonProcess(mu=0.05, kappa=2.0, theta=0.04, sigma=0.3, rho=-0.7,
                     initial_variance=0.04, t=1.0, rng=np.random.default_rng(42))

# Simulation
prices, variances = proc.sample(252)
prices_mc, vars_mc = proc.sample_paths(252, paths=10_000)  # ~36× faster than serial
prices_at, vars_at = proc.sample_at(np.array([0.25, 0.5, 0.75, 1.0]))

# Four variance schemes
proc = HestonProcess(..., scheme='quadratic-exponential')  # Andersen (2008), most accurate

# Antithetic variates
prices_mc, _ = proc.sample_paths(252, paths=10_000, antithetic=True)

# Analytical moments
proc.expected_variance(1.0)       # E[V_T]
proc.expected_log_return(1.0)     # E[log(S_T/S_0)]

# Option pricing
call, se = proc.price_european(strike=1.0, risk_free_rate=0.05, paths=50_000)
strikes, calls = proc.price_european_fft(risk_free_rate=0.05)  # 4096 strikes in ~0.5 ms

# Analytics
strikes, ivols = proc.implied_vol_smile(risk_free_rate=0.05)
k_var = proc.variance_swap_rate()

# Calibration
fitted_ts    = HestonProcess.fit(log_returns, dt=1/252)
fitted_smile = HestonProcess.fit_to_smile(strikes, market_prices, r=0.05, t=1.0)

Numerical Schemes

Component Scheme Reference
Asset price Log-Euler (guarantees S_t > 0)
Variance (default) Full truncation Lord et al. (2010)
Variance (optional) Reflection / Partial-truncation Lord et al. (2010)
Variance (optional) Quadratic-Exponential Andersen (2008)
Correlated increments Cholesky factorisation

The Feller condition 2κθ > σ² is checked; a UserWarning fires when violated (sampling still works).

Performance

Method Config Time
sample_paths (full-truncation) 10k paths × 252 steps 115 ms
Serial sample() 1 path × 252 steps 0.41 ms → ~36× speedup
price_european_fft 4096 strikes ~0.5 ms

Files Changed

File Change
stochastic/processes/diffusion/heston.py NEW — ~1750 lines
tests/processes/diffusion/test_heston.py NEW — 257 tests, 28 classes
stochastic/processes/diffusion/__init__.py Export HestonProcess
stochastic/processes/diffusion/diffusion.py Type annotations
stochastic/processes/diffusion/extended_vasicek.py Type annotations
stochastic/processes/diffusion/vasicek.py Type annotations
stochastic/processes/diffusion/cox_ingersoll_ross.py Type annotations
stochastic/processes/diffusion/ornstein_uhlenbeck.py Type annotations
stochastic/processes/diffusion/constant_elasticity_variance.py Type annotations
CHANGELOG.rst 0.8.0 entry
README.rst Usage example

Tests

674 passed, 10 warnings in 22s   (417 original + 257 new, 0 regressions)
mypy: Success: no issues found in 8 source files
Coverage: 98% on heston.py

References

  1. Heston (1993). A closed-form solution for options with stochastic volatility. Rev. Financial Studies, 6(2), 327–343.
  2. Lord, Koekkoek & Van Dijk (2010). A comparison of biased simulation schemes for stochastic volatility models. Quantitative Finance, 10(2), 177–194.
  3. Andersen (2008). Efficient simulation of the Heston stochastic volatility model. J. Computational Finance, 11(3), 1–22.
  4. Carr & Madan (1999). Option valuation using the fast Fourier transform. J. Computational Finance, 2(4), 61–73.

🤖 Generated with Claude Code

Implements the Heston (1993) bivariate stochastic volatility model:

  dS = μS dt + √V·S·dW^S
  dV = κ(θ−V) dt + σ√V·dW^V,  Corr(dW^S, dW^V) = ρ dt

New public API
--------------
• sample(n) / sample_paths(n, paths) / sample_at(times) — simulation
• 4 variance schemes: full-truncation (default), reflection,
  partial-truncation, quadratic-exponential (Andersen 2008)
• Antithetic variates (exact mirror identity, no approximation)
• expected_variance / variance_of_variance / expected_log_return — exact moments
• characteristic_function(u, t) — Heston (1993) CF, exp(−dT) formulation
• price_european(strike, r) — MC pricer with put-call parity
• price_european_fft(r) — Carr-Madan FFT, 4096 strikes in ~0.5 ms
• implied_vol_smile(r) — BS IV surface via Brent inversion
• variance_swap_rate(t) — closed-form fair variance strike
• realized_variance(path) — time-average of simulated variance
• fit(log_returns, dt) — MLE calibration from return series
• fit_to_smile(strikes, prices, r, t) — smile calibration via FFT

Also adds Python type annotations to all 6 existing diffusion files
(closes crflynn#62) and exports HestonProcess from the package __all__.

Tests: 257 new tests across 28 test classes (674 total, 0 regressions)
Coverage: 98% on heston.py
mypy: clean (8 source files)
Speedup: sample_paths ~36x faster than serial sample() calls

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant