Entwicklung eines Toolkits zur Price-Action-Analyse (Teil 62): Entwicklung eines adaptiven Systems in MQL5 zur Erkennung paralleler Kanäle und den Ausbrüchen.
Inhalt
- Einführung
- Parallelkanäle und strukturelle Ausbrüche
- Systemarchitektur in MQL5
- Tests und Ergebnisse
- Schlussfolgerung
Einführung
Im vorangegangenen Teil dieser Serie haben wir ein Framework zur Erkennung von Trendlinienausbrüchen untersucht, das anhand von drei Swing-Punkten validiert wurde. Die Tests haben gezeigt, dass der Ansatz eindeutige Ausbruchsmöglichkeiten effektiv signalisiert hat. Allerdings zeigte sich eine Einschränkung: Das System erfasste nur Ausbrüche in Richtung der gerade erstellten Trendlinien. Das bedeutete, dass solche Ausbruchsstrukturen unbemerkt blieben, wenn sich der Kurs in die entgegengesetzte Richtung oder auf der nicht überwachten Seite bewegte.
Dieser Artikel erweitert diesen Ansatz durch die Einführung eines adaptiven Systems zur Erkennung paralleler Kanäle und Kanal-Ausbrüche. Das System bildet Kanäle auf der Grundlage von Swing-Punkten, überwacht die Kursentwicklung innerhalb dieser Kanäle und bestätigt Ausbrüche dynamisch. Durch die Überwachung beider Seiten des Kanals stellt das Framework sicher, dass keine strukturell relevanten Kursbewegungen übersehen werden.
Im Mittelpunkt steht die Kombination aus Trendliniengeometrie, adaptiver Neuberechnung und Echtzeit-Validierung, um MQL5-Nutzern ein robustes Toolkit für die Analyse des Kursverhaltens zur Verfügung zu stellen. Dieses System schafft zudem die Grundlage für zukünftige Erweiterungen, wie beispielsweise die Integration von Volatilitätsfiltern, ATR-basierten Anpassungen und fortgeschrittenen Methoden zur Bestätigung von Ausbrüchen.
Parallelkanäle und strukturelle Ausbrüche
Ein Parallelkanal ist ein Chartmuster, das aus zwei gleich weit auseinander liegenden Trendlinien gebildet wird – wobei die eine die Swing-Hochs und die andere die Swing-Tiefs verbindet –, die einen klar definierten Kursbereich einschließen. Parallelkanäle sind ein grundlegendes Element der technischen Analyse, da sie die kurz- und mittelfristige Tendenz des Marktes veranschaulichen und es Händlern gleichzeitig ermöglichen, potenzielle Ausbruchszonen zu antizipieren.
Ein Ausbruch liegt vor, wenn sich der Kurs entschlossen über die Kanalgrenzen hinausbewegt, sei es nach oben oder nach unten. Strukturelle Ausbrüche sind besonders bedeutsam, da sie häufig die Fortsetzung oder Umkehr eines vorherrschenden Trends signalisieren. Um diese Ausbrüche zuverlässig zu erfassen, sind sowohl eine präzise Kanalkonstruktion als auch Mechanismen zur Bestätigung in Echtzeit erforderlich.
Kanalbildung auf Basis von Trendlinien
Die Grundlage des Systems liegt in der präzisen Identifizierung von strukturell bedeutsamen Swing-Hochs und Swing-Tiefs. Anstatt jede noch so kleine Schwankung zu berücksichtigen, nutzt der Erkennungsprozess eine ATR-basierte Filterung, um unbedeutende Kursbewegungen auszublenden. Dadurch wird sichergestellt, dass nur Swings mit ausreichender Auslenkung berücksichtigt werden, was das Rauschen verringert und die strukturelle Integrität gewährleistet.
Sobald validierte Swing-Punkte ermittelt wurden, wird die obere Grenze des Kanals durch Verbinden aufeinanderfolgender Swing-Hochs gebildet. Diese Linie legt die Richtungsgeometrie der Struktur fest. Anschließend wird parallel dazu eine entsprechende untere Begrenzung projiziert, wobei ein aus den Swing-Verhältnissen abgeleiteter äquidistanter Versatz verwendet wird. Das Ergebnis ist ein geometrisch konsistenter Parallelkanal, der die tatsächliche Marktstruktur widerspiegelt und nicht auf willkürlichen Zeichnungen beruht.

Die Verwendung einer echten parallelen Projektion ist von entscheidender Bedeutung. Anstatt zwei voneinander unabhängige Geraden separat anzupassen, sorgt das System dafür, dass die Steigungen der Begrenzungsgeraden übereinstimmen. Dadurch bleibt die Symmetrie erhalten und es wird sichergestellt, dass der Kanal eine kohärente Einschlussstruktur darstellt. Sobald sich neue Swing-Punkte bilden, wird der Kanal neu berechnet. Durch diese kontinuierliche strukturelle Anpassung bleibt das Framework mit der aktuellen Kursentwicklung synchronisiert und behält gleichzeitig seine geometrische Gültigkeit bei.
Erkennung struktureller Ausbrüche
Ein Ausbruch liegt vor, wenn der Kurs außerhalb einer der Kanalgrenzen schließt. Allerdings gilt nicht jede Grenzüberschreitung als gültiges Signal. Um Fehlauslösungen durch geringfügige Kurssprünge oder Liquiditäts-Sweeps zu vermeiden, werden bei der Bestätigung eines Ausbruchs Mindestschwellenwerte berücksichtigt.
Die primäre Bestätigungsregel verlangt einen eindeutigen Kerzenschluss außerhalb der Grenze. Zur Stärkung der Validierung können optionale Filter angewendet werden, darunter volatilitätsbasierte Schwellenwerte, die eine ausreichend starke Bewegung im Verhältnis zum jüngsten Kursverhalten sicherstellen. Die Validierung durch Retests bietet eine zusätzliche Bestätigungsebene. Nach einem ersten Durchbruch der Kursgrenze kann der Kurs vorübergehend zurückkehren, um das durchbrochene Niveau erneut zu testen. Wenn der Kurs dieses Niveau bestätigt und die Bewegung in Richtung des Ausbruchs fortsetzt, gewinnt das Signal an struktureller Glaubwürdigkeit. Dieser Mechanismus reduziert vorzeitige Einstiege und filtert Schwankungen mit geringer Dynamik heraus.

