From ca61cf14983ae9f89803a27d5b27c836f11b0968 Mon Sep 17 00:00:00 2001 From: Axel Hocks Date: Mon, 17 Aug 2026 18:27:26 +0200 Subject: [PATCH] S/R als ZONE statt Linie (RZ/SZ, Indikator v1.37) User-Wunsch nach einem TradingView-Bild: Resistance Zone und eine untere Zone als farbige Baender. Neu RZ;lo;hi und SZ;lo;hi, im Indikator als OBJ_RECTANGLE mit Beschriftung, nach rechts verlaengert. DIE BREITE IST ECHT: sie ist die Spanne der M30-Pivots, die den Cluster gebildet haben (sr_levels.zonen(), additiv -- cluster() bleibt unveraendert, weil es den S/R-Auto-Close speist). Live verifiziert: R;82.786 liegt in RZ;82.776;82.797, S;82.15 in SZ;82.14;82.16. Einzel-Pivot bekommt 0,10xATR Mindestbreite. ZWEI ABWEICHUNGEN VOM VORBILD, beide begruendet: (1) KEIN Fibonacci. Das Bild leitet seine Zone aus 0,618/0,658 ab. Fib ist hier gemessen und verworfen (04.08.): 54,3/54,5 % Haltequote gegen 55,7/53,8 % einer Zufallslinie gleicher Distanz, und schlechter als M30-Pivots. (2) Die untere Zone heisst SUPPORT, nicht "Cumulative Long Liquidation". Echte Liquidationsdaten hat das Projekt nicht; die HL-Waende sind am 17.08. als reaktiv gemessen. Bricht die Support-Zone, liegen dort die Long-Stops -- dieselbe Stelle, ehrlich benannt. Abschaltbar InpShowZonen. Kompiliert ins richtige Terminal (0/0), deployt, verifiziert. Co-Authored-By: Claude Opus 5 --- CLAUDE.md | 28 ++++++++++++++++++++++++ core/engine.py | 40 ++++++++++++++++++++++++++++++++++ core/sr_levels.py | 21 ++++++++++++++++++ mql5/SR_Levels.mq5 | 53 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 141 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index 4b959a0..f789892 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6225,6 +6225,34 @@ Nachjagd-Bremse); vorher lag der Live-Median bei +0,275×ATR. Der Umbau hat also gewirkt — nur die formale Fälligkeit ist unerreichbar, solange der Trader aus ist. **Sie hängt an derselben Entscheidung wie B5, nicht an weiteren Daten.** +### ✅ S/R ALS ZONE STATT LINIE (2026-08-17, Indikator v1.37) + +User-Wunsch nach einem TradingView-Bild: Resistance Zone und eine untere Zone +als farbige Bänder. Neu: `RZ;lo;hi` (Widerstand) und `SZ;lo;hi` (Support), +im Indikator als `OBJ_RECTANGLE` mit Beschriftung, nach rechts verlängert. + +⚠⚠ **DIE BREITE IST ECHT, NICHT ERFUNDEN.** Sie ist die Spanne der M30-Pivots, +die den Cluster gebildet haben (`sr_levels.zonen()`, additiv — `cluster()` +bleibt unverändert, weil es den S/R-Auto-Close speist). Live verifiziert: +`R;82.786` liegt in `RZ;82.776;82.797`, `S;82.15` in `SZ;82.14;82.16`. +⚠ Ein Cluster aus EINEM Pivot hätte Breite 0 → Mindestbreite 0,10×ATR, damit +das Band sichtbar bleibt. + +⚠⚠ **ZWEI ABWEICHUNGEN VOM VORBILD, beide begründet:** +**(1) KEIN Fibonacci.** Das Bild leitet seine Zone aus 0,618/0,658 ab. Fib ist +hier gemessen und **verworfen** (04.08.): die Level halten mit 54,3/54,5 % +**nicht besser** als eine Zufallslinie gleicher Distanz (55,7/53,8 %) — und +schlechter als M30-Pivots (56,6/55,4 %). Eine Fib-Zone wäre eine hübsche Linie +ohne Beleg; die Pivot-Zone ist dieselbe Optik mit Substanz. +**(2) Die untere Zone heißt SUPPORT, nicht „Cumulative Long Liquidation".** +Echte Liquidationsdaten hat das Projekt **nicht** — was es gibt, sind die +HL-Liquiditätswände (`LQ;`, echte ruhende Orders, bereits als Pfeile gezeichnet), +und die sind am 17.08. als **reaktiv** gemessen. Bricht die Support-Zone, liegen +dort die Long-Stops — dieselbe Stelle, aber ehrlich benannt. + +Abschaltbar `InpShowZonen=false`; Farben `InpZoneResColor`/`InpZoneSupColor`. +Kompiliert ins richtige Terminal (0 errors, 0 warnings), deployt und 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 55b5452..27f0569 100644 --- a/core/engine.py +++ b/core/engine.py @@ -2805,6 +2805,46 @@ class TradingEngine: lines.append(f"PL;{_p:.2f};{_cur}") except Exception: pass + # ── ZONEN statt nackter Linien (User-Wunsch 2026-08-17, nach einem + # TradingView-Bild): RZ;lo;hi = Widerstands-Zone · SZ;lo;hi = + # Support-Zone. Der Indikator zeichnet sie als farbiges Band. + # ⚠⚠ DIE BREITE IST ECHT, NICHT ERFUNDEN: sie ist die Spanne der + # M30-Pivots, die den Cluster gebildet haben (`sr_levels.zonen`). + # Das Vorbild-Bild leitet seine Zone aus **Fibonacci** ab (0,618/ + # 0,658) — Fib ist hier gemessen und VERWORFEN: die Level halten + # nicht besser als eine Zufallslinie gleicher Distanz (04.08., + # Haltequote 54,3/54,5 % gegen 55,7/53,8 % Zufall). Eine + # Fib-Zone waere also eine huebsche Linie ohne Beleg. + # ⚠ Ein Cluster aus EINEM Pivot hat Breite 0 — dann bekommt er eine + # Mindestbreite von 0,10xATR, damit das Band sichtbar bleibt. + # ⚠ Die untere Zone heisst SUPPORT, nicht „Long Liquidation": echte + # Liquidations-Daten hat das Projekt nicht. Bricht sie, liegen dort + # die Long-Stops — das ist dieselbe Stelle, aber ehrlich benannt. + try: + _zl = self._draw_levels() or {} + _r0 = (_zl.get("res") or [None])[0] + _s0 = (_zl.get("sup") or [None])[0] + _ws3 = self.wave.snapshot() or {} + _a3 = (_ws3.get("pb_feats") or {}).get("atr") or 0.2 + _lv3 = _ws3.get("pb_levels30") or _ws3.get("pb_levels") or {} + from core.sr_levels import zonen as _zonen_lv + _mind = 0.10 * _a3 + for _px, _seite, _tag in ((_r0, "ph", "RZ"), (_s0, "pl", "SZ")): + if _px is None: + continue + _tr = None + for _m, _lo2, _hi2 in _zonen_lv(_lv3.get(_seite) or [], _a3): + if abs(_m - _px) < 0.0015: + _tr = (_lo2, _hi2); break + if _tr is None: + _tr = (_px, _px) + _lo2, _hi2 = _tr + if _hi2 - _lo2 < _mind: # Einzel-Pivot sichtbar machen + _mit = (_lo2 + _hi2) / 2.0 + _lo2, _hi2 = _mit - _mind / 2, _mit + _mind / 2 + lines.append(f"{_tag};{round(_lo2, 3)};{round(_hi2, 3)}") + 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 diff --git a/core/sr_levels.py b/core/sr_levels.py index 0bf5ef0..efb7835 100644 --- a/core/sr_levels.py +++ b/core/sr_levels.py @@ -89,3 +89,24 @@ def halten(neu, alt, px: float, atr: float, is_res: bool, and abs(neu - px) < abs(alt - px) - naeher * atr): return neu # alte Linie veraltet/weit weg → näheres Level return alt # sonst: HALTEN (kein Springen) + + +def zonen(vals, atr: float, toleranz: float = TOLERANZ_STD) -> list: + """Wie `cluster`, gibt aber je Cluster (mittel, lo, hi) statt nur den Mittelwert. + + ⚠⚠ ADDITIV — `cluster()` bleibt unveraendert. Es speist `_draw_levels` und + damit den S/R-Auto-Close; jede Aenderung dort waere ein Strategie-Eingriff. + Hier geht es nur um die ANZEIGE: eine Zone hat eine Breite, eine Linie nicht. + + Die Breite ist NICHT erfunden — sie ist die Spanne der Pivots, die den + Cluster gebildet haben. Ein Cluster aus einem einzigen Pivot hat folglich + die Breite 0; der Aufrufer entscheidet, ob er ihm eine Mindestbreite gibt. + """ + out: list[list[float]] = [] + for v in sorted(vals): + if out and v - out[-1][-1] <= toleranz * atr: + out[-1].append(v) + else: + out.append([v]) + return [(round(sum(g) / len(g), 3), round(min(g), 3), round(max(g), 3)) + for g in out] diff --git a/mql5/SR_Levels.mq5 b/mql5/SR_Levels.mq5 index 359c154..e335922 100644 --- a/mql5/SR_Levels.mq5 +++ b/mql5/SR_Levels.mq5 @@ -12,7 +12,12 @@ //| 4) Der Bot muss laufen (schreibt die CSV alle ~5 s). | //+------------------------------------------------------------------+ #property copyright "Oil Trading Bot" -#property version "1.36" +#property version "1.37" +// v1.37 (2026-08-17): ZONEN (RZ/SZ) — S/R zusaetzlich als farbiges Band, wie im +// TradingView-Vorbild des Users. Die Breite ist die echte Spanne der +// M30-Pivots im Cluster; die Vorlage leitet ihre Zone aus Fibonacci ab, +// das ist hier gemessen und verworfen. Untere Zone heisst SUPPORT, nicht +// "Long Liquidation" -- echte Liquidationsdaten hat das Projekt nicht. // 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 @@ -230,6 +235,12 @@ input bool InpShowTradeLevels = true; // MT5-Positionslinien+Labels (st input bool InpShowMeldungen = true; // Meldungen oben links einblenden input int InpMeldungSize = 10; // Schriftgroesse der Meldungen input color InpMeldungColor = clrGainsboro; // Farbe der Meldungen +// Zonen statt nackter Linien (User-Wunsch 2026-08-17). Die BREITE ist die echte +// Spanne der Pivots im Cluster — NICHT Fibonacci (im Projekt gemessen und +// verworfen: haelt nicht besser als eine Zufallslinie gleicher Distanz). +input bool InpShowZonen = true; // S/R als ZONE (Band) zeichnen +input color InpZoneResColor = C'60,25,30'; // Widerstands-Zone (dunkelrot) +input color InpZoneSupColor = C'20,45,35'; // Support-Zone (dunkelgruen) const string PFX = "SRB_"; // Präfix S/R-Linien (aus Datei) const string RPFX = "SRR_"; // Präfix dynamische Range (aus Chart) @@ -899,6 +910,46 @@ void Redraw() ObjectSetInteger(0, pn, OBJPROP_COLOR, InpPriceColor); continue; } + // ZONEN (RZ;lo;hi = Widerstand · SZ;lo;hi = Support) — User-Wunsch + // 2026-08-17 nach einem TradingView-Bild. Farbiges Band statt nackter + // Linie; die BREITE ist die echte Spanne der Pivots, die den Cluster + // gebildet haben (nicht Fibonacci — das ist im Projekt gemessen und + // verworfen). Nach rechts verlaengert, damit es wie im Vorbild wirkt. + if(typ == "RZ" || typ == "SZ") + { + if(!InpShowZonen || k < 3) continue; + double zlo = StringToDouble(p[1]), zhi = StringToDouble(p[2]); + if(zlo <= 0 || zhi <= 0) continue; + string zn = PFX + "ZONE_" + typ; + color zc = (typ == "RZ" ? InpZoneResColor : InpZoneSupColor); + datetime t1 = iTime(_Symbol, PERIOD_CURRENT, MathMin(60, Bars(_Symbol, PERIOD_CURRENT) - 1)); + if(ObjectFind(0, zn) < 0) + { + ObjectCreate(0, zn, OBJ_RECTANGLE, 0, t1, zlo, RightTime(), zhi); + ObjectSetInteger(0, zn, OBJPROP_FILL, true); + ObjectSetInteger(0, zn, OBJPROP_BACK, true); + ObjectSetInteger(0, zn, OBJPROP_SELECTABLE, false); + } + ObjectSetInteger(0, zn, OBJPROP_COLOR, zc); + ObjectMove(0, zn, 0, t1, zlo); + ObjectMove(0, zn, 1, RightTime(), zhi); + // Beschriftung an der Oberkante, rechtsbuendig wie die S/R-Labels + string zt = PFX + "TZONE_" + typ; + if(ObjectFind(0, zt) < 0) + { + ObjectCreate(0, zt, OBJ_TEXT, 0, RightTime(), zhi); + ObjectSetInteger(0, zt, OBJPROP_ANCHOR, ANCHOR_RIGHT_LOWER); + ObjectSetInteger(0, zt, OBJPROP_FONTSIZE, InpLabelSize); + ObjectSetInteger(0, zt, OBJPROP_SELECTABLE, false); + } + ObjectSetString (0, zt, OBJPROP_TEXT, + (typ == "RZ" ? "Resistance Zone " : "Support Zone ") + + DoubleToString(zlo, (int)_Digits) + " - " + + DoubleToString(zhi, (int)_Digits)); + ObjectSetInteger(0, zt, OBJPROP_COLOR, zc); + ObjectMove(0, zt, 0, RightTime(), zhi); + 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.