
Entwicklung des Price Action Analysis Toolkit (Teil 21): Das Tool Market Structure Flip Detector
Inhalt
- Einführung
- Warum dieses Tool wichtig ist
- Gliederung des Aktionsplans
- Anatomie des Expertenberaters
- Quellcode-Auflistung
- Leistungsergebnisse
- Schlussfolgerung
Einführung
Dieser EA bewältigt eine der schwierigsten Herausforderungen im Handel: falsche Umkehrsignale. Eine unruhige Kursentwicklung wirft einfache Pivot-Routinen über den Haufen und führt dazu, dass Händler in die Falle von Zick-Zack-Bewegungen geraten. Der Market Structure Flip Detector löst dieses Problem, indem er den ATR in einen flexiblen Filter der Anzahl der Balken umwandelt. Er ignoriert geringfügige Schwankungen, erfasst nur gültige Hochs und Tiefs und markiert dann einen „bearish flip“, wenn ein höheres Hoch zu einem niedrigeren Hoch wird, oder einen „bullish flip“, wenn ein niedrigeres Tief zu einem höheren Tief wird. Auf dem Weg dorthin werden Sie Folgendes sehen:
- Der ATR wird in ein tiefes Maß umgewandelt, das sich in wilden Märkten ausdehnt und in ruhigen Märkten zusammenzieht.
- Pivots werden bestätigt, indem eine genaue Anzahl von Balken auf jeder Seite eines möglichen Hochs oder Tiefs abgetastet werden.
- Die Trendrichtung wird beibehalten, sodass Umschwünge erst nach dem Bruch der vorherigen Struktur ausgelöst werden.
- Signale werden auf dem Chart mit Pfeilen, Pivot-Beschriftungen und einem Live-Statistikfeld angezeigt, die die Anzahl der Flips und das Timing verfolgt.
Am Ende haben wir einen robusten EA, der das Marktrauschen durchbricht und nur die saubersten, regelbasierten Umkehrhinweise liefert, komplett mit Sound- und Push-Benachrichtigungen, wenn echte Flips auftreten.
Warum ist dieses Tool wichtig?
Falsche Umkehrsignale können mehr als die Hälfte aller Pivot-basierten Auslöser in unruhigen Märkten ausmachen, was zu einem häufigen Hin und Her und einer negativen Erwartungshaltung führt. Durch die Verknüpfung unseres Filters für Umkehrpunkte mit dem Average True Range (ATR), den Wilder 1978 einführte, um die Volatilität genauer zu messen als einfache Hoch-Tief-Spannen, passen wir die erforderliche „Tiefe“ für einen Umkehrpunkt in Echtzeit an. Wenn der ATR während volatiler Ausbrüche ansteigt, weitet sich unser Filter, um kleine, erratische Schwankungen zu ignorieren; wenn sich die Märkte beruhigen, wird er enger, um echte Wendungen sofort zu erfassen.Der True Range (TR) pro Balken ist definiert als:
ATR ist der n-periodische einfache gleitende Durchschnitt des TR (Standard n = 14)
Wir konvertieren ATR in eine Tiefe d der Balken über:
Eine Abwärts-Umkehr tritt ein, wenn wir zunächst ein höheres Hoch verzeichnen und der nächste hohe Umkehrpunkt dann unter diesen Höchststand fällt. Eine Aufwärtsbewegung funktioniert auch andersherum. Wenn wir davon ausgehen, dass die Renditen einer Normalverteilung mit einem Durchschnitt von Null und einer Varianz, die wir als „Volatilität im Quadrat“ bezeichnen, folgen, dann ist die Chance, dass ein einzelner Balken innerhalb einer Spanne von „zwei mal unserer Tiefeneinstellung plus eins“ der höchste ist, einfach eins über eben diese „zwei mal Tiefe plus eins“. Da wir unsere Tiefeneinstellung direkt mit der Marktvolatilität verknüpfen, indem wir die Volatilität als ATR geteilt durch die Quadratwurzel von einem halben pi schätzen, können wir die Rate der Fehlsignale direkt steuern. In der Praxis bedeutet dies, dass wir Eingaben wählen können, die das Rauschen auf etwa 5 % begrenzen.
Die TradeStation-Forschung hat gezeigt, dass ATR-basierte Pivot-Fenster die von Rauschen getriebenen Handelsgeschäfte um ~40% reduzieren und den Nettogewinn um ~22% über 5 Jahre auf S&P 500-Daten steigern. QuantifiedStrategies.com berichtet, dass ATR-gefilterte Umkehrpunkte die Trefferquote von ~35% auf ~58% verbessern und das durchschnittliche Gewinn-Risiko-Verhältnis von ~1,1 auf ~1,8 in Backtests auf EURUSD und ES-Futures erhöhen. Das Feedback der Community auf TradingView hebt hervor, dass ATR-gefensterte Pivot-Tools eng mit institutionellen Orderflow-Breaks übereinstimmen, insbesondere auf 1-H- und 4-H-Charts.
Gliederung des Aktionsplans
Dieser EA filtert Marktrauschen heraus, indem er den aktuellen ATR-Wert in ein flexibles „Tiefen“-Fenster umwandelt, das bei volatilen Bedingungen breiter und bei ruhigen Bedingungen schmaler ist, und dann jedes Hoch oder Tief eines geschlossenen Balkens mit seinen Nachbarn innerhalb dieses Fensters vergleicht. Er merkt sich die letzten beiden bestätigten Hochs und Tiefs und verfolgt ein einfaches Bias-Flag, die auf „aufwärts“ umschaltet, wenn ein neues Hoch das vorherige übersteigt, oder auf „abwärts“, wenn ein neues Tief unter sein vorheriges fällt. Wenn sich die Marktstruktur umkehrt, d. h. wenn in einem Aufwärtstrend der letzte Höchststand niedriger ist als der vorherige Höchststand (bearish flip) oder in einem Abwärtstrend der letzte Tiefststand höher ist als der vorherige Tiefststand (bullish flip), lässt der EA einen farbigen Pfeil auf dem Chart erscheinen, kennzeichnet beide Pivots, aktualisiert ein Live-Statistikfeld und kann Ton- oder Push-Warnungen auslösen. Dieser Ansatz stellt sicher, dass Sie nur echte Umkehrungen wie „Hoch-Hoch zu Tief-Hoch“ oder „Tief-Tief zu Hoch-Tief“ sehen.
Bearish Flip
Ein Aufwärtstrend ist erkennbar, wenn der Kurs zwei aufeinanderfolgende höhere Hochs erreicht. Der Expert Advisor (EA) sucht anschließend nach einem hohen Umkehrpunkt, der niedriger ist als der vorherige hohe Umkehrpunkt. Ein hoher Umkehrpunkt ist definiert als der höchste Punkt innerhalb eines Fensters, das auf der Average True Range (ATR) basiert. Befindet sich der EA in einem „Aufwärts“-Zustand und erkennt dieses tiefere Hoch, markiert er den entsprechenden Balken mit einem roten Pfeil mit der Aufschrift „LH“. Zusätzlich zu diesem visuellen Hinweis generiert der EA eine Warnung und zeichnet den Abwärts-Umschwung auf, was signalisiert, dass die Verkäufer beginnen, die Kontrolle zu übernehmen.
Bullish Flip
Ein Abwärtstrend entsteht, wenn der Kurs zwei aufeinanderfolgende Tiefs verzeichnet. Anschließend ermittelt der Expert Advisor (EA) einen tiefen Umkehrpunkt, der über dem vorherigen tiefen Umkehrpunkt liegt. Ein tiefer Umkehrpunkt ist definiert als der niedrigste Punkt innerhalb eines Fensters, das auf der Average True Range (ATR) basiert. Befindet sich der EA in einem „Abwärts“-Zustand und erkennt dieses höhere Tief, zeichnet er einen grünen Pfeil mit der Aufschrift „HL“ auf den entsprechenden Balken. Darüber hinaus generiert es eine Warnmeldung und zeichnet die Aufwärtsbewegung auf, um eine mögliche Rückkehr des Kaufinteresses anzuzeigen.
Anatomie des Expert Advisors
Wenn wir eine beliebige MQL5-Datei starten, fügen wir #property-Zeilen hinzu, um die Szene festzulegen. Hier aktivieren wir die strikte Kompilierung, damit der Compiler alle unsicheren Casts oder veralteten Aufrufe erkennt. Wir fügen auch unsere Copyright-, Link- und Versions-Tags ein, damit jeder, der unseren Code liest, weiß, wer ihn geschrieben hat, wo er weitere Details finden kann und welche Iteration er gerade sieht. Diese Zeilen haben keinen Einfluss auf die Logik; sie sind unsere Art, die Identität der Datei zu markieren.
#property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com/en/users/lynnchris" #property version "1.0" #property strict
Als Nächstes legen wir alle Einstellungen offen, die ein Händler möglicherweise ändern möchte. Die ersten drei Eingaben bestimmen, wie wir Pivots mit ATR erkennen.
- InpAtrPeriod legt fest, wie viele Balken in die ATR-Berechnung eingehen. Eine kurze Spanne (z. B. 7) reagiert schnell, kann aber Rauschen auffangen. Eine längere Spanne (z. B. 21) glättet Spitzen auf Kosten der Verzögerung.
- InpAtrMultiplier wandelt diesen ATR-Bereich in eine Mindestschwingbreite um. Bei 1,0 benötigen wir eine ATR-Bewegung, um einen Pivot zu markieren. Wenn wir den Wert auf 1,5 oder 2,0 erhöhen, wird der Filter noch selektiver.
- InpAtrLoosenFactor skaliert diese Breite nach unten zwischen 0 und 1. Ein Faktor von 0,5 halbiert die Anforderung, sodass Pivots früher angezeigt werden, was bei geringer Volatilität hilfreich sein kann.
Als Nächstes wird das Chartlayout behandelt.
- InpAutoShift reserviert leere Balken auf der rechten Seite, wenn neue Balken erscheinen.
- InpShiftBars legt fest, wie viele leere Balken übrig bleiben sollen (standardmäßig fünf).
Durch diesen einfachen Abstand wird verhindert, dass unsere Pfeile, Beschriftungen und Statistiken die Kursbewegung überlagern.
Schließlich bieten wir zwei Warnmethoden an:
- InpEnableSound lässt den EA bei jedem Umkehrpunkt eine WAV-Datei abspielen.
- InpSoundFile ist der Ort, an dem Sie die Datei aus Ihrem MetaTrader 5 Sounds-Ordner auswählen.
- InpEnablePush sendet eine Push-Nachricht an Ihre MetaTrader 5 Mobile App.
Mit diesen Optionen können Sie wählen, ob Sie einen Alarm auf Ihrem Desktop hören, einen Ping auf Ihrem Telefon erhalten oder beides.
input int InpAtrPeriod = 14; // How many bars for ATR input double InpAtrMultiplier = 1.0; // Scale ATR into bar‑depth input double InpAtrLoosenFactor = 0.5; // Optional: loosen the swing filter input bool InpAutoShift = true; // Push bars left for visibility input int InpShiftBars = 5; // Number of bars for right margin input bool InpEnableSound = true; // Play a sound on flip input string InpSoundFile = "alert.wav"; input bool InpEnablePush = false; // Send push notifications
Wenn der EA startet, prüft OnInit zunächst InpAutoShift und ruft, falls aktiviert, ChartSetInteger mit CHART_SHIFT und InpShiftBars auf, um neue Balken nach links zu schieben und freien Platz für Anmerkungen zu reservieren. Dann fordert er über iATR ein Handle für den in MetaTrader eingebauten ATR-Indikator an, speichert es in atrHandle und bricht sofort mit INIT_FAILED ab, wenn das Handle ungültig ist. Schließlich wird ein Ecklabel (ein OBJ_LABEL mit dem Namen panelName) erstellt, an der oberen linken Ecke angeheftet, horizontal und vertikal um 10 Pixel versetzt, die Schriftgröße auf 10 und die Farbe auf gelb gesetzt und INIT_SUCCEEDED zurückgegeben, um zu bestätigen, dass der ATR-Datenzugriff und das Statistik-Panel für OnTick bereit sind.
int OnInit() { if(InpAutoShift) ChartSetInteger(0, CHART_SHIFT, InpShiftBars); atrHandle = iATR(_Symbol, _Period, InpAtrPeriod); if(atrHandle == INVALID_HANDLE) return INIT_FAILED; ObjectCreate(0, panelName, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, panelName, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, panelName, OBJPROP_XDISTANCE, 10); ObjectSetInteger(0, panelName, OBJPROP_YDISTANCE, 10); ObjectSetInteger(0, panelName, OBJPROP_FONTSIZE, 10); ObjectSetInteger(0, panelName, OBJPROP_COLOR, clrYellow); return INIT_SUCCEEDED; }
Immer wenn wir den EA entfernen oder MetaTrader 5 herunterfahren, löscht OnDeinit alle Pfeile und Textobjekte, die wir erstellt haben, löscht die Beschriftung und gibt den ATR-Handle frei. Dies vermeidet Unordnung und setzt Ressourcen frei.
void OnDeinit(const int reason) { ObjectsDeleteAll(0, -1, OBJ_ARROW); ObjectsDeleteAll(0, -1, OBJ_TEXT); ObjectDelete(0, panelName); if(atrHandle != INVALID_HANDLE) IndicatorRelease(atrHandle); }
In unserem OnTick verhindern wir, dass unsere Pivot-Logik bei jeder einzelnen Preisaktualisierung ausgeführt wird, indem wir eine statische Datumsangabe lastBareinführen. Wir holen thisBar mit iTime(...,1), das die Eröffnungszeit des zuletzt geschlossenen Balkens liefert, und vergleichen sie mit lastBar. Wenn sie sich nicht verändert hat, wissen wir, dass wir uns immer noch in derselben Kerze befinden und kehren einfach zurück. Sobald thisBar abweicht, aktualisieren wir lastBar und fahren fort.
Dann rufen wir CopyBuffer auf dem ATR-Handle auf, um nur den letzten ATR-Wert abzurufen. Wenn dieser Aufruf fehlschlägt, brechen wir ab, um die Arbeit mit ungültigen Daten zu vermeiden. Mit einer gültigen ATR in der Hand berechnen wir unsere „Tiefe“ der Umkehrpunkte, indem wir die ATR-Kurseinheiten in eine Balkenanzahl umwandeln. Wir dividieren durch den kleinsten Preisschritt (SYMBOL_POINT), multiplizieren mit InpAtrMultiplier und InpAtrLoosenFactor und erzwingen dann mit MathMax ein Minimum von einem Balken. Dadurch erhalten wir eine dynamische Tiefe, die sich vergrößert, wenn die Volatilität ansteigt (was größere Ausschläge zur Markierung von Pivots erfordert), und sich verkleinert, wenn sich der Markt beruhigt (was engere Ausschläge zulässt), bevor wir an die eigentlichen Pivot-Erkennungsfunktionen weitergeben.
void OnTick() { static datetime lastBar=0; datetime thisBar = iTime(_Symbol,_Period,1); if(thisBar == lastBar) return; lastBar = thisBar; double atrBuf[]; if(CopyBuffer(atrHandle, 0, 1, 1, atrBuf) <= 0) return; double atr = atrBuf[0]; int depth = MathMax(1, int(atr / SymbolInfoDouble(_Symbol, SYMBOL_POINT) * InpAtrMultiplier * InpAtrLoosenFactor)); // … pivot checks follow … }
Wenn die Tiefe definiert ist, führen wir zwei einfache Schleifen durch, um die Umkehrpunkte zu überprüfen. IsSwingHigh(1, depth) prüft, ob kein Balken innerhalb der Tiefe der Balken auf beiden Seiten das Kandidatenhoch überschreitet; IsSwingLow tut das Gegenteil für die Tiefs. Wenn wir ein neues Hoch oder Tief finden, verschieben wir lastHigh in prevHigh (und dasselbe für Tiefststände) und zeichnen den Zeitstempel auf. Die Verfolgung des vorherigen und des aktuellen Umkehrpunktes ermöglicht uns den nächsten Vergleich.
bool newHigh = IsSwingHigh(1, depth); bool newLow = IsSwingLow (1, depth); double h = iHigh(_Symbol,_Period,1), l = iLow(_Symbol,_Period,1); if(newHigh) { prevHigh = lastHigh; prevHighTime = lastHighTime; lastHigh = h; lastHighTime = thisBar; } if(newLow) { prevLow = lastLow; prevLowTime = lastLowTime; lastLow = l; lastLowTime = thisBar; }
Sobald wir unsere Umkehrpunkte haben, aktualisieren wir structState, um die Trendausrichtung widerzuspiegeln: ein höheres Hoch setzt den Zustand 1 (Abwärts-Umkehr als Nächstes möglich), ein niedrigeres Tief setzt den Zustand 2 (Aufwärts-Umkehr als Nächstes möglich). Dann prüfen wir, ob es sich um eine tatsächliche Umkehr handelt: Wenn im Zustand 1 das neue Hoch unter dem vorherigen Hoch liegt, handelt es sich um eine Abwärts-Umkehr; im Zustand 2, wenn das neue Tief über das vorherige Tief steigt, handelt es sich um eine Aufwärts-Umkehr. Wenn wir auf eine Umkehr treffen, werden unsere Plot- und Benachrichtigungsaufrufe ausgelöst und unsere Zähler angestoßen.
// Update bias if(newHigh && prevHigh>0 && lastHigh > prevHigh) structState = 1; if(newLow && prevLow>0 && lastLow < prevLow) structState = 2; // Bearish flip if(newHigh && structState==1 && lastHigh < prevHigh) { PlotArrow(...); PlotLabel(...); Notify(...); if(countBear>0) sumBearInterval += (lastHighTime - prevLowTime)/60.0; countBear++; } // Bullish flip if(newLow && structState==2 && lastLow > prevLow) { PlotArrow(...); PlotLabel(...); Notify(...); if(countBull>0) sumBullInterval += (lastLowTime - prevHighTime)/60.0; countBull++; }
Wir kapseln alle Zeichnungen auf dem Chart in zwei Hilfsfunktionen - PlotArrow und PlotLabel - um sowohl Effizienz als auch Übersichtlichkeit zu gewährleisten. Innerhalb jeder Funktion rufen wir zunächst ObjectFind(0, name) auf, das nach einem vorhandenen Chartobjekt anhand seines eindeutigen Namens sucht; dieser Vorgang benötigt O(n)-Zeit im Verhältnis zur Anzahl der Objekte ab, ist aber auf modernen Rechnern schnell genug für gelegentliche Überprüfungen pro Balken. Wenn das Objekt noch nicht existiert (ObjectFind gibt -1 zurück), wird es genau einmal mit ObjectCreate erstellt, wobei der entsprechende Objekttyp gewählt wird (ein Pfeil für PlotArrow, ein Textlabel für PlotLabel).
Anschließend passen wir die Eigenschaften an: Für Pfeile setzen wir OBJPROP_ARROWCODE, um die gewünschte Glyphe auszuwählen (z. B. Wingdings-Code 234 für einen roten Pfeil nach unten), und OBJPROP_COLOR, um den Farbton festzulegen; für Beschriftungen setzen wir OBJPROP_TEXT mit unserer Beschriftung (z. B. „LH“ oder „HL“) sowie Versatz und Schriftgröße. Indem wir wiederholte Aufrufe von ObjectCreate vermeiden, verhindern wir Leistungseinbußen und Speicherüberlastung, die auftreten würden, wenn sich im Laufe der Zeit Hunderte oder Tausende von identischen Objekten ansammeln würden. Dieses Muster stellt auch sicher, dass jede Pivot-Marke einen stabilen, vorhersehbaren Bezeichner hat. Wenn Sie also später ihre OBJPROP_ZORDER (Zeichnungspriorität) anpassen oder sie unter bestimmten Bedingungen löschen möchten, können Sie sich mit absoluter Sicherheit auf den Namen beziehen, ohne versehentlich andere Chartelemente zu beeinflussen.
void PlotArrow(string name, datetime t, double price, int code, color c) { if(ObjectFind(0, name) < 0) { ObjectCreate(0, name, OBJ_ARROW, 0, t, price); ObjectSetInteger(0, name, OBJPROP_ARROWCODE, code); ObjectSetInteger(0, name, OBJPROP_COLOR, c); } } // PlotLabel is identical, but creates OBJ_TEXT and sets OBJPROP_TEXT.
Nach jedem Balken wird die Beschriftung panelName neu erstellt und angezeigt:
- Die aktuelle Tiefe der Umkehrpunkte
- Gesamtzahl aller hohen und tiefen Umkehrpunkte
- Durchschnittliche Zeit (in Minuten) zwischen zwei Umkehrpunkten (sobald wir mindestens zwei haben).
So erhalten Sie eine sofortige Rückmeldung darüber, wie oft Strukturbrüche unter den von Ihnen gewählten ATR-Einstellungen auftreten.
string txt = StringFormat("Depth: %d\nBull Flips: %d\nBear Flips: %d", depth, countBull, countBear); if(countBull>1) txt += "\nAvg HL Int: " + DoubleToString(sumBullInterval/(countBull-1),1) + "m"; if(countBear>1) txt += "\nAvg LH Int: " + DoubleToString(sumBearInterval/(countBear-1),1) + "m"; ObjectSetString(0, panelName, OBJPROP_TEXT, txt);
Schließlich fasst unsere Funktion Notify(msg) alle Warnmethoden an einer Stelle zusammen. Wir rufen immer Alert(msg) für ein MetaTrader 5-Popup auf und spielen dann optional einen Ton ab (PlaySound) oder senden einen Push (SendNotification), je nach Ihren Eingaben. Durch die Zentralisierung ist es ganz einfach, später E-Mail- oder Webhook-Warnungen hinzuzufügen.
void Notify(string msg) { Alert(msg); if(InpEnableSound) PlaySound(InpSoundFile); if(InpEnablePush) SendNotification(msg); }
Quellcode-Auflistung
//+------------------------------------------------------------------+ //| Market Structure Flip Detector EA| //| Copyright 2025, MetaQuotes Ltd.| //| https://www.mql5.com/en/users/lynnchris| //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com/en/users/lynnchris" #property version "1.0" #property strict //--- user inputs input int InpAtrPeriod = 14; // ATR lookback input double InpAtrMultiplier = 1.0; // ATR to swing depth factor (lower = looser) input double InpAtrLoosenFactor = 0.5; // Loosen factor for ATR confirmation (0-1) input bool InpAutoShift = true; // Auto-enable chart right shift input int InpShiftBars = 5; // Bars for right margin input bool InpEnableSound = true; input string InpSoundFile = "alert.wav"; input bool InpEnablePush = false; //--- global vars string panelName = "FlipPanel"; int atrHandle; int structState = 0; double prevHigh=0, lastHigh=0; datetime prevHighTime=0, lastHighTime=0; double prevLow=0, lastLow=0; datetime prevLowTime=0, lastLowTime=0; int countBull=0, countBear=0; double sumBullInterval=0, sumBearInterval=0; //+------------------------------------------------------------------+ int OnInit() { if(InpAutoShift) ChartSetInteger(0, CHART_SHIFT, InpShiftBars); atrHandle = iATR(_Symbol, _Period, InpAtrPeriod); if(atrHandle == INVALID_HANDLE) return(INIT_FAILED); ObjectCreate(0, panelName, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, panelName, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, panelName, OBJPROP_XDISTANCE, 10); ObjectSetInteger(0, panelName, OBJPROP_YDISTANCE, 10); ObjectSetInteger(0, panelName, OBJPROP_FONTSIZE, 10); ObjectSetInteger(0, panelName, OBJPROP_COLOR, clrYellow); ObjectSetInteger(0, panelName, OBJPROP_BACK, false); ObjectSetInteger(0, panelName, OBJPROP_ZORDER, 1); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ void OnDeinit(const int reason) { ObjectsDeleteAll(0, -1, OBJ_ARROW); ObjectsDeleteAll(0, -1, OBJ_TEXT); ObjectDelete(0, panelName); if(atrHandle != INVALID_HANDLE) IndicatorRelease(atrHandle); } //+------------------------------------------------------------------+ void OnTick() { static datetime lastBar=0; datetime thisBar = iTime(_Symbol,_Period,1); if(thisBar==lastBar) return; lastBar=thisBar; double atrBuf[]; if(CopyBuffer(atrHandle,0,1,1,atrBuf)<=0) return; double atr = atrBuf[0]; // loosen ATR confirmation by InpAtrLoosenFactor (0-1) double rawDepth = atr/SymbolInfoDouble(_Symbol,SYMBOL_POINT)*InpAtrMultiplier; int depth = MathMax(1, (int)(rawDepth * InpAtrLoosenFactor)); bool newHigh=false,newLow=false; double h=iHigh(_Symbol,_Period,1), l=iLow(_Symbol,_Period,1); if(IsSwingHigh(1,depth)) { prevHigh = lastHigh; prevHighTime = lastHighTime; lastHigh = h; lastHighTime = thisBar; newHigh = true; } if(IsSwingLow(1,depth)) { prevLow = lastLow; prevLowTime = lastLowTime; lastLow = l; lastLowTime = thisBar; newLow = true; } double off = SymbolInfoDouble(_Symbol,SYMBOL_POINT)*10; // Bearish Flip: Lower High after a Higher High if(newHigh && structState==1 && prevHigh>0 && lastHigh<prevHigh) { // signal arrow and label at current LH PlotArrow("Bear_"+IntegerToString((int)lastHighTime), lastHighTime, lastHigh, 234, clrRed); PlotLabel("LH_"+IntegerToString((int)lastHighTime), lastHighTime, lastHigh+off, "LH", clrRed); // label the previous LH used for comparison PlotLabel("PrevLH_"+IntegerToString((int)prevHighTime), prevHighTime, prevHigh+off, "LH_prev", clrRed); Notify("Bearish Flip (LH) at "+TimeToString(lastHighTime,TIME_DATE|TIME_MINUTES)); if(countBear>0) sumBearInterval += (lastHighTime-prevLowTime)/60.0; countBear++; } // Bullish Flip: Higher Low after a Lower Low if(newLow && structState==2 && prevLow>0 && lastLow>prevLow) { // signal arrow and label at current HL PlotArrow("Bull_"+IntegerToString((int)lastLowTime), lastLowTime, lastLow, 233, clrLime); PlotLabel("HL_"+IntegerToString((int)lastLowTime), lastLowTime, lastLow-off, "HL", clrLime); // label the previous HL used for comparison PlotLabel("PrevHL_"+IntegerToString((int)prevLowTime), prevLowTime, prevLow-off, "HL_prev", clrLime); Notify("Bullish Flip (HL) at "+TimeToString(lastLowTime,TIME_DATE|TIME_MINUTES)); if(countBull>0) sumBullInterval += (lastLowTime-prevHighTime)/60.0; countBull++; } // update structure state if(newHigh && prevHigh>0 && lastHigh>prevHigh) structState = 1; if(newLow && prevLow>0 && lastLow <prevLow) structState = 2; // update panel stats string txt = "Depth: "+IntegerToString(depth)+"\n"; txt += "Bull Flips: "+IntegerToString(countBull)+"\n"; txt += "Bear Flips: "+IntegerToString(countBear); if(countBull>1) txt += "\nAvg HL Int: "+DoubleToString(sumBullInterval/(countBull-1),1)+"m"; if(countBear>1) txt += "\nAvg LH Int: "+DoubleToString(sumBearInterval/(countBear-1),1)+"m"; ObjectSetString(0, panelName, OBJPROP_TEXT, txt); } //+------------------------------------------------------------------+ bool IsSwingHigh(int shift,int depth) { double p = iHigh(_Symbol,_Period,shift); for(int i=shift-depth; i<=shift+depth; i++) if(i>=0 && iHigh(_Symbol,_Period,i) > p) return false; return true; } //+------------------------------------------------------------------+ bool IsSwingLow(int shift,int depth) { double p = iLow(_Symbol,_Period,shift); for(int i=shift-depth; i<=shift+depth; i++) if(i>=0 && iLow(_Symbol,_Period,i) < p) return false; return true; } //+------------------------------------------------------------------+ void PlotArrow(string nm,datetime t,double price,int code,color c) { if(ObjectFind(0,nm) < 0) { ObjectCreate(0, nm, OBJ_ARROW, 0, t, price); ObjectSetInteger(0, nm, OBJPROP_ARROWCODE, code); ObjectSetInteger(0, nm, OBJPROP_COLOR, c); ObjectSetInteger(0, nm, OBJPROP_WIDTH, 2); } } //+------------------------------------------------------------------+ void PlotLabel(string nm,datetime t,double price,string txt,color c) { if(ObjectFind(0,nm) < 0) { ObjectCreate(0, nm, OBJ_TEXT, 0, t, price); ObjectSetString(0, nm, OBJPROP_TEXT, txt); ObjectSetInteger(0, nm, OBJPROP_COLOR, c); ObjectSetInteger(0, nm, OBJPROP_FONTSIZE, 10); } } //+------------------------------------------------------------------+ void Notify(string msg) { Alert(msg); if(InpEnableSound) PlaySound(InpSoundFile); if(InpEnablePush) SendNotification(msg); } //+------------------------------------------------------------------+
Leistungsergebnisse
Im Folgenden werde ich die Ergebnisse unserer Tests sowohl unter Live-Marktbedingungen als auch bei den Backtests erläutern.
Live-Markt
Im obigen Chart erkennt der EA zunächst einen hohen Umkehrpunkt mit der Bezeichnung „LH_prev“, das zwei aufeinanderfolgende höhere Hochs widerspiegelt und eine Aufwärtsstruktur etabliert. Einige Balken später wird ein weiterer hoher Umkehrpunkt festgestellt, der das vorherige Hoch nicht übertrifft - dieses niedrigere Hoch innerhalb eines Aufwärtstrends veranlasst den EA, einen roten Pfeil und die Bezeichnung „LH“ an diesem Balken zu zeichnen. Dieses Abwärts-Signal zeigt den Zusammenbruch des Aufwärts-Momentums an und warnt davor, dass eine Abwärtsbewegung einsetzen könnte.
Gif von Live-Markt
Nachfolgend sehen Sie ein GIF, das die Leistung des EA für EURUSD zeigt. Wenn jede Ein-Minuten-Kerze schließt, verfolgt der EA die aufeinanderfolgenden Tiefs, bis er ein tiefen Umkehrpunkt findet, der höher als das vorherige Tief ist. Wenn dieses höhere Tief auftaucht, wird ein grüner HL-Pfeil angezeigt, der den Aufwärtstrend anzeigt. Im gleichen Moment wird die Kopfzeile aktualisiert - hier werden „12 BullFlips: 1 BearFlip: 2Avg Int: 108.0m“ angezeigt - um die aktualisierten Zählungen wiederzugeben. Dieser Clip veranschaulicht deutlich den Übergang von einer Abwärtsstruktur zu einer potenziellen Aufwärtsbewegung.
Backtests
Nachstehend finden Sie eine Tabelle mit den Ergebnissen der Stufenindexanalyse über mehrere Zeitrahmen hinweg. „Positive Signale“ sind solche, nach denen sich der Markt über einen längeren Zeitraum in die angegebene Richtung bewegt hat.
5-Minuten-Zeitrahmen
Signalart | Signale insgesamt | Positive Signale | Gewinnrate |
---|---|---|---|
Verkäufe (sell) | 56 | 39 | 70% |
Käufe (buy) | 53 | 44 | 83% |
15-Minuten-Zeitrahmen
Signalart | Signale insgesamt | Positive Signale | Gewinnrate |
---|---|---|---|
Verkäufe (sell) | 7 | 5 | 71% |
Käufe (buy) | 14 | 9 | 64% |
Die Zusammenfassung der Analysen zeigt, dass der Market Structure Flip Detector durchweg profitable Signale erzeugt, insbesondere in kürzeren Zeitrahmen. Die Erfolgsquote bei den Verkaufsvorbereitungen liegt bei 70 % und mehr, was die Wirksamkeit des Tools unterstreicht. Diese Errungenschaft stellt einen bedeutenden Fortschritt in der Automatisierung der Preisaktionsanalyse dar und bringt uns einem vollständig systematischen Handels-Toolkit mit geringer Latenzzeit näher.
Schlussfolgerung
Nachdem wir dieses Tool sowohl unter Live-Marktbedingungen als auch im Rahmen von Backtests entwickelt und getestet haben, zeigt unsere Analyse, dass es durchweg eine starke Leistung erbringt, insbesondere beim Scalping auf niedrigeren Zeitskalen, wo es beträchtliche Erträge erzielt. Es ist jedoch unerlässlich, Vorsicht walten zu lassen und die Signale mit zusätzlichen Bestätigungsmethoden zu validieren, bevor man einen Handel tätigt. Darüber hinaus ist das Testen des Tools mit verschiedenen Währungspaaren entscheidend, um herauszufinden, wo es sich am besten bewährt. Sie können die Eingabeparameter auch während des Tests anpassen, um die Leistung weiter zu optimieren.
Datum | Name des Tools | Beschreibung | Version | Aktualisierungen | Hinweis |
---|---|---|---|---|---|
01/10/24 | Chart Projector | Skript zur Überlagerung der Kursentwicklung des Vortages mit einem Ghost-Effekt. | 1.0 | Erste Veröffentlichung | Tool Nummer 1 |
18/11/24 | Analytical Comment | Er liefert Informationen zum Vortag in Tabellenform und nimmt die zukünftige Marktentwicklung vorweg. | 1.0 | Erste Veröffentlichung | Tool Nummer 2 |
27/11/24 | Analytics Master | Reguläre Aktualisierung der Marktmetriken alle zwei Stunden. | 1.01 | Zweite Veröffentlichung | Tool Nummer 3 |
02/12/24 | Analytics Forecaster | Reguläre Aktualisierung der Marktmetriken alle zwei Stunden mit Telegram-Integration. | 1.1 | Dritte Ausgabe | Tool Nummer 4 |
09/12/24 | Volatility Navigator | Der EA analysiert die Marktbedingungen anhand der Indikatoren Bollinger Bands, RSI und ATR. | 1.0 | Erste Veröffentlichung | Tool Nummer 5 |
19/12/24 | Mean Reversion Signal Reaper | Analysiert den Markt anhand der Strategie „Umkehr zur Mitte“ und liefert Signale. | 1.0 | Erste Veröffentlichung | Tool Nummer 6 |
9/01/25 | Signal Pulse | Analysator für mehrere Zeitrahmen. | 1.0 | Erste Veröffentlichung | Tool Nummer 7 |
17/01/25 | Metrics Board | Bedienfeld mit Taste für die Analyse. | 1.0 | Erste Veröffentlichung | Tool Nummer 8 |
21/01/25 | External Flow | Analytik durch externe Bibliotheken. | 1.0 | Erste Veröffentlichung | Tool Nummer 9 |
27/01/25 | VWAP | Volumengewichteter Durchschnittspreis | 1.3 | Erste Veröffentlichung | Tool Nummer 10 |
02/02/25 | Heikin Ashi | Trendglättung und Identifizierung von Umkehrsignalen | 1.0 | Erste Veröffentlichung | Tool Nummer 11 |
04/02/25 | FibVWAP | Signalerzeugung durch Python-Analyse | 1.0 | Erste Veröffentlichung | Tool Nummer 12 |
14/02/25 | RSI DIVERGENCE | Kursentwicklung versus RSI-Divergenzen | 1.0 | Erste Veröffentlichung | Tool Nummer 13 |
17/02/25 | Parabolic Stop and Reverse (PSAR) | Automatisierung der PSAR-Strategie | 1.0 | Erste Veröffentlichung | Tool Nummer 14 |
20/02/25 | Quarters Drawer Script | Einzeichnen der Ebenen der Viertel auf dem Chart | 1.0 | Erste Veröffentlichung | Tool Nummer 15 |
27/02/25 | Intrusion Detector | Erkennen und warnen, wenn der Preis ein Viertel-Niveau erreicht | 1.0 | Erste Veröffentlichung | Tool Nummer 16 |
27/02/25 | TrendLoom Tool | Analysepanel für mehrere Zeitrahmen | 1.0 | Erste Veröffentlichung | Tool Nummer 17 |
11/03/25 | Quarters Board | Bedienfeld mit Tasten zum Aktivieren oder Deaktivieren der Viertel-Ebenen | 1.0 | Erste Veröffentlichung | Tool Nummer 18 |
26/03/25 | ZigZag Analyzer | Zeichnen von Trendlinien mit dem ZigZag-Indikator | 1.0 | Erste Veröffentlichung | Tool Nummer 19 |
10/04/25 | Correlation Pathfinder | Plotten von Währungskorrelationen mit Python-Bibliotheken. | 1.0 | Erste Veröffentlichung | Tool Nummer 20 |
23/04/25 | Market Structure Flip Detector Tool | Erkennung von Marktstrukturschwankungen | 1.0 | Erste Veröffentlichung | Tool Nummer 21 |
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/17891
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.





- 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.
Hallo, ich verstehe nicht, warum du int i=shift-depth schreibst, könntest du nicht einfach int i=0 verwenden ?
Können Sie mir das bitte erklären? Danke!