From 204e80bb6882690d8162b0c73853b2ed910bbbbd Mon Sep 17 00:00:00 2001 From: Axel Hocks Date: Mon, 17 Aug 2026 11:00:34 +0200 Subject: [PATCH] Meldungen oben links im MT5-Chart (MS;, Indikator v1.36) User-Wunsch. Neue CSV-Zeile MS;, im Indikator als gestapelte OBJ_LABEL an CORNER_LEFT_UPPER (oben rechts sind Kurs, G/V und HL belegt). Inhalt = dieselben Zeilen wie die Dashboard-Karte "Meldungen": Squeeze, Ueberdehnung, S/R-Ziel mit P(break), Stop-Seite, News-Blackout. NUR ZUSAMMENGESETZT, NICHT NEU GERECHNET -- alles aus bereits berechneten Snapshot-Teilen bzw. _last_sr_close_hint/_last_stop_approach; calendar.blackout() ist ein reiner Speicher-Zugriff. Der Konsens-Pfeil hat im 5-s-Export-Takt einmal ein komplettes zweites _verdict() gezogen. Zwei Felder vorher geprueft statt angenommen: _last_calendar und _export_meldungen gab es NICHT -- ohne die Pruefung haette das umgebende except Exception es still verschluckt und die Meldungen waeren dauerhaft leer geblieben (dieselbe Klasse wie der wave_snap-Fallstrick vom 04.08.). ASCII-SICHER, real noetig: der erste Lauf lieferte "MS; Kompression Ausbruch steht bevor" -- Emoji und Gedankenstrich waren zu Leerzeichen geworden. Der Indikator liest die CSV nicht als UTF-8 (deshalb steht dort auch "Unterstuetzung"). Jetzt Ersetzung + Filter auf 32-126. Verifiziert: MS;Squeeze-Ausbruch LONG @ 82.413, 0 Nicht-ASCII-Zeichen. Deckel 5 Zeilen a 70 Zeichen; eigener Praefix SRB_MSG_*, damit die Labels beim Redraw verschwinden. Abschaltbar per [trading] export_meldungen=false oder InpShowMeldungen. Kompiliert ins richtige Terminal (0 errors, 0 warnings), deployt und am laufenden Server verifiziert. Co-Authored-By: Claude Opus 5 --- CLAUDE.md | 32 ++++++++++++++++++++++ core/engine.py | 66 ++++++++++++++++++++++++++++++++++++++++++++++ mql5/SR_Levels.mq5 | 43 +++++++++++++++++++++++++++++- 3 files changed, 140 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index 62d915d..9b2fb5b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6144,6 +6144,38 @@ in der Lehrbuch- noch in der umgedrehten Lesart. ⚠ Konsistent mit der Kachel-Entscheidung vom 31.07.: die Kerzen-Anatomie ist bewusst **neutral** gefärbt und nennt die gemessene statt der Lehrbuch-Lesart. +### ✅ MELDUNGEN OBEN LINKS IM MT5-CHART (2026-08-17, Indikator v1.36) + +User-Wunsch. Neue CSV-Zeile **`MS;`**, im Indikator als gestapelte +`OBJ_LABEL` an `CORNER_LEFT_UPPER` (oben rechts sind Kurs, G/V und HL). +Inhalt = dieselben Zeilen wie die Dashboard-Karte „Meldungen": Squeeze-Zustand, +Überdehnung, S/R-Ziel mit P(break), Stop-Seite, News-Blackout. + +⚠⚠ **NUR ZUSAMMENGESETZT, NICHT NEU GERECHNET.** Alles kommt aus bereits +berechneten Snapshot-Teilen bzw. `_last_sr_close_hint`/`_last_stop_approach`; +`calendar.blackout()` ist ein reiner Speicher-Zugriff. Der Konsens-Pfeil hat im +~5-s-Export-Takt einmal ein **komplettes zweites `_verdict()`** gezogen — doppelte +Last UND die Gefahr, dass Chart und Dashboard auseinanderlaufen. +✅ **Zwei Felder vorher geprüft statt angenommen:** `_last_calendar` und +`_export_meldungen` gab es **nicht** — ohne die Prüfung hätte das umgebende +`except Exception` es still verschluckt und die Meldungen wären dauerhaft leer +geblieben (dieselbe Klasse wie der `wave_snap`-Fallstrick vom 04.08.). + +⚠⚠ **ASCII-SICHER — real nötig, nicht vorsorglich.** Der erste Lauf lieferte +`MS; Kompression Ausbruch steht bevor`: Emoji und Gedankenstrich waren zu +Leerzeichen geworden. Der Indikator liest die CSV **nicht** als UTF-8 — genau +deshalb steht dort auch „Unterstuetzung" statt „Unterstützung". Jetzt werden +Umlaute/Sonderzeichen ersetzt und alles ausserhalb 32–126 entfernt. +Verifiziert: `MS;Squeeze-Ausbruch LONG @ 82.413`, **0 Nicht-ASCII-Zeichen**. + +⚠ Deckel **5 Zeilen** (der Chart soll lesbar bleiben), je 70 Zeichen; `;` im Text +wird zu `,`. Eigener Objekt-Präfix `SRB_MSG_*`, damit die Labels beim Redraw +verschwinden, wenn keine Meldung mehr ansteht (die Alt-Objekt-Falle der +HL-Pfeile). Abschaltbar: `[trading] export_meldungen=false` **oder** +`InpShowMeldungen=false`; Größe/Farbe über `InpMeldungSize`/`InpMeldungColor`. +✅ Kompiliert ins **richtige** Terminal (0 errors, 0 warnings), deployt und am +laufenden Server verifiziert. + ### ✅ S/R-AUTO-CLOSE WIEDER AN (User-Entscheidung 2026-08-11) Frage war: „sollten wir Trades bei einem S/R-Bounce automatisch schliessen?" diff --git a/core/engine.py b/core/engine.py index e911611..55b5452 100644 --- a/core/engine.py +++ b/core/engine.py @@ -490,6 +490,10 @@ class TradingEngine: self._export_mql5 = self.cfg["trading"].get("export_mql5_levels", "true").lower() == "true" # Kegel im MT5-Chart: per Default AUS, seit die Pfeile ihn ersetzen (2026-07-31). self._export_cone = self.cfg["trading"].get("export_cone", "false").lower() == "true" + # Meldungen oben links im MT5-Chart (User-Wunsch 2026-08-17) — dieselben + # Zeilen wie die Dashboard-Karte, nur zusammengesetzt, nicht neu gerechnet. + self._export_meldungen = ( + self.cfg["trading"].get("export_meldungen", "true").lower() == "true") # Konsens-Pfeil (AR;K) — Default AUS, spiegelt `InpShowConsensus=false` im # Indikator. Bei `true` wird je Export ein zweites `_verdict()` gerechnet. self._export_consensus_arrow = self.cfg["trading"].get( @@ -2801,6 +2805,68 @@ class TradingEngine: lines.append(f"PL;{_p:.2f};{_cur}") except Exception: pass + # ── MELDUNGEN oben links (MS;) — User-Wunsch 2026-08-17 ──── + # Dieselben Zeilen wie die Dashboard-Karte „Meldungen" (`#card-pos`). + # ⚠⚠ NUR ZUSAMMENSETZEN, NICHT NEU RECHNEN. Der Konsens-Pfeil hat im + # ~5-s-Export-Takt ein komplettes zweites `_verdict()` gezogen — + # doppelte Last UND die Gefahr, dass Chart und Dashboard + # auseinanderlaufen. Alles hier kommt aus bereits berechneten + # Snapshot-Teilen bzw. den `_last_*`-Feldern. + # ⚠ Abschaltbar: `[trading] export_meldungen=false`. + if self._export_meldungen: + try: + _ms: list[str] = [] + _ws2 = self.wave.snapshot() or {} + _sq2 = _ws2.get("squeeze") or {} + if _sq2.get("state") == "active" and _sq2.get("dir"): + _ms.append(f"🚀 Squeeze-Ausbruch {_sq2['dir']} " + f"@ {_sq2.get('level')}") + elif _sq2.get("state") == "armed": + _ms.append("🎯 Kompression — Ausbruch steht bevor") + _bo = _ws2.get("bounce") or {} + if _bo.get("state") in ("expected", "active") and _bo.get("dir"): + _pf = "aktiv" if _bo["state"] == "active" else "erwartet" + _ms.append(f"⚠ Ueberdehnung ({_pf}) — Reaktion " + f"{'nach oben' if _bo['dir'] == 'LONG' else 'nach unten'}" + f" moeglich [{_bo.get('tf') or ''}]") + _sh = self._last_sr_close_hint + if _sh and _sh.get("level"): + _pb2 = _sh.get("p_break") + _txt = ("unentschieden" if _pb2 is None or 45 <= _pb2 <= 55 + else f"{_pb2}% Bruch" if _pb2 > 55 + else f"{100 - _pb2}% Abprall") + _ms.append(f"S/R-Ziel {_sh['level']} · {_txt}" + + (" · Bot wuerde schliessen" if _sh.get("close") else "")) + _st2 = self._last_stop_approach + if _st2 and _st2.get("level"): + _pb3 = _st2.get("p_break") + _ms.append(f"Stop-Seite {_st2['level']} · " + + ("bricht wahrscheinlich" if (_pb3 or 0) >= 50 + else "haelt wahrscheinlich")) + # ⚠ `self.calendar` ist das Objekt (kein `_last_*`-Feld) — + # `blackout()` ist ein reiner Speicher-Zugriff, kein Netz. + _bl = self.calendar.blackout() + if _bl: + _ms.append(f"News-Blackout: {_bl.get('title') or ''}") + # ⚠⚠ ASCII-SICHER. Der Indikator liest die CSV NICHT als + # UTF-8 — Emoji und Sonderzeichen kommen als Leerzeichen an + # (real gesehen: „🎯 Kompression — …" wurde „ Kompression + # …"). Genau deshalb steht im Indikator auch + # „Unterstuetzung" statt „Unterstützung". Ersetzen statt + # hoffen. + _ers = {"—": "-", "–": "-", "·": "-", "→": "->", "≥": ">=", + "≤": "<=", "ü": "ue", "ö": "oe", "ä": "ae", + "Ü": "Ue", "Ö": "Oe", "Ä": "Ae", "ß": "ss"} + for _z in _ms[:5]: # Deckel: der Chart soll lesbar bleiben + _t = str(_z) + for _a, _b in _ers.items(): + _t = _t.replace(_a, _b) + _t = "".join(c for c in _t if 32 <= ord(c) < 127) + _t = " ".join(_t.split()) # Mehrfach-Leerzeichen weg + if _t: + lines.append("MS;" + _t.replace(";", ",")[:70]) + except Exception: + pass # Trade-Marker: TR;; → der Indikator umrandet die Kerze, # in der eröffnet (hellgrün) bzw. geschlossen (dunkelgrün) wurde # (User-Vorgabe 2026-07-30). Offene Position + die letzten Trades des Tages. diff --git a/mql5/SR_Levels.mq5 b/mql5/SR_Levels.mq5 index 851998b..359c154 100644 --- a/mql5/SR_Levels.mq5 +++ b/mql5/SR_Levels.mq5 @@ -12,7 +12,13 @@ //| 4) Der Bot muss laufen (schreibt die CSV alle ~5 s). | //+------------------------------------------------------------------+ #property copyright "Oil Trading Bot" -#property version "1.35" +#property version "1.36" +// v1.36 (2026-08-17): MELDUNGEN oben links (MS;) — dieselben Zeilen wie +// die Dashboard-Karte "Meldungen" (Squeeze, Ueberdehnung, S/R-Ziel, +// Stop-Seite, News-Blackout). Der Bot setzt sie nur ZUSAMMEN aus bereits +// berechneten Snapshot-Teilen, er rechnet nichts neu -- die Lehre aus dem +// Konsens-Pfeil, der im 5-s-Takt ein zweites _verdict() zog. +// Abschaltbar per InpShowMeldungen oder [trading] export_meldungen=false. // v1.35 (2026-08-13): S/R-LABEL WORTGLEICH ZUR M15-KARTE (User: „die Beschriftung // fuer S/R im Chart stimmt nicht mit der Analyse in der M15-Karte ueberein"). // Das Label trug seit v1.27 die NACKTE Zahl = P(Durchbruch); die Karte klappt @@ -218,6 +224,12 @@ input color InpThemeText = C'139,148,158'; // Achsen/Text input color InpThemeBidLine = clrWhite; // aktuelle Kurslinie (Bid) — weiss input double InpShiftPct = 12.0; // Platz rechts fuer Pfeile/Labels (% der Chartbreite) input bool InpShowTradeLevels = true; // MT5-Positionslinien+Labels (stehen immer LINKS) +// Meldungen oben links (User-Wunsch 2026-08-17) — dieselben Zeilen wie die +// Dashboard-Karte „Meldungen". Der Bot deckelt auf 5; abschaltbar per ini +// (`[trading] export_meldungen=false`) ODER hier. +input bool InpShowMeldungen = true; // Meldungen oben links einblenden +input int InpMeldungSize = 10; // Schriftgroesse der Meldungen +input color InpMeldungColor = clrGainsboro; // Farbe der Meldungen const string PFX = "SRB_"; // Präfix S/R-Linien (aus Datei) const string RPFX = "SRR_"; // Präfix dynamische Range (aus Chart) @@ -450,6 +462,7 @@ void Redraw() string rows[]; int nr = StringSplit(content, '\n', rows); int idx = 0; + int msg_idx = 0; // Meldungs-Stapel oben links // Kegel-Verkettung je Redraw zuruecksetzen (sonst haengt der Faecher am Stand // des vorherigen Durchlaufs) g_coneT = 0; g_coneLo = 0.0; g_coneHi = 0.0; g_conePx = 0.0; @@ -886,6 +899,34 @@ void Redraw() ObjectSetInteger(0, pn, OBJPROP_COLOR, InpPriceColor); continue; } + // MELDUNGEN oben LINKS (MS;) — User-Wunsch 2026-08-17. + // Dieselben Zeilen wie die Dashboard-Karte „Meldungen"; der Bot setzt sie + // zusammen und deckelt auf 5. Hier nur gestapelt darstellen. + // ⚠ Eigener Praefix MSPFX, damit sie beim Redraw sauber verschwinden, wenn + // der Bot keine MS-Zeile mehr schickt (sonst blieben Alt-Meldungen + // stehen — genau der Fehler, den die HL-Pfeile schon einmal hatten). + if(typ == "MS") + { + if(!InpShowMeldungen || k < 2) continue; + string mn = PFX + "MSG_" + IntegerToString(msg_idx); + if(ObjectFind(0, mn) < 0) + { + ObjectCreate(0, mn, OBJ_LABEL, 0, 0, 0); + ObjectSetInteger(0, mn, OBJPROP_CORNER, CORNER_LEFT_UPPER); + ObjectSetInteger(0, mn, OBJPROP_XDISTANCE, 12); + ObjectSetInteger(0, mn, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER); + ObjectSetString (0, mn, OBJPROP_FONT, "Arial"); + ObjectSetInteger(0, mn, OBJPROP_FONTSIZE, InpMeldungSize); + ObjectSetInteger(0, mn, OBJPROP_SELECTABLE, false); + ObjectSetInteger(0, mn, OBJPROP_BACK, false); + } + ObjectSetInteger(0, mn, OBJPROP_YDISTANCE, + 16 + msg_idx * (InpMeldungSize + 6)); + ObjectSetString (0, mn, OBJPROP_TEXT, p[1]); + ObjectSetInteger(0, mn, OBJPROP_COLOR, InpMeldungColor); + msg_idx++; + continue; + } // G/V der offenen Position — direkt UNTER dem Kurs (User-Wunsch 2026-07-30): // PL;wert;waehrung. Wert ist NETTO (Bot rechnet die WHT-Quellensteuer schon // raus, wie im Dashboard). Gruen im Plus, rot im Minus. Ohne offene Position