Entwurf: BRK mit eigenem Positions-Slot (docs/brk-eigener-slot.md)

User: "der brk trade soll komplett unabhaengig von m15 oder manuellen trades
laufen". Der Entwurf ist am echten Code verifiziert, aber NICHT gebaut -
Umsetzung gehoert in eine eigene Sitzung mit flachem Konto.

DER ENTSCHEIDENDE BEFUND macht den Umbau viel kleiner als gedacht:
TrailingManager.__init__ nimmt BEREITS einen Trader entgegen (trailing.py:146)
und liest ausschliesslich ueber self.trader.snapshot(). Es haengt also nicht an
einer globalen Position, sondern an SEINEM Trader. Damit ist die Loesung ein
ZWEITER, ticket-gebundener TradeManager fuer BRK samt eigenem Trailing - statt
29 Stellen in engine.py umzubauen. Der validierte Pfad (manuell + M15) bleibt
dabei vollstaendig unangetastet, also kein Regressionsrisiko auf der gemessen
besseren Population.

DER KRITISCHE PUNKT ist die Adoption: TradeManager.refresh() greift heute jede
Position auf dem Symbol (positions_get(symbol=sym) mit Fallback auf alle). Mit
zwei Managern wuerden sich beide dieselbe Position schnappen. Der BRK-Manager
muss deshalb STRIKT ticket-gebunden sein - das ist die eine Aenderung, an der
der ganze Entwurf haengt.

