Circuit-Breaker und Tages-P&L summieren jetzt BEIDE Positions-Slots

Letzte offene Luecke des Zwei-Slot-Umbaus (User: "ja").

WARUM ES ZWINGEND IST: nach dem Umbau kann BRK parallel zu einer manuellen oder
M15-Position laufen. Haette der Tages-P&L weiter nur den ersten Slot gesehen,
waere eine offene BRK-Position unsichtbar geblieben - der Breaker griffe also
genau dann zu spaet, wenn zwei Positionen gleichzeitig laufen und das Risiko
doppelt ist. Bei 40 % Einsatz je Position sind 80 % der Margin gebunden.

GEAENDERT:
- snapshot(): day_pl["open"] summiert beide Slots
- _check_circuit_breaker(): dieselbe Summe als Ausloeser
- und der Breaker schliesst jetzt BEIDE Positionen - eine Notbremse, die nur
  die Haelfte schliesst, ist keine. Fehlschlag am zweiten Slot wird geloggt,
  nicht verschluckt.

91 Tests gruen, Deploy ueber tools/deploy.py --feld position_brk.

⚠ NEBENBEFUND beim Verifizieren, NICHT von dieser Aenderung verursacht: der
Circuit-Breaker steht auf 8 % (runtime_state cb_limit_pct = 8.0) und hat heute
dreimal ausgeloest (19:17, 20:03, 20:07). Der Tages-P&L liegt bei -178,89 EUR
gegen ein Limit von -55,89 EUR. Damit sind fuer heute KEINE autonomen Trades mehr
moeglich - auch BRK nicht. Manuelle Orders bleiben frei (so gebaut).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-08-19 20:10:31 +02:00
co-authored by Claude Opus 5
parent f04ae4d9d9
commit a9a6c487d2
+21 -1
View File
@@ -964,7 +964,9 @@ class TradingEngine:
if bal <= 0:
return
ps = self.trader.snapshot()
open_pnl = float(ps.get("pnl") or 0.0)
# ⚠ BEIDE Slots — s. Begruendung im Snapshot-Block.
ps_brk = self.trader_brk.snapshot() or {}
open_pnl = float(ps.get("pnl") or 0.0) + float(ps_brk.get("pnl") or 0.0)
day_total = self._day_realized_cached() + open_pnl
limit_eur = self._cb_limit_pct / 100.0 * bal
if day_total > -limit_eur:
@@ -978,6 +980,15 @@ class TradingEngine:
tg_on = (tg.get("enabled", "false").lower() == "true" and tg.get("bot_token"))
if ps.get("ticket"):
err = self.trader.close(reason="circuit_breaker")
# ⚠ Der zweite Slot MUSS mit — eine Notbremse, die nur die Haelfte
# schliesst, ist keine.
if ps_brk.get("ticket"):
try:
e2 = self.trader_brk.close(reason="circuit_breaker")
if e2:
log.warning(f"Circuit-Breaker: BRK-Slot nicht geschlossen — {e2}")
except Exception as ce:
log.warning(f"Circuit-Breaker BRK-Close: {ce}")
if err:
log.error(f"Circuit-Breaker-Close fehlgeschlagen: {err}")
if tg_on:
@@ -4381,7 +4392,16 @@ class TradingEngine:
.get("total_pnl") or 0.0)
except Exception as e:
log.warning(f"day stats: {e}"); day_realized = 0.0
# ⚠⚠ BEIDE Slots summieren (Zwei-Slot-Umbau 2026-08-19). Wuerde hier
# nur der erste stehen, saehe der Tages-P&L eine offene BRK-Position
# nicht — und der Circuit-Breaker griffe zu spaet, also genau dann
# nicht, wenn zwei Positionen gleichzeitig laufen und das Risiko
# doppelt ist.
open_pnl = float(position.get("pnl") or 0.0)
try:
open_pnl += float((self.trader_brk.snapshot() or {}).get("pnl") or 0.0)
except Exception:
pass
day_pl = {"realized": round(day_realized, 2), "open": round(open_pnl, 2),
"total": round(day_realized + open_pnl, 2)}
# Circuit Breaker — Status für die UI (Tagesverlust-Stopp)