Transformer for FX realized-volatility forecasting. Each hourly block encodes the joint market state — 10 forex pairs at 5m/15m/30m/1h, 14 macro daily series, FOMC/NFP event distances, and HAR realized-vol features — into a single context vector. The model processes 168 hourly blocks (7 days of context) and outputs a 24-horizon volatility forecast for one target symbol. End-to-end research harness with pluggable providers, per-experiment artifact isolation, and cost-aware tradeability analysis baked into every test run.
After 8 documented experiments across 18 months of iteration:
| metric | value |
|---|---|
| Spearman IC, h=2 (test split) | +0.336 |
| Spearman IC averaged across 24 horizons (test) | +0.277 |
| Top-10% predicted-vol lift (realised vol on top decile / pop. mean) | 1.55× at h=2 |
| Calibration | monotonic across all 10 deciles (h=1..12) |
| Train data | 19 years of joint hourly EUR/USD + 9 forex pairs + 14 macro |
| Model size | 1.06M params |
| Training time | ~16 min on Apple Silicon (MPS) |
Position vs literature (see research/research.md): competitive with a strong HAR-RV-IV baseline on EUR/USD vol — not above SOTA, but at the level the field reports.
Honest economic verdict (see end of experiments.md): the IC translates to +8-9%/yr P&L on a long-vol straddle proxy at institutional cost levels (5% bid-ask of premium), and to ~zero or negative under realistic retail OTC FX option costs. Vol-only on EUR/USD is publishable as a forecaster, not deployable as a retail strategy — exactly the structural ceiling Bollerslev-Tauchen-Zhou (2009) predicted.
A clean iteration loop for time-series forecasting research. The same harness has been used to test:
- direction prediction (v1 → v5: rejected — IC ≈ 0 OOS, multiple splits)
- volatility prediction (v6 → v8: confirmed — IC ≈ 0.28 stable, trades break even at best)
Each experiment's full report — what was tried, what numbers came out, what the verdict was, what the next move is — lives in experiments.md.
README.md ← you are here
documentation.md ← technical docs: stack, code, contracts, workflow
experiments.md ← scientific journal — one section per run
research/
research.md ← academic references + how each shaped our design
*.pdf ← open-access papers
src/ ← library (data, dataset, model, train, test, predict)
scripts/ ← one-off helpers (verifications, ablations, sims)
config.yaml ← single source of truth (every knob)
run.py ← CLI: data | train | test | predict
For technical detail (architecture, contracts, dataset format, provider interface, normalisation, end-of-training defences, etc.) see documentation.md.
pip install -r requirements.txt
# 1) edit config.yaml -> bump experiment.name
# 2) build joint-market wide CSVs (~2 min with HistData cache)
python run.py data
# 3) train + auto-final-test
python run.py train
# 4) live 24h forecast for the configured target symbol
python run.py predictEvery command reads from ./config.yaml. See
documentation.md for full CLI.
- Single source of truth: every knob in
config.yaml. Missing keys fail loudly. - One forward path:
src/predict.Predictoris the only call site ofmodel.forward(). Train, test, and live predict all share it. - Per-experiment isolation: bumping
experiment.nameis the only step needed to start a new run — artifacts go undermodel/<name>/andreports/<name>/, nothing overwritten. - No tqdm: custom Rich-based TUI in
src/tui.py. - Safetensors only: never
torch.save.
Full contracts list: documentation.md § 12.
- You're here — get oriented, see headline numbers.
- experiments.md — scroll to the latest section (currently v8) for the most recent verdict; scroll back through v7, v6, v5, v4, v3, v2, v1 to see the iteration arc.
- research/research.md — the academic literature behind every design choice, and where our results sit in it.
- documentation.md — when you want to actually run it or extend it.
- Research code, not investment advice.
- The tradeability analyses are first-order checks, not full backtests.
- Past directional experiments (v1-v5) found no generalisable edge on H1→24h FX direction — see experiments.md for the full negative-results record.
- All shipped data sources are free and require no account.
Mattia Beltrami — Computer Engineering, Politecnico di Milano GitHub: @beltromatti
Released under the MIT License.
Initial public release: 6 May 2026.