Bestaetigtes Chartmuster je Zeitebene ins MT5-Chart (Indikator v1.45)

User-Wunsch: das bestaetigte Muster in das jeweils passende Chart einzeichnen.

CSV: neue Zeile `PT;<TF>;<name>;<dir>;<trigger>;<ziel>` je Zeitebene.
INDIKATOR: zeichnet NUR die Zeile, deren <TF> zu SEINEM Chart passt
(`TFName(PERIOD_CURRENT)`). Ohne diesen Filter laegen alle Zeitebenen
uebereinander im selben Fenster und keine waere lesbar - so bekommt jedes
Chartfenster (M1/M5/M15/M30/H1) sein eigenes Muster.
Gezeichnet werden zwei waagerechte Linien: Trigger (Nackenlinie, durchgezogen,
Breite 2) und Ziel (gestrichelt), gruen bei bullisch, rot bei baerisch, dazu ein
Label an der Triggerlinie.

⚠⚠ NUR `confirmed`. "Bildet sich" ist genau der Zustand, in dem noch nichts
gebrochen ist - ihn zu zeichnen waere eine Vorhersage. Live gegengeprueft:
M30 "Tasse+Henkel" und H1 "Aufsteigendes Dreieck" stehen auf confirmed und sind
in der CSV; der M5-"Steigende Keil" ist nur forming und wird korrekt NICHT
exportiert.

⚠⚠ EHRLICHKEIT IM LABEL: die Muster-Klasse ist als SIGNAL gemessen und
VERWORFEN - die Ziel-Trefferquote liegt bei nur 13-38 % (backtest_patterns.py).
Deshalb steht "(trifft 13-38 %)" im Chart-Label. Eine gezeichnete Ziellinie ohne
diesen Zusatz liest sich wie eine Prognose, und genau das ist sie nicht.
Kein Verdict-Gewicht, kein Trade-Trigger.

⚠ Nur ZUSAMMENGESETZT aus `patterns_tf`, das der Snapshot ohnehin baut - kein
zweiter Rechenweg (der Konsens-Pfeil-Fehler).

⚠ Der dokumentierte Fallstrick beachtet: kompiliert wurde ins RICHTIGE Terminal
(D0E8209F..., das einzige mit sr_levels.csv), mit EIGENEM Logpfad, und geprueft
wurde auf "Result: 0 errors, 0 warnings" PLUS frischen .ex5-Zeitstempel - nicht
auf den Default-Log. Der erste Versuch lief ins Leere, weil der Editor-Pfad
falsch war (Pepperstone-Ordner existiert nicht, es ist "MetaTrader 5"); das
leere Log und die unveraenderte .ex5 haben es verraten.
Quelle ins Repo gespiegelt (mql5/SR_Levels.mq5), Backup daneben.