Nach der Bestätigung werden Ausbruchsereignisse mit nicht nachträglich neu berechneten Pfeilen markiert. Diese Markierungen werden dauerhaft im Chart gespeichert, sodass historische Signale zur Analyse und Überprüfung weiterhin sichtbar bleiben. Diese Trennung zwischen der adaptiven Kanalneuberechnung und der dauerhaften Signalspeicherung ist für die Aufrechterhaltung der analytischen Zuverlässigkeit von entscheidender Bedeutung.
Adaptives Verhalten und Neuberechnung in Echtzeit
Die Finanzmärkte sind dynamisch, und jedes strukturelle Instrument muss sich entsprechend anpassen. Aus diesem Grund wird die Kanalbildung neu berechnet, sobald neue Kursdaten vorliegen. Das System arbeitet mit fertiggestellten Bars, um die Konsistenz zu gewährleisten und Instabilitäten unter Live-Bedingungen zu vermeiden.
Bei jeder Neuberechnung werden die Gültigkeit des Swings erneut geprüft, die Kanalgeometrie bei Bedarf neu berechnet und die Ausbruchbedingungen anhand der aktualisierten Struktur neu bewertet. Sofern der bisherige Kanal strukturell gültig bleibt, wird er beibehalten. Wenn das neu entstehende Kursverhalten die bisherige Struktur ungültig macht, wird eine neue Struktur abgeleitet. Die Ausbruchsbedingungen werden zudem kontinuierlich anhand des sich verändernden Kanals überprüft. Dadurch werden verfrühte Signale vermieden, während gleichzeitig sichergestellt wird, dass bedeutende strukturelle Veränderungen nicht übersehen werden. Durch die gleichzeitige Überwachung der oberen und unteren Grenzwerte vermeidet das System eine richtungsabhängige Verzerrung. Aufwärts- und Abwärtsbewegungen werden gleichermaßen überwacht, wodurch ein umfassendes strukturelles Bild der Kursentwicklung entsteht, anstatt eine einseitige Interpretation zu liefern.

