MQL5 v1.29: Konsolidierungs-Box als Anzeige (CO;lo;hi;tight)

User: "schauen wir uns das mal an" (nach dem verworfenen Konsolidierungs-Backtest).

Der Bot exportiert die Spanne der letzten 10 M5-Bars -- exakt die Box, aus der der
validierte Squeeze-Ausbruch kommt (wave._squeeze_one liefert jetzt box_hi/box_lo in
allen Rueckgaben). Der Indikator zeichnet sie als transparentes blaues Rechteck;
ist sie KOMPRIMIERT (<=2.5xATR, also armed/active), wird sie mit doppelter Deckkraft
gezeichnet -> "Ausbruch steht bevor" ist auf einen Blick sichtbar.

Schalter: InpShowConsol / InpConsolColor / InpConsolAlpha / InpConsolBars.

⚠ REINE ANZEIGE. Alle Konsolidierungs-SETUPS sind gemessen verworfen
(backtest_consolidation.py: False Breakout, Distribution, Accumulation, Retest --
inkl. Kontrolltest, der die Distribution-Hypothese kippte). Die Box zeigt WO
gestaut wird, nicht WOHIN es geht. Validiert ist ausschliesslich der Ausbruch.

Verifiziert: CO;84.105;84.815;0 (0.710$ = 2.68xATR = knapp ueber der Schwelle,
daher korrekt als "nicht komprimiert" markiert).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-07-30 20:14:11 +02:00
co-authored by Claude Opus 4.8
parent 0d2d8679a7
commit 11e13cdb5a
4 changed files with 75 additions and 6 deletions
+1 -1
View File
@@ -1202,7 +1202,7 @@ dort bereits nachvalidiert, ØR +0,305.) **Eine** Oberfläche:
Daten älter als 60 s werden verworfen. **REINE ANZEIGE** — ob HL-Buch-Signale auf den Daten älter als 60 s werden verworfen. **REINE ANZEIGE** — ob HL-Buch-Signale auf den
CFD übertragbar sind, wird gerade gemessen (`analyze_bookflow.py` im HL-Projekt, CFD übertragbar sind, wird gerade gemessen (`analyze_bookflow.py` im HL-Projekt,
Datensammlung seit 2026-07-30, Urteil in ~2 Wochen). Der Indikator Datensammlung seit 2026-07-30, Urteil in ~2 Wochen). Der Indikator
**`mql5/SR_Levels.mq5`** (**v1.28** — `LQ`-Handler zeichnet seit v1.14 **nur noch **`mql5/SR_Levels.mq5`** (**v1.29** — `LQ`-Handler zeichnet seit v1.14 **nur noch
den PFEIL**, rechtsbündig am aktuellen Rand (in `RepositionLabels()` nachgeführt, den PFEIL**, rechtsbündig am aktuellen Rand (in `RepositionLabels()` nachgeführt,
bleibt beim Scrollen rechts; Details im **Tooltip**) — Linie und Text-Label sind bleibt beim Scrollen rechts; Details im **Tooltip**) — Linie und Text-Label sind
auf User-Wunsch raus („Chart zu voll"). **v1.15 = CHART-THEME** (User „Farben im auf User-Wunsch raus („Chart zu voll"). **v1.15 = CHART-THEME** (User „Farben im
+15
View File
@@ -2024,6 +2024,21 @@ class TradingEngine:
lines.append(f"EQ;{tag};{z['lo']};{z['hi']};{int(z['t'])}") lines.append(f"EQ;{tag};{z['lo']};{z['hi']};{int(z['t'])}")
except Exception: except Exception:
pass pass
# KONSOLIDIERUNGS-BOX (M5, dieselbe wie der validierte Squeeze):
# CO;lo;hi;<0|1> — letztes Feld 1 = komprimiert (≤2,5×ATR, Ausbruch steht
# bevor), 0 = nur die aktuelle 10-Bar-Spanne. ⚠ REINE ANZEIGE: die
# Konsolidierungs-SETUPS (False Breakout, Distribution, Accumulation,
# Retest) sind gemessen ALLE verworfen (`backtest_consolidation.py`);
# validiert ist nur der Squeeze-AUSBRUCH. Die Box zeigt also, WO gerade
# gestaut wird — nicht, wohin es geht.
try:
_sq = (self.wave.snapshot() or {}).get("squeeze") or {}
_lo, _hi = _sq.get("box_lo"), _sq.get("box_hi")
if _lo and _hi and _hi > _lo:
_tight = 1 if _sq.get("state") in ("armed", "active") else 0
lines.append(f"CO;{_lo};{_hi};{_tight}")
except Exception:
pass
# Aktueller Kurs für die fette Anzeige oben rechts (User-Wunsch): PX;bid # Aktueller Kurs für die fette Anzeige oben rechts (User-Wunsch): PX;bid
try: try:
_bid = (self.data.snapshot() or {}).get("bid") _bid = (self.data.snapshot() or {}).get("bid")
+8 -4
View File
@@ -604,17 +604,21 @@ class WaveRecommender:
return none return none
box_hi = max(hb); box_lo = min(lb) box_hi = max(hb); box_lo = min(lb)
box_atr = round((box_hi - box_lo) / atr, 2) box_atr = round((box_hi - box_lo) / atr, 2)
# Box-Grenzen immer mitgeben — der MT5-Chart zeichnet die Konsolidierung
# daraus (reine Anzeige; Konsolidierungs-SETUPS sind gemessen verworfen,
# `backtest_consolidation.py` — nur der Squeeze-Ausbruch ist validiert).
_box = {"box_hi": round(box_hi, 3), "box_lo": round(box_lo, 3)}
if box_atr > _SQ_MULT: # keine Kompression if box_atr > _SQ_MULT: # keine Kompression
return {"state": None, "dir": None, "level": None, "box_atr": box_atr} return {"state": None, "dir": None, "level": None, "box_atr": box_atr, **_box}
px = closes[-1] px = closes[-1]
up = box_hi + _SQ_K * atr; dn = box_lo - _SQ_K * atr up = box_hi + _SQ_K * atr; dn = box_lo - _SQ_K * atr
if px >= up: if px >= up:
return {"state": "active", "dir": "LONG", "level": round(up, 3), "box_atr": box_atr} return {"state": "active", "dir": "LONG", "level": round(up, 3), "box_atr": box_atr, **_box}
if px <= dn: if px <= dn:
return {"state": "active", "dir": "SHORT", "level": round(dn, 3), "box_atr": box_atr} return {"state": "active", "dir": "SHORT", "level": round(dn, 3), "box_atr": box_atr, **_box}
dir_ = "LONG" if (up - px) <= (px - dn) else "SHORT" # armed → nähere Grenze dir_ = "LONG" if (up - px) <= (px - dn) else "SHORT" # armed → nähere Grenze
return {"state": "armed", "dir": dir_, return {"state": "armed", "dir": dir_,
"level": round(up if dir_ == "LONG" else dn, 3), "box_atr": box_atr} "level": round(up if dir_ == "LONG" else dn, 3), "box_atr": box_atr, **_box}
@staticmethod @staticmethod
def _bounce_one(closes, atr): def _bounce_one(closes, atr):
+51 -1
View File
@@ -12,7 +12,12 @@
//| 4) Der Bot muss laufen (schreibt die CSV alle ~5 s). | //| 4) Der Bot muss laufen (schreibt die CSV alle ~5 s). |
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
#property copyright "Oil Trading Bot" #property copyright "Oil Trading Bot"
#property version "1.28" #property version "1.29"
// v1.29 (2026-07-30): KONSOLIDIERUNGS-BOX (CO;lo;hi;tight) — die Spanne der letzten
// 10 M5-Bars, aus der der validierte Squeeze-Ausbruch kommt. Komprimiert
// (<=2,5xATR) wird sie deutlicher gezeichnet. ⚠ REINE ANZEIGE: alle
// Konsolidierungs-SETUPS sind gemessen verworfen (backtest_consolidation.py) —
// die Box zeigt WO gestaut wird, nicht WOHIN es geht.
// v1.28 (2026-07-30): G/V der offenen Position direkt UNTER dem Kurs oben rechts // v1.28 (2026-07-30): G/V der offenen Position direkt UNTER dem Kurs oben rechts
// (User-Wunsch) — PL;wert;waehrung, NETTO wie im Dashboard (WHT-Quellensteuer // (User-Wunsch) — PL;wert;waehrung, NETTO wie im Dashboard (WHT-Quellensteuer
// bei Gewinn bereits abgezogen). Gruen im Plus, rot im Minus; ohne offene // bei Gewinn bereits abgezogen). Gruen im Plus, rot im Minus; ohne offene
@@ -136,6 +141,10 @@ input int InpLabelSize = 12; // Schriftgroesse der Linien-Besc
input bool InpShowPBreak = true; // Durchbruchwahrscheinlichkeit am S/R-Label input bool InpShowPBreak = true; // Durchbruchwahrscheinlichkeit am S/R-Label
input color InpLabelColor = clrWhite; // Farbe ALLER Linien-Beschriftungen (User-Wunsch: weiss) input color InpLabelColor = clrWhite; // Farbe ALLER Linien-Beschriftungen (User-Wunsch: weiss)
input color InpPriceColor = clrWhite; // Kurs oben rechts (weiss) input color InpPriceColor = clrWhite; // Kurs oben rechts (weiss)
input bool InpShowConsol = true; // Konsolidierungs-Box (10 M5-Bars) zeichnen
input color InpConsolColor = C'88,166,255'; // Box-Farbe (blau)
input int InpConsolAlpha = 8; // Deckkraft in % (komprimiert: x2)
input int InpConsolBars = 10; // Box-Laenge in Bars (= _SQ_N im Bot)
input bool InpShowPnL = true; // G/V der offenen Position unter dem Kurs input bool InpShowPnL = true; // G/V der offenen Position unter dem Kurs
input color InpPnLUpColor = C'0,255,127'; // G/V im Plus (neongruen) input color InpPnLUpColor = C'0,255,127'; // G/V im Plus (neongruen)
input color InpPnLDownColor = C'255,69,0'; // G/V im Minus (rot) input color InpPnLDownColor = C'255,69,0'; // G/V im Minus (rot)
@@ -578,6 +587,47 @@ void Redraw()
} }
continue; continue;
} }
// KONSOLIDIERUNGS-BOX: CO;lo;hi;<0|1> — die Spanne der letzten 10 M5-Bars
// (dieselbe Box, aus der der validierte Squeeze-Ausbruch kommt). Feld 3 = 1
// bedeutet KOMPRIMIERT (≤2,5×ATR) → Ausbruch steht bevor, dann kräftiger.
// ⚠ REINE ANZEIGE: alle Konsolidierungs-SETUPS (False Breakout, Distribution,
// Accumulation, Retest) sind gemessen verworfen — die Box sagt WO gestaut
// wird, nicht WOHIN es geht.
if(typ == "CO")
{
if(k < 3) continue;
if(!InpShowConsol) continue;
double clo = StringToDouble(p[1]), chi = StringToDouble(p[2]);
bool tight = (k > 3 && p[3] == "1");
if(clo <= 0 || chi <= clo) continue;
datetime ct0 = iTime(_Symbol, PERIOD_CURRENT, 0)
- (datetime)(PeriodSeconds() * InpConsolBars);
datetime ct1 = RightTime();
string cn = PFX + "CONSOL";
if(ObjectCreate(0, cn, OBJ_RECTANGLE, 0, ct0, clo, ct1, chi))
{
ObjectSetInteger(0, cn, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, cn, OBJPROP_WIDTH, 1);
ObjectSetInteger(0, cn, OBJPROP_FILL, true);
ObjectSetInteger(0, cn, OBJPROP_BACK, true);
ObjectSetInteger(0, cn, OBJPROP_SELECTABLE, false);
}
else
{
ObjectMove(0, cn, 0, ct0, clo);
ObjectMove(0, cn, 1, ct1, chi);
}
// komprimiert = deutlicher sichtbar (Ausbruch steht bevor)
ObjectSetInteger(0, cn, OBJPROP_COLOR,
BlendBg(InpConsolColor, tight ? InpConsolAlpha * 2
: InpConsolAlpha));
ObjectSetString (0, cn, OBJPROP_TOOLTIP,
(tight ? "Konsolidierung (komprimiert - Ausbruch steht bevor)"
: "aktuelle 10-Bar-Spanne")
+ " " + DoubleToString(clo, (int)_Digits) + " - "
+ DoubleToString(chi, (int)_Digits));
continue;
}
// AKTUELLER KURS oben rechts, fett (User-Wunsch): PX;bid // AKTUELLER KURS oben rechts, fett (User-Wunsch): PX;bid
if(typ == "PX") if(typ == "PX")
{ {