Skip to main content

Probabilistic price forecasting via stochastic differential equations (GBM/OU/neural), with AIC model selection, Monte Carlo quantiles, and fan charts.

Project description

neural-sde

Probabilistic price forecasting via stochastic differential equations. Fit a GBM or OU (mean-reverting) model to a price series, generate Monte Carlo forecasts with quantified uncertainty, and answer questions like "what's the probability this is up 10% in 30 days?" — without pretending to know the future.

This library produces probabilistic forecasts, not point predictions. forecast() returns a distribution over future paths, not a single "the price will be X" answer. Treat every number it gives you — quantiles, prob_above(), the fan chart — as a statement about uncertainty, not a promise. Financial markets are not stationary; a model fit on last year's regime can be a poor guide to next month's.

Install

pip install -e .                 # core: numpy, scipy, matplotlib
pip install -e ".[torch,pandas]" # + neural SDE path and pandas Series input
pip install -e ".[demo]"         # + yfinance, to run demo_forecast.py on real data

Requires Python 3.9+. See requirements.txt / pyproject.toml for pinned dependency ranges.

Quickstart

from neural_sde.highlevel import fit, forecast

model = fit(prices)                        # auto: AIC picks GBM vs OU
fc = forecast(model, horizon=30)           # antithetic Monte Carlo
print(fc.prob_above(prices[-1] * 1.10))    # P(+10% by day 30)
print(fc.quantiles([0.05, 0.5, 0.95]))     # 5th/50th/95th percentile price
fc.plot("forecast.png")                    # fan chart: history -> forecast cone

prices is any 1-D array-like or pandas Series of price levels (not returns). fit(model="neural") routes to a torch-based NeuralSDETrainer when torch is installed — see Neural path below before using it for anything besides diffusion/volatility. The GBM/OU parametric paths use exact (unbiased) transition densities and are the production-quality default.

On regimes

fit() estimates parameters from whatever window of history you give it. A GBM fit on a 6-month bull run will forecast that drift forward; an OU fit on a period of active mean-reversion will forecast reversion. Neither model knows the regime changed the day after your training window ends. Re-fit periodically, and sanity-check model.summary() (drift/vol/theta) against what you'd expect for the asset before trusting the forecast.

Neural path

fit(model="neural") learns state-dependent drift f(x,t) and diffusion g(x,t) functions instead of GBM/OU's parametric forms.

Diffusion recovery is solid — verified within 0.4-14% of the true value on synthetic GBM/OU calibration tests, and it's a genuine capability the parametric paths don't have: state-dependent volatility, not a single constant sigma. Useful for anything that wants to react to changing vol/regime (option pricing, vol-aware risk sizing).

Drift recovery is not usable at daily sampling frequency, and this isn't a bug that more engineering fixes. Recovering a state-dependent drift function from a single daily-sampled price path hits a hard signal-to-noise limit: SNR ≈ mu * sqrt(dt) / sigma, a few percent for typical parameters. A 5-seed-averaged sweep from 2,000 to 20,000 daily observations (up to 79 simulated years) improved median drift error only from ~267% to ~135% — consistent with the expected slow 1/sqrt(n) convergence, and nowhere near a usable tolerance. Extrapolating that rate, closing the gap would need on the order of 1,000+ years of daily data. The parametric GBM/OU drift estimate doesn't have this problem: it fits one global scalar averaged over the entire series rather than attempting state resolution, which sidesteps the issue instead of solving it.

Practical guidance: use the neural path for diffusion/volatility modeling. For anything that needs a drift estimate — hedging deltas, regime signals, mean-reversion speed — use the parametric GBM/OU drift, not the neural path's drift(x,t).

What's inside

Module Purpose
highlevel.py Public API: fit/forecast/FittedModel/Forecast — start here
sde_core.py Core SDE theory: drift/diffusion, Ito<->Stratonovich conversion
solvers.py / torch_solvers.py Euler-Maruyama, Milstein, Heun solvers (numpy and torch backends)
multi_asset.py Correlated multi-asset GBM/OU/CIR diffusion
neural_networks.py / trainer.py Neural drift/diffusion networks and training loop — see Neural path, requires torch
likelihood.py Score-matching / contrastive-divergence loss functions
forecasting.py Path forecasting and option pricing utilities
api.py Lower-level unified solver entry point

Demo

pip install -e ".[demo]"
python demo_forecast.py

With yfinance installed and network access, edit the top of the script to pull real data:

import yfinance as yf
from neural_sde.highlevel import fit, forecast

prices = yf.download("AAPL", period="2y")["Close"]
model = fit(prices)
fc = forecast(model, horizon=30)
print(fc.summary())
fc.plot("forecast.png")

Offline, the script instead demos against synthetic data with known dynamics, which doubles as a calibration test — it simulates GBM and OU paths with known parameters, fits them back, and checks:

  1. fit() recovers the true GBM parameters and AIC selects GBM.
  2. fit() recovers the true OU parameters and AIC selects OU.
  3. Monte Carlo quantiles agree with the exact lognormal distribution to <1%.
  4. The exact and euler (core-library) engines agree on the median to <3%.

forecast.png and forecast_example.png in this directory are pre-generated sample outputs from that script — regenerate them yourself with python demo_forecast.py.

Testing

pip install -e ".[dev]"
pytest test_convergence_rate.py test_adjoint_grad.py test_adjoint_verify.py \
       test_trainer_losses.py test_torch_solvers.py test_unified_entry.py \
       test_api_integration_v05.py test_edge_case_regression.py

archive/ holds superseded tests kept for historical reference (see archive/README.md); they aren't part of the suite.

License

MIT.

Credit

Built by Kevin Downie in collaboration with Claude (Anthropic).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

neural_sde-0.6.1.tar.gz (263.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

neural_sde-0.6.1-py3-none-any.whl (274.9 kB view details)

Uploaded Python 3

File details

Details for the file neural_sde-0.6.1.tar.gz.

File metadata

  • Download URL: neural_sde-0.6.1.tar.gz
  • Upload date:
  • Size: 263.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.6

File hashes

Hashes for neural_sde-0.6.1.tar.gz
Algorithm Hash digest
SHA256 536bfb70d852fa1fd214ebbd6c6d3d45bcb810d591e2e2bbe494ba4853199981
MD5 54e7299bc62f5f16a263b7d1ca381f51
BLAKE2b-256 6507a4ed5b6af48bf6b3b85b9ffc6cc48c466a0019dc7f34c2b061a28104aa25

See more details on using hashes here.

File details

Details for the file neural_sde-0.6.1-py3-none-any.whl.

File metadata

  • Download URL: neural_sde-0.6.1-py3-none-any.whl
  • Upload date:
  • Size: 274.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.6

File hashes

Hashes for neural_sde-0.6.1-py3-none-any.whl
Algorithm Hash digest
SHA256 3ba666e486e2019e6c66b3f7df1e069de1adc7f59de4a3674df7f7717f0c6a69
MD5 6804ef949584f680f29b2ff36b5c628f
BLAKE2b-256 0ed885b03137403e68649c01d599834d24a40604ce48ceec4a5aab1321bbb554

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page