Dokumentiert sind ausserdem die sieben Bauschritte in Reihenfolge, vier
Vorbedingungen (flaches Konto, RETAIL_HEDGING bestaetigt, doppeltes Risiko und
damit die Breaker-Frage, Margin-Semantik des Feldes "Einsatz je Pfad") und die
Erfolgskontrolle.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-08-19 19:54:08 +02:00
co-authored by Claude Opus 5
parent 5f4d66bcaf
commit 815b6a77b8
+125
View File
@@ -0,0 +1,125 @@
# BRK mit eigenem Positions-Slot — Entwurf
**Auftrag (User, 2026-08-19):** *„der brk trade soll komplett unabhängig von m15
oder manuellen trades laufen"*.
**Status:** Entwurf, am echten Code verifiziert. **Nicht gebaut.** Umsetzung
gehört in eine eigene Sitzung mit **flachem Konto**.
---
## Warum der naheliegende Weg falsch ist
Die erste Idee wäre, die beiden Sperren zu entfernen:
| Stelle | heutiges Verhalten |
|---|---|
| `trader.open_long/short` (Z. 320/333) | lehnt ab, wenn `self.ticket` gesetzt ist |
| `engine._manage_squeeze_pending` | storniert die Pendings, sobald **irgendeine** Position offen ist |
Das wäre an einem Abend gemacht — und **falsch**. `trader` hält EIN Ticket
(`self.ticket`), und `trailing`, Notfall-Stop, S/R-Close und Time-Stop hängen
alle daran (29 Stellen in `engine.py`). Der zweite Trade hätte nur den
Broker-SL.
⚠⚠ **Und das ist gemessen nicht tragfähig** (`backtest_brk_slonly.py`,
2026-08-19, 80k M5, 2 Halbjahre): **keine** der fünf Exit-Varianten erfüllt die
vorab fixierte Regel, alle zehn Konfidenzintervalle enthalten die Null. SL-only
sieht im ØR zwar nicht schlechter aus, aber die Trefferquote fällt **40 → 21 %**
und die KI-Breite **vervierfacht** sich — ein Varianz-Befund, kein Edge.
---
## Der Entwurf: ein ZWEITER, ticket-gebundener Trader
Der entscheidende Befund aus der Code-Sichtung: **`TrailingManager.__init__`
nimmt bereits einen Trader entgegen** (`core/trailing.py:146`, `self.trader =
trader`) und liest ausschließlich über `self.trader.snapshot()`. Es ist also
nicht an eine globale Position gebunden, sondern an *seinen* Trader.
Damit entfällt der 29-Stellen-Umbau:
```
engine.trader ─ TradeManager (wie heute) ─ trail ─ manuell + M15
engine.trader_brk ─ TradeManager (NEU) ─ trail_brk ─ nur BRK
```
**Der validierte Pfad bleibt unangetastet.** Manuelle Trades und der
Schutz-Stack laufen unverändert über `self.trader` — kein Regressionsrisiko auf
der Population, die gemessen die bessere ist (+1,56 gegen 4,71 €/Lot).
---
## ⚠⚠ Der kritische Punkt: Adoption abschalten
`TradeManager.refresh()` (`core/trader.py:511`) macht heute:
```python
on_sym = mt5.positions_get(symbol=sym) or []
all_pos = on_sym if on_sym else (mt5.positions_get() or [])
```
Es **adoptiert** also jede Position auf dem Symbol. Mit zwei Managern würden
sich beide dieselbe Position greifen und gegeneinander arbeiten — Trailing
zweimal auf demselben Ticket, oder beide auf dem falschen.
**➜ Der BRK-Manager muss STRIKT ticket-gebunden sein: `positions_get(ticket=…)`,
keine Adoption, kein Symbol-Fallback.** Das ist die eine Änderung, an der der
ganze Entwurf hängt.
Umsetzung: `TradeManager(..., nur_ticket: bool = False)`. Bei `True`:
- `refresh()` fragt ausschließlich `positions_get(ticket=self.ticket)`
- ist `self.ticket is None`, ist der Manager flat — er sucht sich **nichts**
- `_refresh_locked` adoptiert nicht per magic-match
---
## Schritte (in dieser Reihenfolge)
1. **`TradeManager` um `nur_ticket` erweitern.** Default `False` → der
bestehende Manager verhält sich **bitgenau** wie heute. Test, der das
festnagelt (Muster `tests/test_room_info.py`: alte Fassung eingefroren, über
Zufallslagen gegengerechnet).
2. **`engine.trader_brk` + `engine.trail_brk` anlegen.** Noch ohne Nutzung.
3. **BRK-Pfad umhängen:** `_manage_squeeze_pending`, `_check_pending_fill`,
`_check_auto_squeeze` benutzen `trader_brk`. Die FLAT-Bedingung wird zu
`trader_brk.ticket is None` — BRK sieht die andere Position nicht mehr.
4. **Schutz-Stack für BRK zweimal aufrufen:** `trail_brk.tick()` im `_pos_loop`,
dazu `_check_sr_close` / `_check_auto_close` / `_check_adverse15` mit dem
jeweiligen Trader parametrisieren (sie lesen heute `self.trader` fest).
5. **Snapshot:** zweites Positionsobjekt (`position_brk`) + Dashboard-Zeile.
⚠ Ohne Anzeige wäre eine offene Position unsichtbar — das ist die
Buchführungs-Lücke von Deployment-Drift **Fall 8** in neuer Form.
6. **Circuit-Breaker und Tages-P&L** müssen **beide** Positionen summieren,
sonst greift die Notbremse zu spät.
7. **Margin:** `calc_lots` rechnet auf `margin_free`. Läuft schon eine Position,
ist die frei verfügbare Margin kleiner — BRK würde automatisch kleiner
sizen. Das ist gewollt, aber **das Feld „Einsatz je Pfad" muss dann als
Anteil der GESAMT-Margin gelesen werden, nicht der freien.** Vor dem Bau
entscheiden.
---
## Was vorher geklärt sein muss
-**Konto muss FLAT sein.** Ein halb umgebauter Schutz-Stack hängt an der
falschen Position.
-**`RETAIL_HEDGING` ist bestätigt** (Broker erlaubt mehrere Positionen) —
geprüft 2026-08-19.
-**Zwei Positionen = zweimal Risiko.** Bei 40 % Einsatz je Position sind
80 % gebunden. Der Circuit-Breaker (aktuell **aus**) wäre dann kein Luxus
mehr — das gehört mitentschieden.
-**Die Squeeze-Zahlen gelten weiter nur mit dem kanonischen Exit.** Nach dem
Umbau muss `trail_brk` nachweislich laufen (Log + Snapshot), sonst ist man
ungewollt in der gemessen durchgefallenen SL-only-Variante.
---
## Erfolgskontrolle nach dem Bau
- Ein BRK-Trade läuft, während eine manuelle Position offen ist — beide mit
eigenem SL und **beide** mit aktivem Trailing (im Log sichtbar).
- `squeeze_entry_count` steigt wieder (heute: 0 bei fünf stornierten Fenstern).
- `analyze_squeeze_entry_gap.py`: der Abstand Einstieg↔Level bleibt bei ~0.
- Die B5-Zählung läuft auf einer NEU vorab fixierten Latte weiter (die alte ist
am 2026-08-17 gefallen und rechnerisch unerreichbar).