Telegram: ALLE Trade-Opens und -Closes + Reichweiten-Waechter fuer den 2. Slot
(1) User-Vorgabe: "Alle Trade Closes und Opens sollen per Telegram gemeldet werden". - close_notify_min_eur 50 -> 0, also jeder Close ohne Schwelle (Backup oil_widget_config.ini.bak-2026-08-19-tgopen) - neuer _check_open_notify: meldet jede Eroeffnung, ueber BEIDE Slots. Der BRK-Slot ist ausdruecklich dabei - ein autonomer Entry soll nicht unbemerkt bleiben, genau dafuer wurde der zweite Slot gebaut; die Meldung nennt den Slot mit. - _TG_ERLAUBT um "Trade eroeffnet" erweitert (das Gate ist EINE Filterstelle, nicht 17 Einzeleingriffe). ⚠ 1x je Ticket ueber _open_notify_gemeldet - ohne den Merker feuerte es im 1-s-Takt weiter, solange die Position offen ist. ⚠ In der Startup-Schonfrist wird nur GEMERKT, nicht gemeldet: nach einem Neustart erkennt der Trader eine BESTEHENDE Position wieder, und das ist keine Eroeffnung. (2) Reichweiten-Waechter (_check_slot_reichweite). Gemessener Befund: von den Schutz-Checks ist NUR _check_circuit_breaker slot-faehig. _check_auto_close (Notfall-Stop, haengt an 4 Ticket-Variablen), _check_sr_close, _check_adverse15 und _check_flip_close kennen nur Slot 1. Heute folgenlos, weil alle vier AUS sind - aber wird einer eingeschaltet, waehrend eine BRK-Position laeuft, gilt er stillschweigend nur fuer Slot 1, und im Dashboard saehe alles normal aus. Dieselbe Klasse wie Deployment-Drift Fall 8: nicht die Strategie driftet, sondern ihre REICHWEITE. Der Waechter macht das Loch LAUT (Log-Warnung 1x je Ticket + Snapshot-Feld `slot_luecke`), bis die vier slot-faehig sind. ⚠ Die volle Parametrisierung der vier Checks steht AUS. _check_auto_close allein haengt an vier Ticket-Variablen und ist der Notfall-Stop - das gehoert in eine eigene Sitzung mit Tests, nicht ans Ende einer langen. ⚠ EIGENER FEHLER auf dem Weg: der erste Bauversuch lief per Heredoc und riss das Telegram-Format-Literal an einem \n auseinander (SyntaxError). Das ist exakt die im Projekt dokumentierte \n-Falle - "mehrzeilige Strings mit \n NIE per Heredoc schreiben, den Edit-Weg nehmen". Ich habe die eigene Regel verletzt; engine.py wurde per git checkout zurueckgesetzt und sauber ueber Edit neu gebaut. Deploy ueber tools/deploy.py --feld position_brk, alle 5 Schritte. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
0fe51dea48
commit
f02fd43b39
+84
-1
@@ -183,7 +183,9 @@ def _p_break(mom6: float, mom3: float, wt: float, dist: float) -> float:
|
|||||||
# EINE AUSNAHME mit Bypass: "<ok_word> FEHLGESCHLAGEN" beim Notfall-/
|
# EINE AUSNAHME mit Bypass: "<ok_word> FEHLGESCHLAGEN" beim Notfall-/
|
||||||
# Gewinn-Close. Dort ist die Position NICHT zu und es braucht eine
|
# Gewinn-Close. Dort ist die Position NICHT zu und es braucht eine
|
||||||
# Handeingabe -- Stille genau dort waere die gefaehrlichste Variante.
|
# Handeingabe -- Stille genau dort waere die gefaehrlichste Variante.
|
||||||
_TG_ERLAUBT = ("Trade geschlossen",)
|
# ⚠ User-Vorgabe 2026-08-19: ALLE Trade-Closes UND -Opens melden.
|
||||||
|
# `close_notify_min_eur` steht dafür auf 0 (= jeder Close, keine Schwelle).
|
||||||
|
_TG_ERLAUBT = ("Trade geschlossen", "Trade eroeffnet")
|
||||||
|
|
||||||
|
|
||||||
def send_telegram(text, *a, **kw):
|
def send_telegram(text, *a, **kw):
|
||||||
@@ -862,6 +864,8 @@ class TradingEngine:
|
|||||||
# ⚠ NACH `_check_auto_close`: erst dort wird der Flat-Übergang
|
# ⚠ NACH `_check_auto_close`: erst dort wird der Flat-Übergang
|
||||||
# erkannt und die Benachrichtigung vorgemerkt.
|
# erkannt und die Benachrichtigung vorgemerkt.
|
||||||
self._check_close_notify() # Telegram bei jedem Close ab Schwelle
|
self._check_close_notify() # Telegram bei jedem Close ab Schwelle
|
||||||
|
self._check_open_notify() # Telegram bei jeder Eröffnung
|
||||||
|
self._check_slot_reichweite() # meldet ungedeckte 2. Position
|
||||||
self._check_adverse15() # 15-Min-Regel (nur Bot-Trades)
|
self._check_adverse15() # 15-Min-Regel (nur Bot-Trades)
|
||||||
self._check_flip_close() # Empfehlung dreht → schließen
|
self._check_flip_close() # Empfehlung dreht → schließen
|
||||||
self._check_sr_close()
|
self._check_sr_close()
|
||||||
@@ -945,6 +949,85 @@ class TradingEngine:
|
|||||||
return False
|
return False
|
||||||
return self._circuit_tripped_date == datetime.now(_BERLIN).date()
|
return self._circuit_tripped_date == datetime.now(_BERLIN).date()
|
||||||
|
|
||||||
|
def _check_open_notify(self):
|
||||||
|
"""Telegram bei JEDER Eröffnung — beide Slots (User-Vorgabe 2026-08-19).
|
||||||
|
|
||||||
|
⚠ Bewusst über BEIDE Trader: ein autonomer BRK-Entry soll nicht
|
||||||
|
unbemerkt bleiben — genau der Fall, für den der zweite Slot gebaut
|
||||||
|
wurde. Die Meldung nennt deshalb den Slot mit.
|
||||||
|
⚠ 1× je Ticket (`_open_notify_gemeldet`); ohne den Merker feuerte sie im
|
||||||
|
1-s-Takt weiter, solange die Position offen ist.
|
||||||
|
⚠ In der Startup-Schonfrist wird nur GEMERKT, nicht gemeldet: nach einem
|
||||||
|
Neustart erkennt der Trader eine BESTEHENDE Position wieder, und das ist
|
||||||
|
keine Eröffnung.
|
||||||
|
"""
|
||||||
|
if not hasattr(self, "_open_notify_gemeldet"):
|
||||||
|
self._open_notify_gemeldet = set()
|
||||||
|
for tr, quelle in ((self.trader, "Slot 1"), (self.trader_brk, "BRK")):
|
||||||
|
try:
|
||||||
|
ps = tr.snapshot() or {}
|
||||||
|
tk = ps.get("ticket")
|
||||||
|
if not tk or tk in self._open_notify_gemeldet:
|
||||||
|
continue
|
||||||
|
self._open_notify_gemeldet.add(tk)
|
||||||
|
if self._in_startup_grace():
|
||||||
|
continue
|
||||||
|
lg = ps.get("order_type") == 0
|
||||||
|
zeilen = [
|
||||||
|
f"📈 <b>Trade eroeffnet</b> ({quelle})",
|
||||||
|
f"{self.data.symbol or '?'} "
|
||||||
|
f"{'▲ LONG' if lg else '▼ SHORT'} "
|
||||||
|
f"{ps.get('lots')} Lots @ {ps.get('entry_price')}",
|
||||||
|
f"SL {ps.get('sl') or '—'} · TP {ps.get('tp') or '—'}",
|
||||||
|
]
|
||||||
|
send_telegram("\n".join(zeilen))
|
||||||
|
except Exception as e:
|
||||||
|
log.debug(f"_check_open_notify: {e}")
|
||||||
|
if len(self._open_notify_gemeldet) > 200:
|
||||||
|
self._open_notify_gemeldet = set(list(self._open_notify_gemeldet)[-50:])
|
||||||
|
|
||||||
|
# ⚠⚠ REICHWEITEN-WÄCHTER (2026-08-19). Vier Schutz-Checks kennen bislang NUR
|
||||||
|
# den ersten Slot: `_check_auto_close` (Notfall-Stop, hängt an 4
|
||||||
|
# Ticket-Variablen), `_check_sr_close`, `_check_adverse15`,
|
||||||
|
# `_check_flip_close`. Solange sie AUS sind, ist das folgenlos — der
|
||||||
|
# BRK-Slot hat Broker-SL, `trail_brk` und den Circuit-Breaker.
|
||||||
|
# ⚠ Wird einer davon wieder eingeschaltet, WÄHREND eine BRK-Position
|
||||||
|
# läuft, gilt er stillschweigend nur für Slot 1: die zweite Position liefe
|
||||||
|
# ohne ihn, und im Dashboard sähe alles normal aus. Dieselbe Klasse wie
|
||||||
|
# Deployment-Drift Fall 8 — nicht die Strategie driftet, sondern ihre
|
||||||
|
# REICHWEITE. Bis die vier slot-fähig sind, macht dieser Wächter das Loch
|
||||||
|
# LAUT statt still (1× je Ticket, kein Dauerlärm).
|
||||||
|
def _check_slot_reichweite(self):
|
||||||
|
try:
|
||||||
|
tk = self.trader_brk.ticket
|
||||||
|
if not tk:
|
||||||
|
self._reichweite_gemeldet = None
|
||||||
|
return None
|
||||||
|
offen = []
|
||||||
|
if ((getattr(self, "_emergency_margin_pct", 0) or 0) > 0
|
||||||
|
or (getattr(self, "_emergency_pct", 0) or 0) > 0
|
||||||
|
or (getattr(self, "_emergency_remember", 0) or 0) > 0):
|
||||||
|
offen.append("Notfall-Stop")
|
||||||
|
if getattr(self, "_auto_sr_close", False):
|
||||||
|
offen.append("S/R-Close")
|
||||||
|
if (getattr(self, "_adverse15_atr", 0) or 0) > 0:
|
||||||
|
offen.append("15-Min-Regel")
|
||||||
|
if getattr(self, "_flip_close", False):
|
||||||
|
offen.append("Flip-Close")
|
||||||
|
if not offen:
|
||||||
|
self._reichweite_gemeldet = None
|
||||||
|
return None
|
||||||
|
if getattr(self, "_reichweite_gemeldet", None) != tk:
|
||||||
|
self._reichweite_gemeldet = tk
|
||||||
|
log.warning("⚠ REICHWEITE: %s aktiv, gilt aber NUR für Slot 1 — "
|
||||||
|
"die BRK-Position T=%s läuft ohne (Broker-SL, "
|
||||||
|
"Trailing und Circuit-Breaker greifen weiter).",
|
||||||
|
", ".join(offen), tk)
|
||||||
|
return offen
|
||||||
|
except Exception as e:
|
||||||
|
log.debug(f"_check_slot_reichweite: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
def _check_circuit_breaker(self):
|
def _check_circuit_breaker(self):
|
||||||
"""Tagesverlust-Stopp (User-Vorgabe 2026-07-27): erreicht der Tages-P&L
|
"""Tagesverlust-Stopp (User-Vorgabe 2026-07-27): erreicht der Tages-P&L
|
||||||
(realisiert heute + offene Position) −`daily_loss_limit_pct`% der Balance,
|
(realisiert heute + offene Position) −`daily_loss_limit_pct`% der Balance,
|
||||||
|
|||||||
Reference in New Issue
Block a user