Dieses adaptive Framework ermöglicht es dem System, als „Live-Strukturscanner“ zu fungieren – es reagiert auf Marktveränderungen und gewährleistet gleichzeitig die Signalintegrität.
Systemarchitektur in MQL5
System-Übersicht
In diesem Abschnitt wird der interne Aufbau des Expert Advisors (EA) beschrieben und erläutert, wie seine Komponenten modular aufgebaut sind, wie sie miteinander interagieren und wie der Datenfluss verläuft, durch den Rohmarktdaten in validierte Ausbruchsignale umgewandelt werden. Die Architektur legt Wert auf Übersichtlichkeit, Wartbarkeit und Robustheit und ermöglicht so eine präzise Analyse sowie eine flexible Anpassung. Der EA basiert auf einem stark modularen, ereignisgesteuerten Design, das für MetaTrader 5 optimiert ist. Dabei arbeitet jede Komponente eigenständig und übernimmt eine bestimmte Aufgabe, kommuniziert jedoch nahtlos mit den anderen Komponenten, wodurch ein einheitliches System gewährleistet wird.
Das System wird bei jeder neuen Bar ausgeführt, wobei es auf der Grundlage der jüngsten Swing-Punkte – also bedeutender Wendepunkte am Markt – einen parallelen Kanal rekonstruiert und anschließend überprüft, ob diese Struktur alle vordefinierten Kriterien erfüllt. Der Validierungsprozess umfasst mehrere Filter, darunter die Konsistenz der Steigung, die Anzahl der Berührungen, die Aktualität und die Volatilitätsbedingungen, die alle anhand eines 14-Perioden-ATR normalisiert werden. Diese Normalisierung stellt sicher, dass das System über verschiedene Symbole und Zeiträume hinweg konsistent bleibt und sich automatisch an die Marktvolatilität anpasst. Sobald ein zuverlässiger Kanal identifiziert wurde, wird dieser im Chart mit klaren, verlängerbaren Trendlinien und Beschriftungen dargestellt, wodurch Händler sofort einen visuellen Kontext erhalten. Anschließend wertet das System aus, ob die jüngste Kursentwicklung auf einen Ausbruch hindeutet – ein Ereignis, das einen Handel auslösen könnte –, indem es die Kanallinien auf die Echtzeitdaten projiziert, mehrere Bestätigungsfilter anwendet, um die Gültigkeit des Ausbruchs zu bestätigen, und die Signale so verwaltet, dass Fehlalarme reduziert werden.
Modulare Komponenten und Zuständigkeiten
Modul zur Erkennung von Swing-Punkten
Zuständig für die Analyse von Rohpreisdaten, um signifikante lokale Höchst- und Tiefststände zu ermitteln, die die strukturelle Grundlage für die gesamte Analyse bilden. Es scannt die jüngsten Bars innerhalb eines konfigurierbaren Bereichs – in der Regel die letzten 150 Bars – und wendet dabei fraktale Logik an, um Hochs und Tiefs zu identifizieren, die sich von den benachbarten Punkten abheben. Dabei wird geprüft, ob der Höchst- oder Tiefstwert einer Bar innerhalb eines Rückblickzeitraums (SwingLookback) über oder unter den Werten der umgebenden Bars liegt. Um nicht auf geringfügige Schwankungen zu reagieren, kann ein optionaler ATR-Filter aktiviert werden, der nur Swings berücksichtigt, die eine von der Volatilität abhängige Mindestgröße (SwingSizeATRFactor) überschreiten. Erkannte Swing-Punkte werden in speziellen Arrays gespeichert, chronologisch sortiert und mit Laufnummern versehen, was den Zugriff darauf in nachfolgenden Modulen erleichtert. Diese Wendepunkte können visuell mit Pfeilen und Beschriftungen markiert werden, was den Händlern hilft, die aktuelle Marktstruktur auf einen Blick zu erfassen.
//+------------------------------------------------------------------+ //| Detect significant swing highs and lows | //+------------------------------------------------------------------+ void FindSignificantSwings(const MqlRates &rates[],int totalBars, SwingPoint &highs[],int &highCount, SwingPoint &lows[],int &lowCount) { highCount = 0; lowCount = 0; double minSize = UseATRFiltering ? currentATR * SwingSizeATRFactor : MinSwingSize; for(int i = SwingLookback; i < totalBars - SwingLookback; i++) { //--- Detect Swing High bool isHigh = true; double currentHigh = rates[i].high; for(int j=1; j<=SwingLookback; j++) { if(rates[i-j].high >= currentHigh || rates[i+j].high >= currentHigh) { isHigh = false; break; } } if(isHigh) { double leftLow = MathMin(rates[i-1].low,rates[i-2].low); double rightLow = MathMin(rates[i+1].low,rates[i+2].low); double swingSize = currentHigh - MathMax(leftLow,rightLow); if(swingSize >= minSize && highCount < 50) { highs[highCount].time = rates[i].time; highs[highCount].price = currentHigh; highs[highCount].barIndex = i; highs[highCount].size = swingSize; highs[highCount].isHigh = true; highCount++; } } //--- Detect Swing Low bool isLow = true; double currentLow = rates[i].low; for(int j=1; j<=SwingLookback; j++) { if(rates[i-j].low <= currentLow || rates[i+j].low <= currentLow) { isLow = false; break; } } if(isLow) { double leftHigh = MathMax(rates[i-1].high,rates[i-2].high); double rightHigh = MathMax(rates[i+1].high,rates[i+2].high); double swingSize = MathMin(leftHigh,rightHigh) - currentLow; if(swingSize >= minSize && lowCount < 50) { lows[lowCount].time = rates[i].time; lows[lowCount].price = currentLow; lows[lowCount].barIndex = i; lows[lowCount].size = swingSize; lows[lowCount].isHigh = false; lowCount++; } } } if(DebugMode) Print("Swings found: Highs=",highCount," Lows=",lowCount); } //+------------------------------------------------------------------+
Modul zur Kanalkonstruktion und Bewertungslogik
Dieses Kernmodul führt eine umfassende Suche über alle Kombinationen von Swing-Hochs und Swing-Tiefs durch, um den zuverlässigsten und strukturell stabilsten Parallelkanal zu ermitteln. Es bewertet jeden Kandidaten anhand mehrerer Kriterien, darunter Neigungsähnlichkeit und Breite, und wendet dabei Filter zur frühzeitigen Aussortierung an, wie beispielsweise „MaxSlopeDifference“ und „MinChannelWidthATR“. Für jeden Kandidaten werden die Berührungen der oberen und unteren Trendlinien mithilfe der erweiterten Funktion CountTouchesOnLine() gezählt, die nur Swings berücksichtigt, die auf oder nahe den Linien innerhalb einer Toleranz liegen und für die Position der Linie relevant sind.
Die Anzahl der Berührungen ist ein entscheidender Indikator dafür, wie gut der Kandidat zur aktuellen Marktstruktur passt. Die Bewertung setzt sich aus der Gesamtzahl der Berührungen, Aktualitätsboni und Stärkeindikatoren zusammen, die davon abhängen, wie viele der jüngsten Swings die Linien berühren. Der Kandidat mit der höchsten Punktzahl, der alle Mindestkriterien erfüllt, wird als am besten geeigneter Kanal ausgewählt, da er den bedeutendsten Unterstützungs- oder Widerstandsbereich im jüngsten Marktverhalten darstellt.
//+------------------------------------------------------------------+ //| Find the best parallel channel from swing points | //+------------------------------------------------------------------+ bool FindBestChannel(const SwingPoint &highs[],int highCount, const SwingPoint &lows[],int lowCount, const MqlRates &rates[],int totalBars, Channel &bestChannel) { bestChannel.score = 0.0; if(highCount < 2 || lowCount < 2) { if(DebugMode) Print("Not enough swings: highs=",highCount," lows=",lowCount); return false; } double tolerance = TouchToleranceATR * currentATR; for(int hi1=0; hi1<highCount-1; hi1++) { for(int hi2=hi1+1; hi2<highCount; hi2++) { double dt_high = (double)(highs[hi2].time - highs[hi1].time); if(dt_high <= 0) continue; double slope_high = (highs[hi2].price - highs[hi1].price) / dt_high; for(int lo1=0; lo1<lowCount-1; lo1++) { for(int lo2=lo1+1; lo2<lowCount; lo2++) { double dt_low = (double)(lows[lo2].time - lows[lo1].time); if(dt_low <= 0) continue; double slope_low = (lows[lo2].price - lows[lo1].price) / dt_low; double avgSlope = (MathAbs(slope_high) + MathAbs(slope_low)) / 2.0; double diff = MathAbs(slope_high - slope_low); double maxDiff = MaxSlopeDifference * MathMax(avgSlope,0.000001); if(diff > maxDiff) continue; double upper_at_l1 = highs[hi1].price + slope_high * (lows[lo1].time - highs[hi1].time); double upper_at_l2 = highs[hi1].price + slope_high * (lows[lo2].time - highs[hi1].time); if(upper_at_l1 <= lows[lo1].price || upper_at_l2 <= lows[lo2].price) continue; double dist1 = upper_at_l1 - lows[lo1].price; double dist2 = upper_at_l2 - lows[lo2].price; double width = (dist1 + dist2) / 2.0; if(width < MinChannelWidthATR * currentATR) continue; double lower_at_l1 = upper_at_l1 - width; double lower_at_l2 = upper_at_l2 - width; if(lower_at_l1 > lows[lo1].price + tolerance || lower_at_l2 > lows[lo2].price + tolerance) continue; int recentHigh = 0; int touchesHigh = CountTouchesOnLine(highs[hi1],highs[hi2],highs,highCount,true,tolerance,RecentTouchBars,recentHigh); SwingPoint lowerAnchor1, lowerAnchor2; lowerAnchor1.time = highs[hi1].time; lowerAnchor1.price = highs[hi1].price - width; lowerAnchor2.time = highs[hi2].time; lowerAnchor2.price = highs[hi2].price - width; int recentLow = 0; int touchesLow = CountTouchesOnLine(lowerAnchor1,lowerAnchor2,lows,lowCount,false,tolerance,RecentTouchBars,recentLow); if(touchesHigh < MinTouchPointsRequired || touchesLow < MinTouchPointsRequired) continue; if(MinRecentTouches > 0 && (recentHigh < MinRecentTouches || recentLow < MinRecentTouches)) continue; double score = (touchesHigh + touchesLow) * 25.0; double recencyBonus = (1.0 - (double)MathMin(highs[hi2].barIndex,lows[lo2].barIndex) / totalBars) * 30.0; score += recencyBonus; if(score > bestChannel.score) { bestChannel.high1 = highs[hi1]; bestChannel.high2 = highs[hi2]; bestChannel.low1 = lows[lo1]; bestChannel.low2 = lows[lo2]; bestChannel.slope = slope_high; bestChannel.width = width; bestChannel.highTouches = touchesHigh; bestChannel.lowTouches = touchesLow; bestChannel.score = score; bestChannel.type = ClassifyChannel(slope_high); bestChannel.strength = GradeStrength(touchesHigh + touchesLow); if(DebugMode) Print(StringFormat("Candidate accepted: H-touches=%d, L-touches=%d, width=%g, score=%g", touchesHigh,touchesLow,width,score)); } } } } } return (bestChannel.score > 0.0); } //+------------------------------------------------------------------+
Der Kanal-Suchprozess wertet Kombinationen aus Swing-Hochs und -Tiefs mithilfe einer verschachtelten Iteration aus. Obwohl dies zu einer theoretischen quadratischen Komplexität führt, bleibt die praktische Leistung dank aggressiver Frühfilter zur frühzeitigen Aussortierung unter Kontrolle. Kriterien wie die maximale Neigungsabweichung und die minimale ATR-normierte Kanalbreite sorgen dafür, dass schwache Kandidaten bereits vor einer eingehenderen Bewertung aussortiert werden. Zudem verhindert die Beschränkung der Swing-Erkennung auf ein begrenztes Rückblickfenster ein unkontrolliertes Anwachsen der möglichen Kombinationen. Diese strukturierte Vorselektion stellt sicher, dass das Kernmodul auch in volatilen Marktphasen leistungsfähig bleibt.
Visualisierungsmodul
Sobald der beste Kanal ermittelt wurde, stellt diese Komponente ihn im Chart übersichtlich dar. Es werden zwei parallele Trendlinien gezeichnet: eine obere Linie, die den anfänglichen Höchstpunkt mit einem prognostizierten zukünftigen Punkt verbindet, und eine untere Linie, die um die Kanalbreite versetzt ist, wobei die Parallelität gewahrt bleibt. Diese Linien werden um eine konfigurierbare Anzahl von Bars (LineExtensionBars) in die Zukunft verlängert und bilden so eine zukunftsorientierte Unterstützungs-/Widerstandszone. Die Trendlinien werden bei jedem Tick dynamisch neu erzeugt bzw. aktualisiert, um die Synchronisation mit den Echtzeitdaten zu gewährleisten und so eine überladene Darstellung zu vermeiden. Zur besseren Übersichtlichkeit werden zusätzliche visuelle Hinweise hinzugefügt, wie beispielsweise Kreuze an Swing-Punkten und Beschriftungen, die die Anzahl der Berührungen, die Kanalstärke und Tendenzsignale (nur Kauf, nur Verkauf oder neutral) angeben. Alle grafischen Objekte werden mit einem Präfix (TL_PREFIX) benannt und aktiv verwaltet – sie werden bei jedem Tick gelöscht und neu erstellt –, um das Chart optisch übersichtlich und präzise zu halten.
//+------------------------------------------------------------------+ //| Draw the parallel channel with extension | //+------------------------------------------------------------------+ void DrawChannel(const Channel &ch) { string upName = TL_PREFIX + "UPPER"; string dnName = TL_PREFIX + "LOWER"; string lblName = TL_PREFIX + "LABEL"; color upperColor = UpperLineColor; color lowerColor = LowerLineColor; //--- Compute future extension point datetime lastSwingTime = MathMax(ch.high2.time,ch.low2.time); datetime futureTime = lastSwingTime + LineExtensionBars * PeriodSeconds(_Period); double futureUpper = LinePriceAtTime(ch.high1,ch.high2,futureTime); double futureLower = futureUpper - ch.width; //--- Upper line (from first high to future point) if(ObjectFind(0,upName) < 0) ObjectCreate(0,upName,OBJ_TREND,0,ch.high1.time,ch.high1.price,futureTime,futureUpper); else { ObjectMove(0,upName,0,ch.high1.time,ch.high1.price); ObjectMove(0,upName,1,futureTime,futureUpper); } ObjectSetInteger(0,upName,OBJPROP_COLOR,upperColor); ObjectSetInteger(0,upName,OBJPROP_WIDTH,LineWidth); ObjectSetInteger(0,upName,OBJPROP_STYLE,LineStyle); ObjectSetInteger(0,upName,OBJPROP_RAY_RIGHT,false); ObjectSetInteger(0,upName,OBJPROP_BACK,false); //--- Lower line (parallel, starting at same time as upper) double lower1 = ch.high1.price - ch.width; if(ObjectFind(0,dnName) < 0) ObjectCreate(0,dnName,OBJ_TREND,0,ch.high1.time,lower1,futureTime,futureLower); else { ObjectMove(0,dnName,0,ch.high1.time,lower1); ObjectMove(0,dnName,1,futureTime,futureLower); } ObjectSetInteger(0,dnName,OBJPROP_COLOR,lowerColor); ObjectSetInteger(0,dnName,OBJPROP_WIDTH,LineWidth); ObjectSetInteger(0,dnName,OBJPROP_STYLE,LineStyle); ObjectSetInteger(0,dnName,OBJPROP_RAY_RIGHT,false); ObjectSetInteger(0,dnName,OBJPROP_BACK,false); //--- Optional low reference crosses if(ShowLowReferenceCrosses) { string cross1 = TL_PREFIX + "LOWREF1", cross2 = TL_PREFIX + "LOWREF2"; if(ObjectFind(0,cross1) < 0) ObjectCreate(0,cross1,OBJ_ARROW,0,ch.low1.time,ch.low1.price); else ObjectMove(0,cross1,0,ch.low1.time,ch.low1.price); ObjectSetInteger(0,cross1,OBJPROP_ARROWCODE,159); ObjectSetInteger(0,cross1,OBJPROP_COLOR,clrGray); ObjectSetInteger(0,cross1,OBJPROP_WIDTH,1); ObjectSetInteger(0,cross1,OBJPROP_BACK,false); if(ObjectFind(0,cross2) < 0) ObjectCreate(0,cross2,OBJ_ARROW,0,ch.low2.time,ch.low2.price); else ObjectMove(0,cross2,0,ch.low2.time,ch.low2.price); ObjectSetInteger(0,cross2,OBJPROP_ARROWCODE,159); ObjectSetInteger(0,cross2,OBJPROP_COLOR,clrGray); ObjectSetInteger(0,cross2,OBJPROP_WIDTH,1); ObjectSetInteger(0,cross2,OBJPROP_BACK,false); } //--- Label datetime labelTime = MathMax(ch.high2.time,ch.low2.time); double labelPrice = (ch.high1.price + ch.high2.price)/2.0 - ch.width/2.0; string strengthText = (ch.strength == HIGH ? "HIGH" : (ch.strength == MEDIUM ? "MEDIUM" : "LOW")); string biasText = "NEUTRAL"; if(UseChannelTypeFilter) { if(ch.type == ASCENDING) biasText = "BUY ONLY"; else if(ch.type == DESCENDING) biasText = "SELL ONLY"; } string labelText = "Touches: " + IntegerToString(ch.highTouches + ch.lowTouches) + "\nStrength: " + strengthText + "\nBias: " + biasText; if(ObjectFind(0,lblName) < 0) ObjectCreate(0,lblName,OBJ_TEXT,0,labelTime,labelPrice); else ObjectMove(0,lblName,0,labelTime,labelPrice); ObjectSetString(0,lblName,OBJPROP_TEXT,labelText); ObjectSetInteger(0,lblName,OBJPROP_COLOR,clrWhite); ObjectSetInteger(0,lblName,OBJPROP_FONTSIZE,10); ObjectSetInteger(0,lblName,OBJPROP_BACK,false); } //+------------------------------------------------------------------+
Die Breakout-Validierung unterliegt einem strukturierten Zustandsmodell, um eine doppelte oder vorzeitige Signalausgabe zu verhindern. Jedes erkannte Ereignis durchläuft definierte Phasen:
- Neutral – Keine Ausbruchsaktivitäten.
- Anstehender Ausbruch – Erstes Kreuzen erkannt, jedoch wird auf die Bestätigung durch einen Retest gewartet (sofern der Modus für Retest aktiviert ist).
- Bestätigter Ausbruch – alle Filterkriterien erfüllt; Signal ausgegeben.
- Abgelaufen/Ungültig – Die Bedingungen sind vor der Bestätigung ungültig geworden.
//+------------------------------------------------------------------+ //| Checks for breakout crossing and applies filters | //+------------------------------------------------------------------+ void CheckChannelBreakouts(const MqlRates &rates[],const Channel &ch, const SwingPoint &highs[],int highCount, const SwingPoint &lows[],int lowCount) { if(ArraySize(rates) < 3) return; datetime t1 = rates[1].time; datetime t2 = rates[2].time; double buf = BreakoutBufferPrice(); double minStrength = BreakoutMinStrengthATR * currentATR; double strongThreshold = BreakoutStrongThreshold * currentATR; int totalTouches = ch.highTouches + ch.lowTouches; double upper1 = LinePriceAtTime(ch.high1,ch.high2,t1); double upper2 = LinePriceAtTime(ch.high1,ch.high2,t2); double pUp1 = BreakoutUseClose ? rates[1].close : rates[1].high; double pUp2 = BreakoutUseClose ? rates[2].close : rates[2].high; bool crossedUp = false; if(BreakoutStrictMode) crossedUp = (pUp2 <= upper2 + buf) && (pUp1 > upper1 + buf); else crossedUp = (pUp1 > upper1 + buf); double upStrength = pUp1 - (upper1 + buf); bool strongUp = (minStrength == 0) || (upStrength >= minStrength); bool superStrongUp = (strongThreshold > 0) && (upStrength >= strongThreshold); double lower1 = upper1 - ch.width; double lower2 = upper2 - ch.width; double pLow1 = BreakoutUseClose ? rates[1].close : rates[1].low; double pLow2 = BreakoutUseClose ? rates[2].close : rates[2].low; bool crossedDown = false; if(BreakoutStrictMode) crossedDown = (pLow2 >= lower2 - buf) && (pLow1 < lower1 - buf); else crossedDown = (pLow1 < lower1 - buf); double downStrength = (lower1 - buf) - pLow1; bool strongDown = (minStrength == 0) || (downStrength >= minStrength); bool superStrongDown = (strongThreshold > 0) && (downStrength >= strongThreshold); bool isSweepUp = false, isSweepDown = false; if(UseLiquiditySweepFilter) { double high = rates[1].high, low = rates[1].low, close = rates[1].close; isSweepUp = (high > upper1 + buf) && (close <= upper1 + buf); isSweepDown = (low < lower1 - buf) && (close >= lower1 - buf); } bool volExpanded = true; if(UseVolatilityExpansion && atrBuffer[0] > 0) { double atrNow = atrBuffer[0]; double atr10 = atrBuffer[10]; if(atr10 > 0) volExpanded = (atrNow / atr10) >= MinVolatilityExpansion; } bool structBullish = true, structBearish = true; if(UseStructuralBreak) { SwingPoint lastHigh, lastLow; GetLastSwing(highs,highCount,lows,lowCount,lastHigh,lastLow); if(crossedUp && lastHigh.time > 0) structBullish = (pUp1 > lastHigh.price); if(crossedDown && lastLow.time > 0) structBearish = (pLow1 < lastLow.price); } bool allowBullish = true, allowBearish = true; if(UseChannelTypeFilter) { if(ch.type == ASCENDING) allowBearish = false; else if(ch.type == DESCENDING) allowBullish = false; } //--- Bullish breakout handling if(crossedUp && strongUp && allowBullish && !isSweepUp && volExpanded && structBullish) { bool trigger = superStrongUp; if(!trigger) { trigger = true; for(int i=1; i<=BreakoutConfirmationBars; i++) { if(i >= ArraySize(rates)) { trigger = false; break; } datetime ti = rates[i].time; double ui = LinePriceAtTime(ch.high1,ch.high2,ti); double pi = BreakoutUseClose ? rates[i].close : rates[i].high; if(!(pi > ui + buf && (pi - (ui + buf)) >= minStrength)) { trigger = false; break; } } } if(trigger) { if(UseRetestMode) { // Store pending breakout if(pendingCount >= ArraySize(pendingBreakouts)) ArrayResize(pendingBreakouts,pendingCount+10); PendingBreakout pb; pb.breakoutTime = t1; pb.price = pUp1; pb.isBullish = true; pb.linePrice = upper1; pb.totalTouches = totalTouches; pb.channelSlope = ch.slope; pb.channelWidth = ch.width; pb.high1 = ch.high1; pb.high2 = ch.high2; pendingBreakouts[pendingCount++] = pb; if(DebugMode) Print("Bullish pending retest at ",TimeToString(t1)); } else { double arrowPrice = rates[1].low - currentATR*0.15; DrawPermanentArrow(t1,arrowPrice,true,totalTouches,rates[1].low,rates[1].high); } if(AlertOnBreakout) Alert(_Symbol," ",EnumToString(_Period),": BUY breakout"); } } //--- Bearish breakout handling (symmetrical) if(crossedDown && strongDown && allowBearish && !isSweepDown && volExpanded && structBearish) { bool trigger = superStrongDown; if(!trigger) { trigger = true; for(int i=1; i<=BreakoutConfirmationBars; i++) { if(i >= ArraySize(rates)) { trigger = false; break; } datetime ti = rates[i].time; double ui = LinePriceAtTime(ch.high1,ch.high2,ti); double li = ui - ch.width; double pi = BreakoutUseClose ? rates[i].close : rates[i].low; if(!(pi < li - buf && ((li - buf) - pi) >= minStrength)) { trigger = false; break; } } } if(trigger) { if(UseRetestMode) { if(pendingCount >= ArraySize(pendingBreakouts)) ArrayResize(pendingBreakouts,pendingCount+10); PendingBreakout pb; pb.breakoutTime = t1; pb.price = pLow1; pb.isBullish = false; pb.linePrice = lower1; pb.totalTouches = totalTouches; pb.channelSlope = ch.slope; pb.channelWidth = ch.width; pb.high1 = ch.high1; pb.high2 = ch.high2; pendingBreakouts[pendingCount++] = pb; if(DebugMode) Print("Bearish pending retest at ",TimeToString(t1)); } else { double arrowPrice = rates[1].high + currentATR*0.15; DrawPermanentArrow(t1,arrowPrice,false,totalTouches,rates[1].low,rates[1].high); } if(AlertOnBreakout) Alert(_Symbol," ",EnumToString(_Period),": SELL breakout"); } } } //+------------------------------------------------------------------+
Dieses zustandsgesteuerte Design stellt sicher, dass jeder Ausbruch deterministisch und nur einmal verarbeitet wird, wodurch Signaldopplungen verhindert werden und die logische Transparenz sowohl im Sofort- als auch im Retest-Modus gewahrt bleibt.
Signalverwaltung und Persistenzschicht
Diese Komponente stellt sicher, dass Signale und visuelle Hinweise auch bei der Aktualisierung von Charts, bei Neuinitialisierungen oder bei der Neukompilierung des Codes zuverlässig erhalten bleiben. Es verwaltet Arrays wie „breakoutsArray“, in denen bestätigte Ausbrüche gespeichert werden, einschließlich Details wie Zeitpunkt, Kurs und Stärke. Es zeichnet permanente Pfeile und Zonen, die Ausbruchsniveaus markieren, und dehnt diese bei entsprechender Konfiguration (UseBreakoutZones) in die Zukunft aus. Im Retest-Modus wird kontinuierlich überwacht, ob der Kurs erneut in die Ausbruchszone zurückkehrt, wobei das Signal erst nach einem erfolgreichen Retest bestätigt wird. Es verwaltet den Lebenszyklus grafischer Objekte, löscht bei jedem Tick temporäre Objekte, sodass dauerhaft gespeicherte Signale sichtbar bleiben. Dieser Ansatz bietet Händlern einen einheitlichen visuellen und entscheidungsrelevanten Rahmen und verringert so die Verwirrung, die durch das Neuladen von Charts oder Codeänderungen entstehen kann.
//+------------------------------------------------------------------+ //| Store and draw confirmed signals | //+------------------------------------------------------------------+ void DrawPermanentArrow(datetime time,double price,bool isBullish,int totalTouches,double low=0,double high=0) { string arrowName = SIG_PREFIX + (isBullish ? "BUY_" : "SELL_") + IntegerToString((int)time) + "_" + IntegerToString(totalTouches); //--- Avoid duplicate arrows if(ObjectFind(0,arrowName) >= 0) return; if(!ObjectCreate(0,arrowName,OBJ_ARROW,0,time,price)) { if(DebugMode) Print("Failed to create arrow: ",GetLastError()); return; } ObjectSetInteger(0,arrowName,OBJPROP_ARROWCODE,isBullish ? 233 : 234); ObjectSetInteger(0,arrowName,OBJPROP_COLOR,isBullish ? BullArrowColor : BearArrowColor); ObjectSetInteger(0,arrowName,OBJPROP_WIDTH,ArrowSize); ObjectSetInteger(0,arrowName,OBJPROP_BACK,false); ObjectSetInteger(0,arrowName,OBJPROP_SELECTABLE,false); ObjectSetInteger(0,arrowName,OBJPROP_HIDDEN,true); string desc = "Channel Breakout " + (isBullish ? "BULLISH" : "BEARISH") + " (" + IntegerToString(totalTouches) + " touches)"; ObjectSetString(0,arrowName,OBJPROP_TEXT,desc); if(UseBreakoutZones && high > low) DrawBreakoutZone(time,low,high,isBullish,totalTouches); //--- Store in persistent array if(breakoutsCount >= ArraySize(breakoutsArray)) ArrayResize(breakoutsArray,breakoutsCount+10); breakoutsArray[breakoutsCount].time = time; breakoutsArray[breakoutsCount].price = price; breakoutsArray[breakoutsCount].isBullish = isBullish; breakoutsArray[breakoutsCount].totalTouches = totalTouches; breakoutsCount++; } //+------------------------------------------------------------------+
Bevor ein neues Breakout-Signal gespeichert oder gezeichnet wird, überprüft das System, ob nicht bereits ein gleichwertiges Signal im selben strukturellen Kontext aufgezeichnet wurde. Dadurch wird verhindert, dass bei anhaltender Volatilität oder bei mehreren Ticks innerhalb derselben Bar wiederholte Pfeile gezeichnet werden. Jeder gespeicherte Ausbruch enthält einen Zeitstempel und einen Strukturverweis, wodurch das System die Regel „ein Signal pro Ereignis“ durchsetzen kann. Dies gewährleistet Klarheit bei der visuellen Darstellung und gewährleistet die analytische Glaubwürdigkeit.
Unterstützungs- und Hilfssysteme
Die Unterstützungssysteme bilden die Grundlage für alle Module, indem sie wichtige Funktionen wie die ATR-Berechnung, die Objektverwaltung und mathematische Hilfsfunktionen bereitstellen. ATR wird über ein spezielles Handle (iATR) verwaltet, das bei jeder Bar aktualisiert wird und normalisierte Volatilitätskennzahlen liefert, die systemweit für die Filterung und die Darstellung von Zonen verwendet werden. Funktionen wie „LinePriceAtTime()“ berechnen den prognostizierten Kurs von Trendlinien zu bestimmten Zeitpunkten, während „CountTouchesOnLine()“ ermittelt, wie viele Swings für jede Trendlinie relevant sind, wobei nur diejenigen berücksichtigt werden, die innerhalb einer bestimmten Toleranz auf oder nahe der Linie liegen und für die Position der Linie relevant sind.
Klassifizierungsfunktionen analysieren die Steigung der infrage kommenden Kanäle und stufen sie als ansteigend, abfallend oder horizontal ein, was die Filterung und die Erkennung von Tendenzsignalen unterstützt. Funktionen zur Einstufung der Berührungsstärke werten die Anzahl der Berührungen aus und stufen die Kanäle als „hohe“, „mittlere“ oder „niedrige“ Stärke ein, was dabei hilft, weniger zuverlässige Strukturen herauszufiltern. Das gesamte System umfasst eine umfassende Debugging-Infrastruktur, die Entscheidungspunkte, Berechnungen und Filterergebnisse protokolliert, wodurch es für Entwickler und Händler einfacher wird, Parameter zu optimieren, Probleme zu beheben und den Entscheidungsprozess nachzuvollziehen.
//+------------------------------------------------------------------+ //| Calculate the slope between two swing points | //+------------------------------------------------------------------+ double CalculateSlope(const SwingPoint &a,const SwingPoint &b) { double deltaTime = (b.time - a.time); if(deltaTime == 0) return(0); return (b.price - a.price)/deltaTime; } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Count touches on a trendline considering only swings on relevant side | //+------------------------------------------------------------------+ int CountTouchesOnLine(const SwingPoint &a,const SwingPoint &b, const SwingPoint &swings[],int swingCount, bool isUpperLine,double tolerance, int recentBars,int &recentCount) { int touches = 2; // the two anchor swings recentCount = 0; double timeDiff = (double)(b.time - a.time); if(timeDiff <= 0) return touches; double slope = (b.price - a.price) / timeDiff; for(int i=0; i<swingCount; i++) { if(swings[i].time == a.time || swings[i].time == b.time) continue; if(swings[i].time < a.time || swings[i].time > b.time) continue; double linePrice = a.price + slope * (swings[i].time - a.time); double distance = isUpperLine ? linePrice - swings[i].price : swings[i].price - linePrice; bool correctSide = (isUpperLine && distance >= -tolerance) || (!isUpperLine && distance >= -tolerance); if(correctSide && MathAbs(distance) <= tolerance) { touches++; if(swings[i].barIndex <= recentBars) recentCount++; } } return touches; } //+------------------------------------------------------------------+
Alle Analysephasen basieren auf klar definierten Datenstrukturen wie SwingPoint, Channel und BreakoutInfo. Dieser strukturierte Ansatz sorgt für eine klare Zuordnung der Datenverantwortung und eine klare Trennung der Zuständigkeiten zwischen den Modulen. Anstatt reine Preiswerte zwischen Funktionen zu übergeben, werden gekapselte Objekte übertragen, wodurch die Datenintegrität gewährleistet und das Risiko logischer Inkonsistenzen verringert wird. Dieser Ansatz verbessert die Wartbarkeit und ermöglicht zukünftige Systemerweiterungen – wie beispielsweise die Mehrkanalverfolgung oder die Multisymbol-Anpassung – ohne eine Umstrukturierung der Architektur.
Datenfluss und Interaktion