Abschaltbar: InpShowMuster=false; Farben ueber InpMusterBullColor/-BearColor.
Pipeline A-G gruen, 97 Tests, deployt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-08-21 13:02:58 +02:00
co-authored by Claude Opus 5
parent db0de81ef6
commit 263ec9f9a5
3 changed files with 1317 additions and 1 deletions
+82 -1
View File
@@ -12,7 +12,7 @@
//| 4) Der Bot muss laufen (schreibt die CSV alle ~5 s). |
//+------------------------------------------------------------------+
#property copyright "Oil Trading Bot"
#property version "1.44"
#property version "1.45"
// v1.42 (2026-08-19): Y-Stapel oben rechts GEMESSEN statt geschaetzt. Der
// Faktor 1,8 aus v1.41 war nur die naechste Schaetzung; jetzt liefert
// TextGetSize die TATSAECHLICHE Pixelhoehe (LabelH). Ausserdem wird Y bei
@@ -271,6 +271,12 @@ 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)
// Bestaetigtes Chartmuster je Zeitebene (User-Wunsch 2026-08-21).
// ⚠ Gezeichnet wird NUR das Muster, dessen Zeitebene zum EIGENEN Chart passt.
input bool InpShowMuster = true; // bestaetigtes Chartmuster zeichnen
input color InpMusterBullColor = C'70,180,100';// bullisch
input color InpMusterBearColor = C'220,90,80'; // baerisch
const string PFX = "SRB_"; // Präfix S/R-Linien (aus Datei)
const string RPFX = "SRR_"; // Präfix dynamische Range (aus Chart)
string g_last = "\x01"; // letzter Datei-Inhalt (gegen Flackern)
@@ -317,6 +323,25 @@ int OnInit()
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Farbe mit dem Chart-Hintergrund mischen — simuliert TRANSPARENZ. |
//+------------------------------------------------------------------+
//| Zeitebene dieses Charts als Text ("M1","M5","M15","M30","H1" ...) |
//| ⚠ Muss zu den Schluesseln passen, die der Bot in `PT;` schreibt |
//| (`engine.patterns_tf`). Weicht die Schreibweise ab, wird still |
//| NICHTS gezeichnet — deshalb die Fallback-Zeile am Ende. |
//+------------------------------------------------------------------+
string TFName(ENUM_TIMEFRAMES tf)
{
switch(tf)
{
case PERIOD_M1: return "M1";
case PERIOD_M5: return "M5";
case PERIOD_M15: return "M15";
case PERIOD_M30: return "M30";
case PERIOD_H1: return "H1";
}
return EnumToString(tf);
}
//| ⚠ MT5 kann bei OBJ_RECTANGLE KEIN echtes Alpha (nur Canvas- |
//| Objekte könnten das). Da der Hintergrund bekannt und einfarbig |
//| ist, sieht die Mischung exakt aus wie eine transparente Füllung. |
@@ -981,6 +1006,62 @@ void Redraw()
// 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.
// BESTAETIGTES CHARTMUSTER je Zeitebene (PT;<TF>;<name>;<dir>;<trigger>;<ziel>)
// — User-Wunsch 2026-08-21.
// ⚠⚠ Es wird NUR die Zeile gezeichnet, deren <TF> zum EIGENEN Chart passt.
// Der Bot liefert alle Zeitebenen in derselben CSV; ohne diesen Filter
// laegen fuenf Musterpaare uebereinander und keines waere lesbar.
// So bekommt jedes Chartfenster (M1/M5/M15/H1) sein eigenes Muster.
// ⚠⚠ EHRLICHKEIT: die Ziel-Trefferquote dieser Muster-Klasse liegt gemessen
// bei nur 13-38 % (backtest_patterns.py). Sie steht im Label, weil eine
// gezeichnete Ziellinie sonst wie eine Prognose aussieht — und genau das
// ist sie nicht.
// ⚠ Nur `confirmed` kommt ueberhaupt an; "bildet sich" waere der Zustand, in
// dem noch nichts gebrochen ist.
if(typ == "PT")
{
if(!InpShowMuster || k < 6) continue;
if(p[1] != TFName(PERIOD_CURRENT)) continue; // fremde Zeitebene
double trg = StringToDouble(p[4]), zl = StringToDouble(p[5]);
if(trg <= 0 || zl <= 0) continue;
bool bull = (p[3] == "bull");
color pc = bull ? InpMusterBullColor : InpMusterBearColor;
datetime pt0 = iTime(_Symbol, PERIOD_CURRENT,
MathMin(80, Bars(_Symbol, PERIOD_CURRENT) - 1));
string ln1 = PFX + "MUST_TRG", ln2 = PFX + "MUST_ZIEL";
if(ObjectFind(0, ln1) < 0)
{
ObjectCreate(0, ln1, OBJ_TREND, 0, pt0, trg, RightTime(), trg);
ObjectSetInteger(0, ln1, OBJPROP_RAY_RIGHT, false);
ObjectSetInteger(0, ln1, OBJPROP_WIDTH, 2);
ObjectSetInteger(0, ln1, OBJPROP_SELECTABLE, false);
}
if(ObjectFind(0, ln2) < 0)
{
ObjectCreate(0, ln2, OBJ_TREND, 0, pt0, zl, RightTime(), zl);
ObjectSetInteger(0, ln2, OBJPROP_RAY_RIGHT, false);
ObjectSetInteger(0, ln2, OBJPROP_STYLE, STYLE_DOT);
ObjectSetInteger(0, ln2, OBJPROP_SELECTABLE, false);
}
ObjectSetInteger(0, ln1, OBJPROP_COLOR, pc);
ObjectMove(0, ln1, 0, pt0, trg); ObjectMove(0, ln1, 1, RightTime(), trg);
ObjectSetInteger(0, ln2, OBJPROP_COLOR, pc);
ObjectMove(0, ln2, 0, pt0, zl); ObjectMove(0, ln2, 1, RightTime(), zl);
string plb = PFX + "MUST_LBL";
if(ObjectFind(0, plb) < 0)
{
ObjectCreate(0, plb, OBJ_TEXT, 0, RightTime(), trg);
ObjectSetInteger(0, plb, OBJPROP_ANCHOR, ANCHOR_RIGHT_LOWER);
ObjectSetInteger(0, plb, OBJPROP_FONTSIZE, InpLabelSize);
ObjectSetInteger(0, plb, OBJPROP_SELECTABLE, false);
}
ObjectSetString(0, plb, OBJPROP_TEXT,
(bull ? "^ " : "v ") + p[2] + " bestaetigt - Ziel "
+ DoubleToString(zl, (int)_Digits) + " (trifft 13-38 %)");
ObjectSetInteger(0, plb, OBJPROP_COLOR, pc);
ObjectMove(0, plb, 0, RightTime(), trg);
continue;
}
if(typ == "RZ" || typ == "SZ")
{
if(!InpShowZonen || k < 3) continue;
File diff suppressed because it is too large Load Diff