diff --git a/CLAUDE.md b/CLAUDE.md index 0aa5149..64b571d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -984,9 +984,12 @@ dort bereits nachvalidiert, ØR +0,305.) **Eine** Oberfläche: PWA-Chart. **Für das Desktop-Terminal: Datei-Bridge** — `engine._write_levels_file` (im `_run_analysis`, ~5 s, `[trading] export_mql5_levels=true`) schreibt atomar `\MQL5\Files\sr_levels.csv` (`SYM;…` / `R;preis` / `S;preis` / **`CH;; - t1;p1;t2;p2`** = Regressionskanal-Anker; Quelle **`_draw_levels`** (S/R) + - **`structure.channel_line`** (Kanal), Indikator-Farben blau DodgerBlue/DeepSkyBlue); - der Indikator **`mql5/SR_Levels.mq5`** (v1.10, in `MQL5\Indicators\`, **braucht + t1;p1;t2;p2`** = Regressionskanal-Anker / **`PT;name;dir;trigger;target;status`** = + erkanntes Chartmuster (2026-07-27, top 2 aus `patterns.snapshot`); Quelle + **`_draw_levels`** (S/R) + **`structure.channel_line`** (Kanal) + **`self.patterns`** + (Muster), Indikator-Farben blau DodgerBlue/DeepSkyBlue, Muster rot/grün); + der Indikator **`mql5/SR_Levels.mq5`** (**v1.11** — zeichnet jetzt auch die Muster: + Trigger-/Nackenlinie kräftig + gepunktete Ziel-Linie + Label; in `MQL5\Indicators\`, **braucht `OnCalculate` als No-op** sonst Compile-Error, F7-kompilieren, auf den Chart ziehen) liest die S/R-Linien per Timer (OBJ_HLINE) UND den **M30-Regressionskanal als 3 diagonale Trendlinien** (OBJ_TREND, nach rechts verlängert, oben/unten gestrichelt/ diff --git a/core/engine.py b/core/engine.py index 6c55a70..19629ed 100644 --- a/core/engine.py +++ b/core/engine.py @@ -1691,6 +1691,18 @@ class TradingEngine: lines.append(f"CH;{kind};{cl['t1']};{pts[0]};{cl['t2']};{pts[1]}") except Exception: pass + # Erkannte Chartmuster (reine Anzeige): Trigger/Nackenlinie + Ziel als + # horizontale Linien + Label. Format PT;name;dir;trigger;target;status + # (target leer = Ausbruch offen, z. B. symmetrisches Dreieck). + try: + pats = (self.patterns.snapshot() or {}).get("patterns") or [] + for m in pats[:2]: + tgt = m.get("target") + lines.append(f"PT;{m.get('name','')};{m.get('dir','')};" + f"{m.get('trigger')};{tgt if tgt is not None else ''};" + f"{m.get('status','')}") + except Exception: + pass # Zonen NICHT mehr aus der (statischen) [zones]-Config — die dynamische # Handels-Range zeichnet der Indikator selbst aus den Chart-Kerzen (TF-genau). path = os.path.join(self._mql5_files_dir, "sr_levels.csv") diff --git a/mql5/SR_Levels.mq5 b/mql5/SR_Levels.mq5 index bdc56df..5d864ee 100644 --- a/mql5/SR_Levels.mq5 +++ b/mql5/SR_Levels.mq5 @@ -12,7 +12,10 @@ //| 4) Der Bot muss laufen (schreibt die CSV alle ~5 s). | //+------------------------------------------------------------------+ #property copyright "Oil Trading Bot" -#property version "1.10" +#property version "1.11" +// v1.11: zeichnet zusätzlich erkannte Chartmuster (PT;… aus der CSV) — Trigger-/ +// Nackenlinie (rot/grün) + gepunktete Ziel-Linie + Label. Reine Anzeige. +// ⚠ nach dem Update den Indikator NEU mit F7 kompilieren. #property indicator_chart_window #property indicator_plots 0 @@ -241,6 +244,65 @@ void Redraw() } continue; } + // Chartmuster: PT;name;dir;trigger;target;status → kräftige Trigger-/Nacken- + // linie (rot=bear/grün=bull/grau=neutral) + gepunktete Ziel-Linie + Labels. + // REINE ANZEIGE (im Bot als Signal noch unbelegt). + if(typ == "PT") + { + if(k < 4) continue; + string pname = p[1]; + string pdir = p[2]; + double ptrig = StringToDouble(p[3]); + double ptgt = (k > 4 && StringLen(p[4]) > 0) ? StringToDouble(p[4]) : 0.0; + if(ptrig <= 0) continue; + color pcol = (pdir == "bull" ? clrLime : (pdir == "bear" ? clrRed : clrSilver)); + // Trigger-/Nackenlinie (WIDTH 2 → hebt sich von den dünnen S/R-Linien ab) + string nm = PFX + "PT_" + IntegerToString(idx); + if(ObjectCreate(0, nm, OBJ_HLINE, 0, 0, ptrig)) + { + ObjectSetInteger(0, nm, OBJPROP_COLOR, pcol); + ObjectSetInteger(0, nm, OBJPROP_STYLE, STYLE_SOLID); + ObjectSetInteger(0, nm, OBJPROP_WIDTH, 2); + ObjectSetInteger(0, nm, OBJPROP_BACK, true); + ObjectSetInteger(0, nm, OBJPROP_SELECTABLE, false); + } + string lbl = (ptgt > 0) + ? pname + " -> Ziel " + DoubleToString(ptgt, (int)_Digits) + : pname + " (Trigger " + DoubleToString(ptrig, (int)_Digits) + ")"; + string tn = PFX + "TPT_" + IntegerToString(idx); + if(ObjectCreate(0, tn, OBJ_TEXT, 0, CenterTime(), ptrig)) + { + ObjectSetString (0, tn, OBJPROP_TEXT, lbl); + ObjectSetInteger(0, tn, OBJPROP_COLOR, pcol); + ObjectSetInteger(0, tn, OBJPROP_FONTSIZE, 9); + ObjectSetInteger(0, tn, OBJPROP_ANCHOR, ANCHOR_LOWER); + ObjectSetInteger(0, tn, OBJPROP_SELECTABLE, false); + } + // Ziel-Linie (gepunktet) + Label, falls Ziel bekannt + if(ptgt > 0) + { + string tg = PFX + "PTG_" + IntegerToString(idx); + if(ObjectCreate(0, tg, OBJ_HLINE, 0, 0, ptgt)) + { + ObjectSetInteger(0, tg, OBJPROP_COLOR, pcol); + ObjectSetInteger(0, tg, OBJPROP_STYLE, STYLE_DOT); + ObjectSetInteger(0, tg, OBJPROP_WIDTH, 1); + ObjectSetInteger(0, tg, OBJPROP_BACK, true); + ObjectSetInteger(0, tg, OBJPROP_SELECTABLE, false); + } + string tgn = PFX + "TPTG_" + IntegerToString(idx); + if(ObjectCreate(0, tgn, OBJ_TEXT, 0, CenterTime(), ptgt)) + { + ObjectSetString (0, tgn, OBJPROP_TEXT, "Ziel " + pname); + ObjectSetInteger(0, tgn, OBJPROP_COLOR, pcol); + ObjectSetInteger(0, tgn, OBJPROP_FONTSIZE, 8); + ObjectSetInteger(0, tgn, OBJPROP_ANCHOR, ANCHOR_LOWER); + ObjectSetInteger(0, tgn, OBJPROP_SELECTABLE, false); + } + } + idx++; + continue; + } // ("Z;"-Zonen-Zeilen schreibt der Bot nicht mehr — die dynamische Handels- // Range zeichnet DrawRange() selbst aus den Chart-Kerzen.) }