Der Datenfluss beginnt mit dem Swing-Point-Erkennungsmodul, das jüngste Kursdaten analysiert, um signifikante Swings zu ermitteln – lokale Hochs und Tiefs, die die Marktstruktur bestimmen. Diese Swing-Punkte dienen als Eingabe für die „Channel Construction & Scoring Engine“, die umfassend nach dem statistisch signifikantesten Parallelkanal sucht, der zu diesen Swings passt. Das System bewertet jeden Kandidaten anhand der Anzahl der Berührungen, der Aktualität und der Stärke und vergibt entsprechend Punkte. Der Kanal mit der höchsten Punktzahl wird anschließend an das Visualisierungsmodul weitergeleitet, das die Trendlinien mit einer deutlichen Verlängerung in die Zukunft sowie informativen Beschriftungen und Markierungen darstellt.
Gleichzeitig projiziert die „Breakout Detection & Confirmation Engine“ diese Trendlinien auf die Echtzeitdaten und überwacht kontinuierlich, ob es zu Überschreitungen kommt, die auf Ausbrüche hindeuten könnten. Wenn sich ein potenzieller Ausbruch abzeichnet, werden mehrere Filter – basierend auf Volatilität, strukturellen Brüchen, Liquidität und Volatilitätsausweitung – angewendet, um das Ereignis zu validieren. Erst nachdem alle Filter durchlaufen wurden, generiert das System ein bestätigtes Handelssignal – entweder sofort oder nach einer Bestätigung durch einen Retest.
Die Signalverwaltungs- und Persistenzschicht stellt sicher, dass diese Signale zusammen mit ihren visuellen Darstellungen dauerhaft gespeichert und auch nach dem Neuladen der Charts zuverlässig angezeigt werden. Es verwaltet den Lebenszyklus aller grafischen Objekte – löscht bei jedem Tick temporäre Objekte und verwaltet permanente Signale und Zonen. Dadurch wird sichergestellt, dass Händler stets einen klaren, aktuellen visuellen Anhaltspunkt und eine zuverlässige Aufzeichnung bestätigter Signale haben.
Während dieses gesamten Prozesses werden die Daten anhand strukturierter Datentypen organisiert und durchlaufen dabei verschiedene Stufen – von rohen Swing-Punkten über potenzielle Kanäle bis hin zu bestätigten Signalen –, wobei sich jedes Modul auf einen bestimmten Aspekt der Analyse konzentriert. Dieser strukturierte Datenfluss gewährleistet, dass das System transparent und anpassungsfähig bleibt und qualitativ hochwertige, validierte Ausbruchsignale liefern kann.
Ausführungslebenszyklus und Ereignisbehandlung
Der Expert Advisor hält sich strikt an das ereignisgesteuerte Ausführungsmodell von MetaTrader 5. Die Initialisierung erfolgt in OnInit(), wo Indikator-Handles (wie z. B. ATR), Konfigurationsparameter und Präfixe für die Bezeichnungen der Grafiken vorbereitet werden. Alle persistenten Arrays werden in dieser Phase zugewiesen, um sicherzustellen, dass die Struktur bereit ist, bevor die Marktverarbeitung beginnt.
Der zentrale Analyse-Workflow wird innerhalb von OnTick() ausgeführt. Um jedoch die Recheneffizienz zu gewährleisten, werden strukturelle Neuberechnungen – wie beispielsweise die Swing-Erkennung und die Kanalrekonstruktion – nur dann durchgeführt, wenn eine neue Bar erkannt wird. Dies wird erreicht, indem der Zeitstempel der zuletzt verarbeiteten Bar gespeichert und mit der Eröffnungszeit der aktuellen Bar verglichen wird (siehe die Variable static datetime lastBarTime im OnTick()-Codeausschnitt aus dem Unterabschnitt *Breakout Detection & Confirmation Engine*). Indem das System die rechenintensive Logik hinter die Erkennung einer neuen Bar verschiebt, vermeidet es redundante Verarbeitungsschritte bei jedem Tick und reagiert dennoch sofort auf Breakout-Bedingungen.
Wenn der EA entfernt oder neu kompiliert wird, führt OnDeinit() eine kontrollierte Bereinigung der Grafikobjekte und Indikator-Handles durch, um sicherzustellen, dass keine verwaisten Objekte im Chart verbleiben. Dieses disziplinierte Lebenszyklusmanagement sorgt für mehr Stabilität, Effizienz und ein vorhersehbares Verhalten bei wiederholten Neuinitialisierungen.
Tests und Ergebnisse
In diesem Abschnitt wird der Testprozess beschrieben, mit dem die Leistung und Zuverlässigkeit des Tools bewertet wurden. Die Tests wurden aus zwei sich ergänzenden Perspektiven durchgeführt:
1) Live-Tests auf Demo-Charts in Echtzeit
Das Tool wurde unter Echtzeitbedingungen auf einem Demo-Chart eingesetzt, um seine Reaktionsgeschwindigkeit, Genauigkeit und Stabilität bei aktuellen Marktbewegungen zu überprüfen. In dieser Phase wurde überprüft, ob das System in der Lage ist, echte Ausbrüche zu erkennen, Fehlsignale herauszufiltern und in einem dynamischen Umfeld eindeutige visuelle Warnmeldungen zu generieren.
- Live-Test: EURUSD (H1)
Das folgende Chart veranschaulicht einen klassischen Ausbruch aus einem bärischen Parallelkanal, den das System Mitte Februar 2026 auf dem EURUSD-H1-Chart erfasst hat, und demonstriert damit die Wirksamkeit der modularen Architektur unter realitätsnahen Bedingungen.

