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>
126 lines
5.5 KiB
Markdown
126 lines
5.5 KiB
Markdown
# 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).
|