diff --git a/core/engine.py b/core/engine.py index a86e319..714c74f 100644 --- a/core/engine.py +++ b/core/engine.py @@ -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