Der Chart zeigt einen klar definierten absteigenden (bärischen) Parallelkanal, der sich über mehrere Tage (etwa vom 11. bis 17. Februar 2026) gebildet hat. Die obere Grenze (grüne Linie) verbindet die jüngsten Swing-Hochs, während die untere Grenze parallel dazu verläuft und dabei mehrere Swing-Tiefs berücksichtigt. Zu den vom Indikator generierten zentralen visuellen Elementen gehören:
- Swing-Punkte – gekennzeichnet durch rote Kreise (Höchststände) und grüne Kreise (Tiefststände), gefiltert anhand einer auf dem ATR basierenden Mindestgröße der Swings, um unbedeutende Swings auszuschließen.
- Kanal-Linien – nach vorn verlängert (über „LineExtensionBars“), die abwärtsgerichtete Neigung deutlich veranschaulichen und von „ClassifyChannel()“ als „DESCENDING“ klassifiziert werden.
- Berührungsindikatoren – An beiden Rändern sind mehrere Berührungen zu erkennen, was zu einem hohen Kanalwert und einer Stärkeeinstufung von MITTEL/HOCH beiträgt.
- Ausbruchsignal – Ein deutlich sichtbarer roter Abwärtspfeil befindet sich in der Nähe des Schlusskurses der Kerze vom 18. Februar im Bereich von 1,1832–1,1820 und wurde erst ausgelöst, nachdem der Kurs deutlich unterhalb der unteren Kanalgrenze geschlossen hatte.
Dieses Beispiel verdeutlicht, wie das System Swing-Erkennung, Kanalbildung, Breakout-Bestätigung und dauerhafte visuelle Signale miteinander verbindet, um präzise, umsetzbare Informationen in Echtzeit-Handelsszenarien zu liefern.
2) Historisches Backtesting
Es wurde ein umfassender Backtest anhand historischer Datensätze durchgeführt, um das Tool unter verschiedenen Marktbedingungen zu bewerten. Im Mittelpunkt des Verfahrens standen die Messung der Genauigkeit des Tools bei der Erkennung gültiger Ausbrüche, seiner Falschsignalquote sowie von Leistungskennzahlen wie der Gewinnquote und dem Risiko-Ertrags-Verhältnis.
- Backtest: EURUSD (H1)
Das folgende Diagramm veranschaulicht die Backtesting-Performanz des EA. Das System erkennt zuverlässig wichtige Wendepunkte und bildet stabile Parallelkanäle, während geringfügige Swings herausgefiltert werden. Sowohl bullische als auch bärische Ausbrüche werden zuverlässig erfasst, wobei bestätigte Signale durch Pfeile deutlich gekennzeichnet sind.

