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:
fit()recovers the true GBM parameters and AIC selects GBM.fit()recovers the true OU parameters and AIC selects OU.- Monte Carlo quantiles agree with the exact lognormal distribution to <1%.
- The
exactandeuler(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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
536bfb70d852fa1fd214ebbd6c6d3d45bcb810d591e2e2bbe494ba4853199981
|
|
| MD5 |
54e7299bc62f5f16a263b7d1ca381f51
|
|
| BLAKE2b-256 |
6507a4ed5b6af48bf6b3b85b9ffc6cc48c466a0019dc7f34c2b061a28104aa25
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3ba666e486e2019e6c66b3f7df1e069de1adc7f59de4a3674df7f7717f0c6a69
|
|
| MD5 |
6804ef949584f680f29b2ff36b5c628f
|
|
| BLAKE2b-256 |
0ed885b03137403e68649c01d599834d24a40604ce48ceec4a5aab1321bbb554
|