trading-system-docs/notes/trading/system-docs/phase10a_execution_context.md

111 lines
6 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.

# Phase 10a — ExecutionContext-Dataclass + Versionierung + Tests (M12/M13)
> Autoren: Rain Ocampo (Hermes) | Datum: 2026-08-23
> Status: **ABGESCHLOSSEN + DEPLOYT** (Analyse/Design/Verifikation + Datenmodell/Audit/Run-Hash-Integration, OHNE Fill-Änderungen)
> Tags: trading, mt5, architecture, historical-v2, m12, m13, phase10a, execution-context
---
## 1. Ziel (aus Phase-9-Freigabe)
Phase 10a = **ExecutionContext-Dataclass + Versionierung + Tests**.
**WICHTIG — NUR Datenmodell/Context/Audit/Run-Hash-Integration vorbereiten.**
Noch KEINE Bid/Ask-Ausführung, KEINE Spread-/Slippage-/Kostenberechnung.
Danach STOPP und Bericht.
Die 7 festgelegten Entscheidungen (Christian, 22.08.2026) sind als Modellversionen
und Defaults in diesem Modul kodiert — aber es wird NOCH NICHTS berechnet.
---
## 2. Modul: `shared/historical/execution_context.py` (NEU)
Gemeinsame Quelle für M12 UND M13 (konsistent mit DatasetContext, R1-Prinzip).
### Enums (festgelegte Bezeichnungen, Entscheidung 7)
- `ExecutionModel`: `LEGACY_SINGLE_PRICE`, `REFERENCE_BID_ASK`, `BROKER_APPROXIMATION`, `BROKER_REPLAY`, `TICK_REPLAY`
- `SpreadModel`: `NONE`, `BID_ASK_INTRINSIC`, `SYNTHETIC_FIXED` (Entscheidung 1)
- `SlippageModel`: `NONE`, `DETERMINISTIC_FIXED` (Entscheidung 3: deterministisch V1)
- `CostModel`: `NONE`, `cost_model_v1_simple` (Entscheidung 4)
- `IntrabarPolicy`: `PESSIMISTIC`(Default), `OPTIMISTIC`, `STOP_FIRST`, `TARGET_FIRST`, `TICK_RESOLUTION`, `UNKNOWN` (Entscheidung 2)
### Modellversionen (pro Modell unabhängig, künftig bumpbar)
`execution_context_v1`, `execution_model_v1`, `spread_model_v1`, `slippage_model_v1`, `cost_model_v1`, `intrabar_policy_v1`.
### Dataclass `ExecutionContext`
Felder: `execution_context_version`, `execution_model`+`_version`, `price_basis`, `spread_model`+`_version`+`spread_points`, `slippage_model`+`_version`+`slippage_points`, `cost_model`+`_version`, `intrabar_policy`+`_version`, `feed_type`, `validation_errors`.
Methoden: `to_dict()`, `is_valid()`, `validate()` (fail-closed bei unbekanntem Modell), Build-Helper `build_execution_context()`.
**Keine Berechnung** — nur Konfiguration + Modellversionen für Hash/Audit.
---
## 3. service.py-Integration (M12 Run-Hash + Audit)
### `_compute_run_hash` — erweitert um `execution`-Parameter
- **Legacy** (`execution=None`): exakt alter Hash, **unverändert** (diff-verifiziert).
- **V2** (`execution` gesetzt): fließen zusätzlich ein (Entscheidung J — **Modellwerte + Versionen**):
- `execution_model`, `execution_model_version`
- `price_basis`
- `spread_model`, `spread_model_version`
- `slippage_model`, `slippage_model_version`
- `cost_model`, `cost_model_version`
- `intrabar_policy`, `intrabar_policy_version`
> **Wichtiger Befund (Reproducibility)**: Anfangs wurden nur die Modell-**Versionen** in den Hash genommen. Das war fehlerhaft: ein Wechsel `bid_ask`→`single` ändert das Ausführungsmodell (REFERENCE_BID_ASK vs LEGACY_SINGLE_PRICE), aber die Version blieb `execution_model_v1` → **identischer Hash**. Korrigiert: **Modellwerte UND Versionen** fließen in den Hash. Test `test_andere_execution_andere_hash` + `test_andere_execution_version_andere_hash` decken beides ab.
### Gate/Audit — ExecutionContext im V2-Pfad
- Im Gate (`ctx is not None`) wird ein ExecutionContext gebaut (aus `price_basis`+`feed_type` des DatasetContext):
- `price_basis=="bid_ask"``execution_model=REFERENCE_BID_ASK`
- sonst → `LEGACY_SINGLE_PRICE`
- Das Execution-Audit (`exec_ctx.to_dict()`) wird **sowohl für allowed als auch blocked Runs** an `audit["execution"]` angehängt (auditierbar).
- Der V2-run_hash nutzt dieses Execution-Audit.
---
## 4. Tests: `m12_app/tests/test_phase10a_execution_context.py` (11/11)
| # | Test | Zweck |
|---|------|-------|
| 1 | `test_default_legacy_single_price` | Defaults: LEGACY_SINGLE_PRICE, NONE-Modelle, PESSIMISTIC, keine Doppelzählung |
| 2 | `test_build_reference_bid_ask` | REFERENCE_BID_ASK-Ableitung; kein künstlicher Spread |
| 3 | `test_validate_fail_closed_unknown_model` | unbekanntes Modell → invalid |
| 4 | `test_validate_unknown_intrabar` | unbekannte Intrabar-Policy → invalid |
| 5 | `test_to_dict_roundtrip` | to_dict serialisierbar |
| 6 | `test_gleiche_execution_gleicher_hash` | gleiche Execution → gleicher Hash |
| 7 | `test_andere_execution_andere_hash` | bid_ask vs single → anderer Hash + Audit-Model |
| 8 | `test_andere_execution_version_andere_hash` | Versions-Bump → andere Identität |
| 9 | `test_legacy_kein_execution_audit` | Legacy: kein Audit, kein Execution-Dict, Hash unverändert |
| 10 | `test_v2_execution_audit_present` | V2: Audit.execution vorhanden mit Modellversionen |
| 11 | `test_blocked_execution_audit_present` | Blocked-Run trägt Execution-Audit |
**Regression (alle grün):**
- Phase 8 Gate: 13/13
- M12 Backtest: 12/12
- Phase 5: 20/20, Phase 6: 14/14, Phase 7: AJ (Legacy-Hash `8a5760…` unverändert)
- M13 shared AJ
---
## 5. Deploy & Verifikation (Produktion)
- **Deploy**: `execution_context.py` + `__init__.py` + `service.py` per `docker cp` in **Modul-12-Backtesting**; `execution_context.py` + `__init__.py` auch in **Modul-13-Optimization** (geteiltes shared/historical — sonst ImportError bei `import shared.historical`).
- **chown** auf appuser 1001 (Deploy-Pitfall, bekannt aus Phase 8).
- **Restart** M12 (uvicorn ohne `--reload`).
- **Health**: `/health` 200, `/health/ready` 200 (via Python urllib im Container).
- **Legacy-Smoke PASS**: beide Runs COMPLETED, run_hash `bc6e2553…` + data_hash `d76a7549…` **identisch wie Phase 8** → Legacy unverändert.
- **Rollback-Backup**: `/opt/trading-modules/backup_phase10a_<TS>/` (service.py, shared_init.py, execution_context.py).
---
## 6. Nächster Schritt (Phase 10b, nach Freigabe)
**Bid/Ask-Datenmodell + Fill** — vollständige Propagation der bid/ask-OHLC durch den M12-Engine-/Execution-Pfad (Entscheidung 5), erste echte Bid/Ask-Fills (Long Entry=Ask, Exit=Bid; Short umgekehrt, Entscheidung 1). NOCH NICHT jetzt — STOPP nach dieser Phase.
---
## 7. STOPP
Phase 10a abgeschlossen. **Keine Implementierung von Phase 10b.** Auf Freigabe warten.