15 knowledge objects (log, note, index, module, history) migrated to C3 knowledge schema v1. Bodies unchanged, metadata preserved.
119 lines
6.2 KiB
Markdown
119 lines
6.2 KiB
Markdown
---
|
||
id: object/086b7673-c183-6ca2-52fc-6f394107c9cf
|
||
type: arch
|
||
role: history
|
||
representation: canonical
|
||
state: historical
|
||
knowledge_schema: 1
|
||
---
|
||
# 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: A–J (Legacy-Hash `8a5760…` unverändert)
|
||
- M13 shared A–J
|
||
|
||
---
|
||
|
||
## 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.
|