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
+8 -4
View File
@@ -604,17 +604,21 @@ class WaveRecommender:
return none
box_hi = max(hb); box_lo = min(lb)
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
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]
up = box_hi + _SQ_K * atr; dn = box_lo - _SQ_K * atr
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:
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
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
def _bounce_one(closes, atr):