trading-system-docs/notes/trading/system-docs/modul-12-backtesting.md

128 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Modul-12: Backtesting
**Status: FREIGEGEBEN** · Container `Modul-12-Backtesting` · Image `backtesting:0.1.2` (V1 + V1.1 parallel)
## Zweck
Deterministische, reproduzierbare **historische Strategietests** auf echten
OHLCV-Daten aus **Modul-03** (PostgreSQL). Gleiche Strategie-Logik wie
**Modul-05** (`trend_pullback_v1`) und identische Regime-Engine wie **Modul-04**
der Backtest entscheidet exakt so wie Live/Paper. **V1 ohne KI/ML, ohne Live-Orders,
ohne Broker-Ausführung.** Modular erweiterbar für weitere Strategien (Breakout, ORB,
Mean-Reversion) über gemeinsame `Strategy`-Schnittstelle + Registry.
## Architektur / Datenfluss
```
OHLCV (Modul-01 PostgreSQL, Tabelle ohlcv)
│ synchron, direkt nach Timestamp/Zeitraum (KEIN /history?limit)
Modul-12-Backtesting ── POST /backtest
├── core/engine.py deterministische Backtest-Loop (kein Lookahead)
├── strategies/ trend_pullback_v1 (1:1 zu Modul-05)
├── regime/engine.py Regime-Engine (1:1 zu Modul-04)
├── storage/storage.py Persistenz backtest_run/trade/equity
└── api/main.py REST-API (intern, Port 55012)
API (Docker-intern, Port 55012):
/health, /health/ready
POST /backtest Backtest starten (synchron, returns Ergebnis)
GET /backtest/{run_id} Run-Metadaten
GET /backtest/{run_id}/status Status + run_hash/data_hash
GET /backtest/{run_id}/trades gespeicherte Trades
GET /backtest/{run_id}/equity Equity-Kurve
GET /backtest alle Runs
POST /backtest/{run_id}/rebuild (idempotenter Rebuild aus DB)
GET /strategies registrierte Strategien + Versionen
```
Kein RabbitMQ: Backtest ist ein synchroner, request/response-Aufruf. Port `55012`
ist **nur intern** (`expose:`), kein öffentliches Port-Mapping.
## Datenquelle
- OHLCV direkt aus PostgreSQL (`ohlcv`), Spalten `provider, symbol, timeframe, ts,
open, high, low, close, volume`.
- Abfrage **nach Timestamp/Zeitraum** (`start_date`..`end_date`), nicht via
`/history?limit=N` — vollständige, deterministische Datenbasis.
- Mindestanzahl Candles: `min_candles_required` (default 220), sonst Fehler.
## Bias-Schutz / Realismus (kein Lookahead)
- **Entry am OPEN der Folgewandle** nach dem Signal (nie zum bekannten Signal-Close).
- **Regime & Strategie** werden nur auf **abgeschlossenen** Candles (bis Candle i)
ausgewertet — keine zukünftige Information.
- **Intrabar Stop/Target konservativ**: Stop wird VOR Target geprüft (kein Lookahead
durch Intrabar-Reihenfolge). Falls beide in einer Candle getroffen, gewinnt Stop
(Worst-Case).
- **Gap-Handling**: Überspringt der Open den Stop/Target, Fill zum Gap-Open
(realistisch schlechter).
- **Gebühren/Spread/Slippage** werden auf Entry UND Exit angewendet (verschlechtern
den Fill).
- **R-Multiple** bezieht sich auf das **Geldrisiko** `qty * |entry stop|` (nicht
Preisdifferenz) — `expectancy_r` daher korrekt (vorheriger Bug: 31431 → korrekt 2.0).
## Eingaben (POST /backtest)
- Symbol, Asset-Klasse, Provider, Timeframe, Start-/Enddatum
- Strategy + Version (`trend_pullback_v1`, default `1.0.0`)
- Initiales Kapital, Risk % (Risk-basierte Positionsgröße)
- Gebühren (fix + %), Spread (Preispunkte), Slippage (Preispunkte)
- Optionale Limits: `max_positions`, `max_qty`
## Eigene Tabellen (Migration `migrations/001_backtest.sql`)
- `backtest_run` — Run-Metadaten: run_id, strategy+version, symbol, timeframe,
status (COMPLETED/…), data_hash, run_hash, Parameter (JSON), Datenzeitraum.
- `backtest_trade` — einzelne Trades: direction (LONG/SHORT), qty, entry/exit-Preis,
entry/exit_ts, signal_ts, reason (target/stop/force_close), regime, gross_pnl,
fee, pnl, r (R-Multiple), strategy_version.
- `backtest_equity` — Equity-Kurve (Zeitstempel, Equity, offene Positionen).
Jede Tabelle FK auf `backtest_run(run_id) ON DELETE CASCADE`.
## Determinismus / Reproduzierbarkeit
- Eindeutige `run_id` + deterministischer `run_hash` + `data_hash`.
- `run_hash`: Hash über Strategy+Version+Parameter+Datenzeitraum+data_hash.
- `data_hash`: Hash über die geladenen OHLCV-Daten.
- **Gleiche Daten + gleiche Version + gleiche Parameter → identische Trades, Equity,
Kennzahlen und identischer run_hash** (E2E-verifiziert).
## Tests
- `tests/test_backtest.py`: 12/12 grün (deterministisch, LONG/SHORT, fees, slippage,
lookahead, stop/target, gaps, unzureichende Daten, Strategy-Version/Parameter,
Rebuild-Identität).
- `tests/fixtures.py`: deterministische Fixture-Factory.
- `tests/m12_fixtures.py`: erzeugt E2E-Fixtures (BT_PULL LONG, BT_PULL_S SHORT) für
die VPS-ohlcv-Tabelle.
- `tests/determinism_check.py` / `determinism_diff.py`: E2E-Determinismus-Nachweis
(identische Trades/Equity/Kennzahlen/Hashes).
## E2E-Verifikation (VPS, 20.08.2026)
- **LONG** (BT_PULL, TREND_UP): 1 Trade, winrate 1.0, expectancy_r 1.94, net_pnl
196.59, max_drawdown 0.0001, r=1.94, reason=target.
- **SHORT** (BT_PULL_S, TREND_DOWN): 1 Trade, short_count 1, net_pnl 194.96.
- `signal_ts 15:00 → entry_ts 16:00` (Einstieg am Open der Folgewandle — Lookahead
praktisch verifiziert).
- run_hash + data_hash gesetzt (Beispiel: `bc6e2553…` / `d76a7549…`).
- **Determinismus**: zwei identische Backtests → identischer run_hash, data_hash,
Metrics, Trades (normalisiert), Equity-Curve.
- **Stop/Target/Gap**: Engine-`_evaluate_exit` geprüft — Gap-Down unter Stop → Fill
zum Gap-Open; Target bei high≥target; Stop vor Target (konservativ); SHORT Gap-Up
→ Fill zum Gap-Open.
- Health `/health` 200, `/health/ready` 200; keine öffentlichen Ports.
## Compose / Betrieb
- Netzwerk `trading-modules`, DB-Host `Modul-01-PostgreSQL` (Modul-01), Port 55012
nur intern (`expose`), `restart: unless-stopped`. Kein öffentliches Port-Mapping.
## Nächste Module
- **Modul-13: Optimization** — Image `optimization:0.1.0`, E2E-verifiziert (12/12 Punkte), **FREIGEGEBEN** (20.08.2026). Details: `modul-13-optimization.md`.
- **V1.1-Strategie**: `trend_pullback_v1.1` (Image `backtesting:0.1.2`) — Spezifikation und Parameter: `trend-pullback-v1.1-spec.md`.
---
## Geändert
```
Geändert von: Rain Ocampo
Datum: 20.08.2026
Grund: Modul-12-Backtesting als FREIGEGEBEN markiert (deployt + E2E verifiziert: deterministisch, kein Lookahead, Stop/Target/Gap, LONG/SHORT, run_hash+data_hash).
```
Geändert von: Rain Ocampo
Datum: 20.08.2026
Grund: Modul-12-Doku aktualisiert — Image auf backtesting:0.1.2 (V1.1), V1-Kompatmodus bitgenau, Referenz auf V1.1-Spec und Modul-13.