Insgesamt bestätigen die Backtesting-Ergebnisse die Fähigkeit des EAs, strukturelle Genauigkeit zu wahren, Ausbrüche zu validieren und klare visuelle Hinweise in verschiedenen historischen Marktszenarien zu liefern, was die Robustheit und Zuverlässigkeit des Tools unterstreicht.
Schlussfolgerung
Die modulare Architektur dieses Systems verdeutlicht einen ganzheitlichen Ansatz zur Erkennung, Validierung und Visualisierung von Ausbrüchen aus parallelen Kanälen in MQL5. Durch sorgfältig strukturierte Komponenten – Swing-Erkennung, Kanalbildung, Ausbruchbestätigung, visuelle Signalisierung und adaptive Neuberechnung – gewährleistet das Tool sowohl Genauigkeit als auch Reaktionsfähigkeit unter Echtzeit-Marktbedingungen.
Live-Tests anhand von Demo-Charts bestätigten die Fähigkeit des Systems, aussagekräftige Ausbrüche zu erkennen und gleichzeitig Störsignale herauszufiltern, wodurch klare und umsetzbare visuelle Hinweise geliefert wurden. Ergänzende historische Backtests anhand mehrerer Datensätze bestätigten die Robustheit des EAs und zeigten eine konsistente Leistung bei der Identifizierung signifikanter Wendepunkte, der Bildung qualitativ robuster Kanäle und der zuverlässigen Signalisierung sowohl bullischer als auch bärischer Ausbrüche.
Durch die Einbeziehung dieser Ergebnisse bietet das System eine zuverlässige Grundlage für Trader, die eine präzise und strukturell fundierte Breakout-Analyse suchen. Die Kombination aus Echtzeit-Anpassungsfähigkeit, historischer Verlässlichkeit und kontinuierlichem visuellem Feedback gewährleistet, dass Nutzer das Marktverhalten sicher interpretieren und auf validierte Signale reagieren können, was das Tool zu einem vielseitigen und praktischen Hilfsmittel für die professionelle MQL5-Chartanalyse macht.
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/21443
Warnung: Alle Rechte sind von MetaQuotes Ltd. vorbehalten. Kopieren oder Vervielfältigen untersagt.
Dieser Artikel wurde von einem Nutzer der Website verfasst und gibt dessen persönliche Meinung wieder. MetaQuotes Ltd übernimmt keine Verantwortung für die Richtigkeit der dargestellten Informationen oder für Folgen, die sich aus der Anwendung der beschriebenen Lösungen, Strategien oder Empfehlungen ergeben.
Larry Williams’ Marktgeheimnisse (Teil 13): Automatisierung von Hidden-Smash-Day-Umkehrmustern
Einführung in MQL5 (Teil 42): Leitfaden für Einsteiger zur Dateiverarbeitung in MQL5 (IV)
Eine alternative Log-datei mit der Verwendung der HTML und CSS
Trading-Disziplin in Code umsetzen (Teil 2): Entwicklung eines MQL5-Systems zur Durchsetzung eines täglichen Handelslimits für alle Trades in MQL5
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.