Slot-Pruefung: close() traf nur Slot 1, squeeze_reverse den falschen

User: "ueberpruefe die Trade Logiken genau auf weitere Fehler oder Widersprueche,
besonders bezogen auf die 2 Slots". Systematisch alle `self.trader.`-Zugriffe in
engine.py durchgegangen (24 Stellen, nach Funktion gruppiert). VIER Widersprueche,
alle aus dem Umbau vom 19.08.:

① BEHOBEN - `engine.close()` schloss NUR Slot 1. Hielt der BRK-Slot eine Position
   und Slot 1 war leer, tat der CLOSE-Knopf im Dashboard NICHTS. Das ist die
   gefaehrlichste Variante der Luecke: nicht eine Zahl stimmt nicht, sondern eine
   SCHUTZHANDLUNG greift ins Leere. Jetzt ueber beide Slots, Slot 1 zuerst
   (wer CLOSE drueckt, meint meist die selbst geoeffnete Position), Fehler
   gesammelt gemeldet.

③ BEHOBEN - `squeeze_reverse` rief `self.trader.close()`, traf also die MANUELLE
   Position statt der BRK-Position, die der Reverse eigentlich drehen soll.
   Dormant (auto_squeeze_reverse=false), aber falsch verdrahtet.

② GEMELDET, NICHT geaendert - `set_sltp()` wirkt nur auf Slot 1. Die SL/TP-Felder
   der Trade-Leiste koennen eine BRK-Position nicht anpassen. Das ist eine
   UI-Frage (welches Feld gehoert zu welchem Slot?) und braucht eine Entscheidung,
   keinen stillen Fix.

④ GEMELDET - `_check_auto_m15` bindet `self.trader.open_long` VOR dem Aufruf von
   `_open`, umgeht also `_slot(source)`. Funktioniert derzeit nur, weil
   `_slot("auto_m15")` ohnehin `self.trader` liefert. Fragil: bekaeme M15 je
   einen eigenen Slot, waere es still falsch.

GEPRUEFT UND KORREKT: `_manage_squeeze_pending` (pending_orders/cancel_pending/
place_stop sind magic-basierte BROKER-Abfragen, kein Slot-Zustand),
`_broker_offset_s` (Zeitzone), `snapshot()` (position / position_brk getrennt),
Circuit-Breaker (summiert und schliesst beide).

⚠ Beim Bau eine Einrueckung zerschossen - Stufe A der Pipeline hat es sofort
gefangen (IndentationError + ty invalid-syntax + pytest). Genau dafuer ist sie da.

91 Tests gruen, Deploy verifiziert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-08-20 08:37:11 +02:00
co-authored by Claude Opus 5
parent c33227664c
commit a652223a05
+26 -2
View File
@@ -1732,7 +1732,10 @@ class TradingEngine:
pnl = ps.get("pnl")
log.info(f"🔄 AUTO-SQUEEZE-REVERSE: {pos_dir}-Position gegen {d}-Ausbruch "
f"@ {lvl} (P&L {pnl:+.2f} EUR) → sofort schließen, dann drehen")
err = self.trader.close(reason="squeeze_reverse")
# ⚠ Der Reverse gehoert zum BRK-Pfad und muss dessen Slot
# schliessen — vorher traf er Slot 1, also die MANUELLE Position.
# Dormant (`auto_squeeze_reverse=false`), aber falsch verdrahtet.
err = self.trader_brk.close(reason="squeeze_reverse")
tg = self.cfg["telegram"]
tg_on = (tg.get("enabled", "false").lower() == "true" and tg.get("bot_token"))
if err:
@@ -2856,7 +2859,28 @@ class TradingEngine:
return None
def close(self) -> str | None:
return self.trader.close(reason="manual")
"""Schliesst die offene Position — BEIDE Slots (Fix 2026-08-20).
Bis heute lief das nur auf `self.trader`. Hielt der BRK-Slot eine
Position und Slot 1 war leer, tat der CLOSE-Knopf im Dashboard NICHTS
der Nutzer konnte einen autonom eroeffneten Trade nicht von Hand
schliessen. Das ist die gefaehrlichste Variante der Slot-Luecke: nicht
eine Zahl stimmt nicht, sondern eine SCHUTZHANDLUNG greift ins Leere.
Reihenfolge bewusst Slot 1 zuerst: das ist die manuelle Position, und
wer CLOSE drueckt, meint in aller Regel die, die er selbst geoeffnet hat.
Sind beide offen, werden beide geschlossen und Fehler gesammelt gemeldet.
"""
fehler = []
for tr, name in ((self.trader, "Slot 1"), (self.trader_brk, "BRK")):
try:
if not (tr.snapshot() or {}).get("ticket"):
continue
e = tr.close(reason="manual")
if e:
fehler.append(f"{name}: {e}")
except Exception as ex:
fehler.append(f"{name}: {ex}")
return "; ".join(fehler) if fehler else None
def toggle_trail(self) -> bool:
sym = self.data.symbol