English
preview
Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 16): Einführung in die Quarters Theory (II) - Intrusion Detector EA

Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 16): Einführung in die Quarters Theory (II) - Intrusion Detector EA

MetaTrader 5Handelssysteme | 20 Juni 2025, 12:19
16 0
Christian Benjamin
Christian Benjamin

Einführung

In unserem letzten Artikel haben wir Ihnen das Skript Quarters Drawer vorgestellt, ein Tool, mit dem Sie die Ebenen der Viertel (Quarter) visuell im Chart darstellen können, um die Marktanalyse intuitiver zu gestalten. Dieses Konzept leitet sich von der Quarter-Theorie ab, die ursprünglich von Ilian Yotov eingeführt wurde. Das erfolgreiche Zeichnen dieser Viertel hat sich als eine leistungsfähige Methode zur Vereinfachung der Preisaktionsanalyse erwiesen. Die manuelle Überwachung dieser Niveaus, da der Preis mit ihnen interagiert, erfordert jedoch viel Zeit und Aufmerksamkeit.

Um dieser Herausforderung zu begegnen, freue ich mich, den EA „Intrusion Detector“ vorstellen zu können, eine Lösung, die den Überwachungsprozess automatisiert. Dieser EA verfolgt kontinuierlich die Charts und erkennt, wenn der Preis ein beliebiges Viertel-Niveau erreicht, egal ob es sich um ein kleines, großes, Hauptviertel oder Überschreitungs-/Unterschreitungszonen (overshoot bzw. undershoot) handelt. Darüber hinaus bietet es sofortige Kommentare und Einblicke auf der Grundlage der Quarter-Theorie von Ilian Yotov und hilft jedem Händler, potenzielle Marktreaktionen zu antizipieren. In diesem Artikel werden wir zunächst das Tool „Quarters Drawer“ vorstellen, dann das Strategiekonzept und die MQL5-Implementierung näher erläutern, die Testergebnisse analysieren und abschließend die wichtigsten Erkenntnisse darlegen. Das nachstehende Inhaltsverzeichnis bietet einen strukturierten Überblick.

Inhalt



Rückblick auf den vorherigen Artikel

Ich werde nicht zu sehr auf diesen Abschnitt eingehen, da das Skript Quarters Drawer in unserem vorherigen Artikel ausführlich besprochen wurde. Wenn Sie es jedoch noch nicht gelesen haben, empfehle ich Ihnen dringend, den angegebenen Links zu folgen, um ein umfassendes Verständnis der grundlegenden Konzepte zu erlangen. In diesem Artikel ging es in erster Linie um die Automatisierung der Erstellung von Quartalszahlen, wodurch die Marktanalyse strukturierter und effizienter wurde.

Wie bereits erwähnt, wurde die Quarters-Theorie von Ilian Yotov entdeckt und später in der Handelsgemeinschaft eingeführt. Ein entscheidender Punkt, der im letzten Artikel vielleicht nicht genug betont wurde, ist, dass diese Theorie in hohem Maße auf Währungspaare anwendbar ist, was sie zu einem unverzichtbaren Instrument für Devisenhändler macht. Um ein besseres Verständnis der Funktionsweise dieser vierteljährlichen Ebenen zu erhalten, werfen Sie einen Blick auf das folgende Chart, das die Struktur der Theorie visuell darstellt.

Quarters Levels

Abb. 1. Level der Viertel

Unser Tool „Quarters Drawer“ lieferte bemerkenswerte Ergebnisse, indem es erfolgreich große Viertel, die Über- und Unterschreitungen und kleinere Viertel aufzeichnete. Noch wichtiger ist, dass wir festgestellt haben, dass der Preis durchgängig mit diesen Niveaus interagiert und auf sie reagiert, was die Legitimität und Wirksamkeit von Yotovs Theorie untermauert. Es handelte sich dabei nicht nur um eine theoretische Übung, sondern das Instrument bestätigte die Aussagekraft von Quartalswerten unter realen Marktbedingungen. Analysieren wir nun das nachstehende Chart, um einige unserer wichtigsten Erkenntnisse und Einsichten erneut zu betrachten.

Ergebnisse

Abb. 2. Ergebnisse


Strategiekonzept und MQL5-Implementierung

Zentrale Logik

Beim EA „Intrusion Detector“ geht es darum, psychologisch wichtige Kursniveaus mithilfe der Quartalstheorie zu ermitteln. Es unterteilt den Markt in Bereiche von 1000 Punkte, wobei die großen ganzen Zahlen als Basis dienen. Innerhalb dieser Bereiche werden große Quartale (250-Punkte-Zonen) und, falls aktiviert, kleine Quartale für eine noch feinere Granularität markiert. Der EA zeichnet auch Über- und Unterschreitungsbereiche, um Kursausdehnungen zu erkennen, die den Händler täuschen könnten. Bei jedem Tick wird der aktuelle Kurs gescannt und überprüft, ob er innerhalb einer bestimmten Toleranz (auch Fehlertoleranz genannt) gegen diese Schlüsselwerte stößt, und es werden Warnungen ausgelöst, wenn sich etwas tut.

Das Hauptziel besteht darin, potenzielle Wendepunkte, Ausbrüche oder vorgetäuschte Ausbrüche zu erkennen, bevor sie für alle anderen offensichtlich werden. Wenn sich der Kurs in der Nähe einer großen ganzen Zahl abkühlt, kennzeichnet der EA diese als wichtige Unterstützungs- oder Widerstandszone. Wenn er sich um die Marke von großen Viertel herum bewegt, deutet dies darauf hin, dass eine Bewegung von 250 Pips bevorstehen könnte. Überschreitungs- und Unterschreitungsbereiche? Sie helfen dabei, Fallen zu erkennen, in denen der Preis stark rückläufig sein könnte. Der EA stellt sicher, dass er keine Spam-Warnungen versendet, indem er das Eindringen verfolgt, und er aktualisiert ein sofortiges Kommentar-Panel, damit Sie immer wissen, was vor sich geht. Das Ganze ist so aufgebaut, dass Sie der Herde einen Schritt voraus sind, indem Sie die Theorie der Viertel praktisch und umsetzbar machen.

Umsetzung

In diesem EA beginnen wir mit einer Kopfzeile, die Metadaten über den EA enthält, wie z. B. seinen Namen („Intrusion Detector“), Angaben zum Copyright und einen Link zum Profil des Entwicklers. Die Direktiven #property spezifizieren diese Details und erzwingen strenge („strict“) Kompilierungsregeln, die sicherstellen, dass der Code den modernen MQL5-Standards entspricht.

//+------------------------------------------------------------------+
//|                                             Intrusion Detector   |
//|                             Copyright 2025, Christian Benjamin   |
//|                        https://www.mql5.com/en/users/lynnchris   |
//+------------------------------------------------------------------+
#property copyright "Christian Benjamin"
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.0"
#property strict

Als Nächstes definieren wir eine Reihe von Eingabeparametern, mit denen Sie das Verhalten des EA anpassen können, ohne den Code zu verändern. Zu den Parametern gehören numerische Werte wie MajorStep, der das Intervall zwischen den Hauptniveaus festlegt (und damit einen Bereich von 1000 PIP definiert), und AlertTolerance, der den Schwellenwert für die Erkennung des „Berührens“ eines bestimmten Niveaus durch den Kurs festlegt. Boolesche Eingaben steuern, ob der EA zusätzliche Linien, wie große und kleine Viertellinien, sowie Überschreitungsbereiche um diese Hauptniveaus herum zeichnet.

Darüber hinaus werden die Farbeinstellungen mit Hilfe von Hexadezimalwerten (oder vordefinierten Farben) definiert, um sicherzustellen, dass jeder Linientyp, ob Hauptlinie, großes Viertel, kleines Viertel oder Überschwinger, im Chart mit dem vorgesehenen visuellen Stil erscheint. Es folgen Linienstile und Einstellungen für die Linienstärke, mit denen wir das Aussehen der gezeichneten Linien weiter anpassen können.

Konfiguration Einstellungen

input double MajorStep          = 0.1000;   // Difference between Major Whole Numbers (defines the 1000-PIP Range)
input bool   DrawLargeQuarters  = true;     // Draw intermediate Large Quarter lines.
input bool   DrawSmallQuarters  = false;    // Draw Small Quarter lines.
input bool   DrawOvershootAreas = true;     // Mark overshoot/undershoot areas for Large Quarter lines.
input double AlertTolerance     = 0.0025;   // Tolerance for detecting a "touch"

  • MajorStep: Legt das Intervall zwischen den Hauptstufen fest (z. B. ein 1000-PIP-Bereich).
  • DrawLargeQuarters & DrawSmallQuarters: Boolesche Werte, die bestimmen, ob der EA zusätzliche Linien innerhalb des Bereichs zeichnen soll.
  • DrawOvershootAreas: Legt fest, ob zusätzliche Über- und Unterschreitungslinien in der Nähe der großen Viertelstufen gezeichnet werden sollen.
  • AlertTolerance: Gibt an, wie nahe der Kurs an ein Niveau herankommen muss (innerhalb von 0,0025), damit es als „Berührung“ gilt.

Farbeinstellungen:

input color  MajorColor         = 0x2F4F4F; // Dark Slate Gray for Major lines.
input color  LargeQuarterColor  = 0x8B0000; // Dark Red for Large Quarter lines.
input color  SmallQuarterColor  = 0x00008B; // Dark Blue for Small Quarter lines.
input color  OvershootColor     = clrRed;   // Red for overshoot/undershoot lines.

Für jeden Linientyp werden Farben definiert, damit sie beim Zeichnen im Chart visuell mit der Beschreibung übereinstimmen.

Einstellungen für Linienstil und Linienstärke

input ENUM_LINE_STYLE MajorLineStyle       = STYLE_SOLID;
input int    MajorLineWidth                 = 4;
input ENUM_LINE_STYLE LargeQuarterLineStyle  = STYLE_DOT;
input int    LargeQuarterLineWidth          = 3;
input ENUM_LINE_STYLE OvershootLineStyle     = STYLE_DASH;
input int    OvershootLineWidth             = 1;
input ENUM_LINE_STYLE SmallQuarterLineStyle  = STYLE_SOLID;
input int    SmallQuarterLineWidth          = 1;

Für jeden Linientyp (Hauptlinie, große Viertellinie, Überschreitung, kleine Viertellinie) gibt es Einstellungen für den Stil (durchgezogen, punktiert, gestrichelt) und die Breite.

Anpassbare Kommentarmeldungen

Diese Meldungen beschreiben die Bedeutung der einzelnen Niveaus, wenn der Preis sie „berührt“. Sie werden später zur Erstellung einer Kommentartabelle verwendet.

  • MajorSupportReason: Dies deutet darauf hin, dass es auf dem Markt eine wichtige Unterstützung gibt. Fällt der Kurs unter dieses Niveau, deutet dies auf eine Verschiebung der Handelsspanne hin, die zu weiteren Kursrückgängen führen kann.
  • MajorResistanceReason: Dies stellt einen kritischen Widerstand dar. Bricht der Kurs über diesen Widerstand, könnte dies den Beginn einer neuen Handelsspanne signalisieren, was zu einer Aufwärtsbewegung führen könnte.
  • LargeQuarterReason: Diese Aussage weist darauf hin, dass ein entscheidender Durchbruch des Kurses auf diesem Niveau zu einer beträchtlichen Kursbewegung führen könnte, die bis zu 250 Pips betragen könnte. Dies bedeutet, dass Händler dieses Niveau im Hinblick auf potenzielle Handelsmöglichkeiten im Auge behalten sollten.
  • OvershootReason: Dies bedeutet, dass der Kurs ein Ausbruchsniveau testet, und wenn es ihm nicht gelingt, das Momentum aufrechtzuerhalten, ist eine Umkehr der Kursrichtung wahrscheinlich. Dies bedeutet, dass Händler vorsichtig sein sollten, wenn der Kurs über ein Schlüsselniveau steigt, ohne dass eine starke Kaufunterstützung besteht.
  • UndershootReason: Dies deutet darauf hin, dass der Markt nicht genügend Aufwärtsinteresse gezeigt hat, sodass eine Umkehr zu einem Abwärtstrend möglich sein könnte. Händler sollten dieses Signal genau beobachten, um mögliche Leerverkaufsmöglichkeiten zu erkennen.
  • SmallQuarterReason: Dabei handelt es sich um eine geringfügige Preisschwankung auf dem Markt. Es deutet darauf hin, dass sich der Kurs in kleinen Schritten bewegt und möglicherweise keine bedeutenden Handelsmöglichkeiten oder Trendänderungen anzeigt.

input string MajorSupportReason    = "Key support level. Break below signals range shift.";
input string MajorResistanceReason = "Pivotal resistance. Breakout above may start new range.";
input string LargeQuarterReason    = "Decisive break could trigger next 250-PIP move.";
input string OvershootReason       = "Test of breakout; reversal likely if momentum fails.";
input string UndershootReason      = "Insufficient bullish force; possible bearish reversal.";
input string SmallQuarterReason    = "Minor fluctuation.";

Eine globale, boolesche Variable, intrusionAlerted wird verwendet, um sicherzustellen, dass Warnungen nur einmal pro Einbruchsereignis ausgelöst werden, um wiederholte Benachrichtigungen zu vermeiden, wenn der Preis um ein bestimmtes Niveau herum verweilt.

// Global flag to avoid repeated alerts while price lingers at a level
bool intrusionAlerted = false;

Die Funktion DrawHorizontalLine ist das Herzstück der visuellen Ausgabe des EA. Diese Funktion nimmt Parameter wie den Namen der Zeile, den Preis, die Farbe, die Breite und den Stil entgegen und prüft zunächst, ob eine Zeile mit diesem Namen bereits existiert - falls ja, wird die Zeile gelöscht. Anschließend wird eine neue horizontale Linie zum angegebenen Preis erstellt und ihre Eigenschaften entsprechend eingestellt, wobei sichergestellt wird, dass die Linie bis zum rechten Rand des Charts reicht. Dieser modulare Ansatz macht es einfach, die Funktion wiederzuverwenden, wenn eine neue Ebene gezeichnet werden muss.

void DrawHorizontalLine(string name, double price, color lineColor, int width, ENUM_LINE_STYLE style)
{
   if(ObjectFind(0, name) != -1)
      ObjectDelete(0, name);

   if(!ObjectCreate(0, name, OBJ_HLINE, 0, 0, price))
   {
      Print("Failed to create line: ", name);
      return;
   }
   ObjectSetInteger(0, name, OBJPROP_COLOR, lineColor);
   ObjectSetInteger(0, name, OBJPROP_STYLE, style);
   ObjectSetInteger(0, name, OBJPROP_WIDTH, width);
   ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, true);
}

DrawQuarters nutzt die Funktion DrawHorizontalLine, um die Hauptgrenzen des 1000-PIP-Bereichs (berechnet auf der Grundlage des aktuellen Kurses) sowie zusätzliche Linien innerhalb dieses Bereichs zu zeichnen. Wenn diese Option aktiviert ist, zeichnet der EA die Linien von „Large Quarter“, indem er den Bereich in vier Segmente unterteilt. Wenn Überschreitungsbereiche aktiviert sind, zeichnet die Funktion für jede dieser Linien auch Linien leicht oberhalb und unterhalb des Hauptpegels, um mögliche Über- oder Unterschreitungen anzuzeigen. Wenn die Option aktiviert ist, unterteilt der EA den Bereich sogar in noch feinere Linien „Small Quarter“, die Ihnen detailliertere visuelle Hinweise auf die Preisstruktur geben.

void DrawQuarters(double currentPrice)
{
   // Calculate the boundaries of the current 1000-PIP Range
   double lowerMajor = MathFloor(currentPrice / MajorStep) * MajorStep;
   double upperMajor = lowerMajor + MajorStep;

   // Draw Major Whole Number lines (defining the 1000-PIP Range)
   DrawHorizontalLine("MajorLower", lowerMajor, MajorColor, MajorLineWidth, MajorLineStyle);
   DrawHorizontalLine("MajorUpper", upperMajor, MajorColor, MajorLineWidth, MajorLineStyle);

   // Draw Large Quarter lines and their overshoot/undershoot areas if enabled
   if(DrawLargeQuarters)
   {
      double LQIncrement = MajorStep / 4.0;
      for(int i = 1; i < 4; i++)
      {
         double level = lowerMajor + i * LQIncrement;
         string objName = "LargeQuarter_" + IntegerToString(i);
         DrawHorizontalLine(objName, level, LargeQuarterColor, LargeQuarterLineWidth, LargeQuarterLineStyle);

         if(DrawOvershootAreas)
         {
            double offset = MajorStep / 40.0; // approximately 25 pips if MajorStep=0.1000
            DrawHorizontalLine("Overshoot_" + IntegerToString(i) + "_up", level + offset, OvershootColor, OvershootLineWidth, OvershootLineStyle);
            DrawHorizontalLine("Undershoot_" + IntegerToString(i) + "_down", level - offset, OvershootColor, OvershootLineWidth, OvershootLineStyle);
         }
      }
   }

   // Draw Small Quarter lines if enabled (optional, finer divisions)
   if(DrawSmallQuarters)
   {
      double segStep = MajorStep / 10.0;
      double smallQuarter = segStep / 4.0;
      for(int seg = 0; seg < 10; seg++)
      {
         double segStart = lowerMajor + seg * segStep;
         for(int j = 1; j < 4; j++)
         {
            double level = segStart + j * smallQuarter;
            string objName = "SmallQuarter_" + IntegerToString(seg) + "_" + IntegerToString(j);
            DrawHorizontalLine(objName, level, SmallQuarterColor, SmallQuarterLineWidth, SmallQuarterLineStyle);
         }
      }
   }
}

Eine weitere wichtige Funktion ist CreateOrUpdateLabeldie für die Anzeige von Text im Chart zuständig ist. Diese Funktion prüft, ob ein Kennzeichnung bereits vorhanden ist und erstellt es, falls nicht. Anschließend werden der Text, die Farbe, die Schriftgröße und andere Eigenschaften des Etiketts aktualisiert, wobei eine einzeilige Schrift (Courier New) verwendet wird, um sicherzustellen, dass alle Tabellendaten sauber ausgerichtet bleiben. Diese Funktion ist besonders wichtig für die Aktualisierung der Kommentare, in denen die Marktbedingungen erläutert werden.

void CreateOrUpdateLabel(string name, string text, int corner, int xdist, int ydist, color txtColor, int fontSize)
{
   if(ObjectFind(0, name) == -1)
   {
      ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
      ObjectSetInteger(0, name, OBJPROP_CORNER, corner);
      ObjectSetInteger(0, name, OBJPROP_XDISTANCE, xdist);
      ObjectSetInteger(0, name, OBJPROP_YDISTANCE, ydist);
      // Set a monospaced font for tabular display (Courier New)
      ObjectSetString(0, name, OBJPROP_FONT, "Courier New");
   }
   ObjectSetString(0, name, OBJPROP_TEXT, text);
   ObjectSetInteger(0, name, OBJPROP_COLOR, txtColor);
   ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontSize);
}

Wenn der EA initialisiert wird (in der Funktion OnInit), erstellt er ein dauerhaftes Etikett in der oberen linken Ecke des Charts mit der Meldung „Intrusion Detector Initialized“. Umgekehrt wird beim Entfernen des EA (über die Funktion OnDeinit) diese Kennzeichnung gelöscht, um das Chart aufgeräumt zu halten.

int OnInit()
{
   // Create a persistent commentary label in the top-left corner
   CreateOrUpdateLabel("IntrusionCommentary", "Intrusion Detector Initialized", CORNER_LEFT_UPPER, 10, 10, clrWhite, 14);
   return(INIT_SUCCEEDED);
}

Das Herzstück des EA liegt in der Funktion OnTick, die bei jedem neuen Markttick ausgeführt wird. Wenn der EA einen neuen Tick erhält, wird die Funktion OnTick ausgelöst. Der erste Schritt in dieser Funktion besteht darin, ein Flag namens intrusionDetected auf false zu initialisieren und das aktuelle Marktangebot mit SymbolInfoDouble(_Symbol, SYMBOL_BID) abzurufen. Wenn der zurückgegebene Preis 0 ist (was auf einen ungültigen oder nicht verfügbaren Wert hinweist), wird die Funktion sofort beendet.

void OnTick()
{
   bool intrusionDetected = false;
   double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   if(currentPrice == 0)
      return;

Als Nächstes ruft der EA die Funktion DrawQuarters Funktion mit dem aktuellen Preis auf. Dieser Aufruf ist für das Zeichnen aller Schlüsselebenen auf dem Chart verantwortlich, einschließlich der Hauptebenen, der großen Viertellinien und, falls aktiviert, der kleineren Viertellinien, die die visuelle Struktur liefern, die unseren Bereich definiert. Unmittelbar danach berechnet der EA die Grenzen des aktuellen 1000-PIP-Bereichs neu, indem er das Level LowerMajor mit MathFloor(currentPrice / MajorStep) * MajorStep bestimmt und dann MajorStep addiert, um das Level UpperMajor zu finden.

   // Draw the quarter lines first
   DrawQuarters(currentPrice);

Um zu verdeutlichen, was der EA erkennt, wird eine tabellarische Zeichenfolge erstellt. Diese Tabelle beginnt mit einer Kopfzeile, die drei Spalten definiert: Zone, Preis und Grund. In diesen Spalten wird die Bedeutung der einzelnen Niveaus aufgeführt, wenn sich der Preis ihnen nähert.

   double lowerMajor = MathFloor(currentPrice / MajorStep) * MajorStep;
   double upperMajor = lowerMajor + MajorStep;

Im nächsten Schritt wird geprüft, ob sich der Kurs in der Nähe von Schlüsselwerten befindet. Der EA prüft zunächst, ob der Kurs innerhalb der festgelegten Toleranz der unteren Begrenzung (Major Support) oder der oberen Begrenzung(Major Resistance) liegt. Wenn eine der beiden Bedingungen erfüllt ist, fügt die Funktion der Kommentartabelle eine Zeile mit der entsprechenden Meldung hinzu (mit vordefinierten Meldungen wie „Key support level. Break below signals range shift.“ für Unterstützung und eine ähnliche Meldung für Widerstand) und setzt intrusionDetected auf true.

// Check for Major Support
if(MathAbs(currentPrice - lowerMajor) <= AlertTolerance)
{
   table += StringFormat("%-18s | %-8s | %s\n", "Major Support", DoubleToString(lowerMajor,4), MajorSupportReason);
   intrusionDetected = true;
}
// Check for Major Resistance
if(MathAbs(currentPrice - upperMajor) <= AlertTolerance)
{
   table += StringFormat("%-18s | %-8s | %s\n", "Major Resistance", DoubleToString(upperMajor,4), MajorResistanceReason);
   intrusionDetected = true;
}

Wenn das Zeichnen der Linien von großen Vierteln aktiviert ist, unterteilt der EA den Bereich in Viertel und durchläuft diese Zwischenstufen. Für jedes große Viertel wird geprüft, ob der Kurs innerhalb der Toleranz liegt; ist dies der Fall, wird eine entsprechende Zeile (mit einer Meldung wie „Decisive break could trigger next 250-PIP move.“) an die Tabelle angehängt. Wenn Überschreitungsbereiche aktiviert sind, berechnet die Funktion außerdem einen kleinen Offset oberhalb und unterhalb jedes großen Viertels und prüft, ob der Preis diese Überschreitungs- oder Unterschreitungsbereiche berührt, wobei wiederum eine Zeile an die Tabelle angehängt wird, wenn die Bedingung erfüllt ist.

if(DrawLargeQuarters)
{
   double LQIncrement = MajorStep / 4.0;
   for(int i = 1; i < 4; i++)
   {
      double level = lowerMajor + i * LQIncrement;
      if(MathAbs(currentPrice - level) <= AlertTolerance)
      {
         table += StringFormat("%-18s | %-8s | %s\n", "Large Quarter", DoubleToString(level,4), LargeQuarterReason);
         intrusionDetected = true;
      }
      if(DrawOvershootAreas)
      {
         double offset = MajorStep / 40.0; // ~25 pips
         double overshootUp = level + offset;
         double undershootDown = level - offset;
         if(MathAbs(currentPrice - overshootUp) <= AlertTolerance)
         {
            table += StringFormat("%-18s | %-8s | %s\n", "Overshoot", DoubleToString(overshootUp,4), OvershootReason);
            intrusionDetected = true;
         }
         if(MathAbs(currentPrice - undershootDown) <= AlertTolerance)
         {
            table += StringFormat("%-18s | %-8s | %s\n", "Undershoot", DoubleToString(undershootDown,4), UndershootReason);
            intrusionDetected = true;
         }
      }
   }
}

Wenn der EA so konfiguriert ist, dass er kleine Viertellinien zeichnet, wird der Bereich optional noch weiter unterteilt. Die Funktion iteriert über diese feineren Unterteilungen und führt ähnliche Näherungsprüfungen durch, indem sie Zeilen mit der Meldung „Minor fluctuation“ schreibt, sobald sich der Preis einem dieser kleinen Quartalsniveaus nähert.

if(DrawSmallQuarters)
{
   double segStep = MajorStep / 10.0;
   double smallQuarter = segStep / 4.0;
   for(int seg = 0; seg < 10; seg++)
   {
      double segStart = lowerMajor + seg * segStep;
      for(int j = 1; j < 4; j++)
      {
         double level = segStart + j * smallQuarter;
         if(MathAbs(currentPrice - level) <= AlertTolerance)
         {
            table += StringFormat("%-18s | %-8s | %s\n", "Small Quarter", DoubleToString(level,4), SmallQuarterReason);
            intrusionDetected = true;
         }
      }
   }
}

Wenn keine der Stufen ein Eindringen feststellt (d. h. intrusionDetected bleibt falsch), erstellt der EA eine Standardmeldung. Diese Meldung informiert den Nutzer darüber, dass kein signifikanter Einbruch festgestellt wurde und dass sich der Markt zu konsolidieren scheint, und zeigt gleichzeitig den aktuellen Kurs an.

   // If no zones were triggered, still provide full information
   if(!intrusionDetected)
   {
      table = StringFormat("No significant intrusion detected.\nCurrent Price: %s\nMarket consolidating within established quarters.\n", DoubleToString(currentPrice,4));
   }

Nachdem die Kommentartabelle erstellt wurde, aktualisiert der EA die Texte auf dem Chart mit der Funktion CreateOrUpdateLabel, um sicherzustellen, dass die neueste Analyse deutlich im Chart angezeigt wird. Wenn schließlich ein Eindringling entdeckt wird und zuvor keine Warnung gesendet wurde (erkennbar am Flag intrusionAlerted), löst der EA eine Warnung mit dem Inhalt der Tabelle aus und setzt das Flag auf true, um wiederholte Benachrichtigungen zu verhindern. Um sicherzustellen, dass alle neuen Objekte und Aktualisierungen sofort sichtbar sind, endet die Funktion mit dem Aufruf von ChartRedraw.

   // Update the label with the commentary table.
   CreateOrUpdateLabel("IntrusionCommentary", table, CORNER_LEFT_UPPER, 10, 10, clrWhite, 14);

   // Trigger an alert only once per intrusion event.
   if(intrusionDetected && !intrusionAlerted)
   {
      Alert(table);
      intrusionAlerted = true;
   }
   if(!intrusionDetected)
      intrusionAlerted = false;

   ChartRedraw();
}

Vollständiger MQL5-Code

//+------------------------------------------------------------------+
//|                                               Intrusion Detector |
//|                               Copyright 2025, Christian Benjamin |
//|                          https://www.mql5.com/en/users/lynnchris |
//+------------------------------------------------------------------+
#property copyright "Christian Benjamin"
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.0"
#property strict

//---- Input parameters -------------------------------------------------
input double MajorStep          = 0.1000;   // Difference between Major Whole Numbers (defines the 1000-PIP Range)
input bool   DrawLargeQuarters  = true;     // Draw intermediate Large Quarter lines.
input bool   DrawSmallQuarters  = false;    // Draw Small Quarter lines.
input bool   DrawOvershootAreas = true;     // Mark overshoot/undershoot areas for Large Quarter lines.
input double AlertTolerance     = 0.0025;   // Tolerance for detecting a "touch" (e.g., ~25 pips for a pair where 1 pip=0.0001)

//---- Color settings ---------------------------------------------------
input color  MajorColor         = 0x2F4F4F; // Dark Slate Gray for Major lines.
input color  LargeQuarterColor  = 0x8B0000; // Dark Red for Large Quarter lines.
input color  SmallQuarterColor  = 0x00008B; // Dark Blue for Small Quarter lines.
input color  OvershootColor     = clrRed;   // Red for overshoot/undershoot lines.

//---- Line style and thickness settings -------------------------------
input ENUM_LINE_STYLE MajorLineStyle       = STYLE_SOLID;
input int    MajorLineWidth                 = 4;
input ENUM_LINE_STYLE LargeQuarterLineStyle  = STYLE_DOT;
input int    LargeQuarterLineWidth          = 3;
input ENUM_LINE_STYLE OvershootLineStyle     = STYLE_DASH;
input int    OvershootLineWidth             = 1;
input ENUM_LINE_STYLE SmallQuarterLineStyle  = STYLE_SOLID;
input int    SmallQuarterLineWidth          = 1;

//---- Commentary Messages (customizable) -----------------------------
input string MajorSupportReason    = "Key support level. Break below signals range shift.";
input string MajorResistanceReason = "Pivotal resistance. Breakout above may start new range.";
input string LargeQuarterReason    = "Decisive break could trigger next 250-PIP move.";
input string OvershootReason       = "Test of breakout; reversal likely if momentum fails.";
input string UndershootReason      = "Insufficient bullish force; possible bearish reversal.";
input string SmallQuarterReason    = "Minor fluctuation.";

// Global flag to avoid repeated alerts while price lingers at a level
bool intrusionAlerted = false;

//+------------------------------------------------------------------+
//| DrawHorizontalLine: Creates or replaces a horizontal line        |
//+------------------------------------------------------------------+
void DrawHorizontalLine(string name, double price, color lineColor, int width, ENUM_LINE_STYLE style)
  {
   if(ObjectFind(0, name) != -1)
      ObjectDelete(0, name);

   if(!ObjectCreate(0, name, OBJ_HLINE, 0, 0, price))
     {
      Print("Failed to create line: ", name);
      return;
     }
   ObjectSetInteger(0, name, OBJPROP_COLOR, lineColor);
   ObjectSetInteger(0, name, OBJPROP_STYLE, style);
   ObjectSetInteger(0, name, OBJPROP_WIDTH, width);
   ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, true);
  }

//+------------------------------------------------------------------+
//| DrawQuarters: Draws all quarter lines based on the current price |
//+------------------------------------------------------------------+
void DrawQuarters(double currentPrice)
  {
// Calculate the boundaries of the current 1000-PIP Range
   double lowerMajor = MathFloor(currentPrice / MajorStep) * MajorStep;
   double upperMajor = lowerMajor + MajorStep;

// Draw Major Whole Number lines (defining the 1000-PIP Range)
   DrawHorizontalLine("MajorLower", lowerMajor, MajorColor, MajorLineWidth, MajorLineStyle);
   DrawHorizontalLine("MajorUpper", upperMajor, MajorColor, MajorLineWidth, MajorLineStyle);

// Draw Large Quarter lines and their overshoot/undershoot areas if enabled
   if(DrawLargeQuarters)
     {
      double LQIncrement = MajorStep / 4.0;
      for(int i = 1; i < 4; i++)
        {
         double level = lowerMajor + i * LQIncrement;
         string objName = "LargeQuarter_" + IntegerToString(i);
         DrawHorizontalLine(objName, level, LargeQuarterColor, LargeQuarterLineWidth, LargeQuarterLineStyle);

         if(DrawOvershootAreas)
           {
            double offset = MajorStep / 40.0; // approximately 25 pips if MajorStep=0.1000
            DrawHorizontalLine("Overshoot_" + IntegerToString(i) + "_up", level + offset, OvershootColor, OvershootLineWidth, OvershootLineStyle);
            DrawHorizontalLine("Undershoot_" + IntegerToString(i) + "_down", level - offset, OvershootColor, OvershootLineWidth, OvershootLineStyle);
           }
        }
     }

// Draw Small Quarter lines if enabled (optional, finer divisions)
   if(DrawSmallQuarters)
     {
      double segStep = MajorStep / 10.0;
      double smallQuarter = segStep / 4.0;
      for(int seg = 0; seg < 10; seg++)
        {
         double segStart = lowerMajor + seg * segStep;
         for(int j = 1; j < 4; j++)
           {
            double level = segStart + j * smallQuarter;
            string objName = "SmallQuarter_" + IntegerToString(seg) + "_" + IntegerToString(j);
            DrawHorizontalLine(objName, level, SmallQuarterColor, SmallQuarterLineWidth, SmallQuarterLineStyle);
           }
        }
     }
  }

//+------------------------------------------------------------------+
//| CreateOrUpdateLabel: Creates or updates a label with given text  |
//+------------------------------------------------------------------+
void CreateOrUpdateLabel(string name, string text, int corner, int xdist, int ydist, color txtColor, int fontSize)
  {
   if(ObjectFind(0, name) == -1)
     {
      ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
      ObjectSetInteger(0, name, OBJPROP_CORNER, corner);
      ObjectSetInteger(0, name, OBJPROP_XDISTANCE, xdist);
      ObjectSetInteger(0, name, OBJPROP_YDISTANCE, ydist);
      // Set a monospaced font for tabular display (Courier New)
      ObjectSetString(0, name, OBJPROP_FONT, "Courier New");
     }
   ObjectSetString(0, name, OBJPROP_TEXT, text);
   ObjectSetInteger(0, name, OBJPROP_COLOR, txtColor);
   ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontSize);
  }

//+------------------------------------------------------------------+
//| OnInit: Initialization function for the EA                       |
//+------------------------------------------------------------------+
int OnInit()
  {
// Create a persistent commentary label in the top-left corner
   CreateOrUpdateLabel("IntrusionCommentary", "Intrusion Detector Initialized", CORNER_LEFT_UPPER, 10, 10, clrWhite, 14);
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| OnDeinit: Deinitialization function for the EA                   |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
// Remove the commentary label on exit
   ObjectDelete(0, "IntrusionCommentary");
  }

//+------------------------------------------------------------------+
//| OnTick: Main function called on every tick                       |
//+------------------------------------------------------------------+
void OnTick()
  {
   bool intrusionDetected = true;
   double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   if(currentPrice == 0)
      return;

// Draw the quarter lines first
   DrawQuarters(currentPrice);

// Calculate boundaries of the current 1000-PIP Range
   double lowerMajor = MathFloor(currentPrice / MajorStep) * MajorStep;
   double upperMajor = lowerMajor + MajorStep;

// Build a tabular commentary string with a header.
   string header = StringFormat("%-18s | %-8s | %s\n", "Zone", "Price", "Reason");
   string separator = "----------------------------------------------\n";
   string table = header + separator;

// Check for Major Support
   if(MathAbs(currentPrice - lowerMajor) <= AlertTolerance)
     {
      table += StringFormat("%-18s | %-8s | %s\n", "Major Support", DoubleToString(lowerMajor,4), MajorSupportReason);
      intrusionDetected = true;
     }
// Check for Major Resistance
   if(MathAbs(currentPrice - upperMajor) <= AlertTolerance)
     {
      table += StringFormat("%-18s | %-8s | %s\n", "Major Resistance", DoubleToString(upperMajor,4), MajorResistanceReason);
      intrusionDetected = true;
     }

// Check Large Quarter Levels and Overshoot/Undershoot Zones
   if(DrawLargeQuarters)
     {
      double LQIncrement = MajorStep / 4.0;
      for(int i = 1; i < 4; i++)
        {
         double level = lowerMajor + i * LQIncrement;
         if(MathAbs(currentPrice - level) <= AlertTolerance)
           {
            table += StringFormat("%-18s | %-8s | %s\n", "Large Quarter", DoubleToString(level,4), LargeQuarterReason);
            intrusionDetected = true;
           }
         if(DrawOvershootAreas)
           {
            double offset = MajorStep / 40.0; // ~25 pips
            double overshootUp = level + offset;
            double undershootDown = level - offset;
            if(MathAbs(currentPrice - overshootUp) <= AlertTolerance)
              {
               table += StringFormat("%-18s | %-8s | %s\n", "Overshoot", DoubleToString(overshootUp,4), OvershootReason);
               intrusionDetected = true;
              }
            if(MathAbs(currentPrice - undershootDown) <= AlertTolerance)
              {
               table += StringFormat("%-18s | %-8s | %s\n", "Undershoot", DoubleToString(undershootDown,4), UndershootReason);
               intrusionDetected = true;
              }
           }
        }
     }

// Check Small Quarter Levels (if enabled)
   if(DrawSmallQuarters)
     {
      double segStep = MajorStep / 10.0;
      double smallQuarter = segStep / 4.0;
      for(int seg = 0; seg < 10; seg++)
        {
         double segStart = lowerMajor + seg * segStep;
         for(int j = 1; j < 4; j++)
           {
            double level = segStart + j * smallQuarter;
            if(MathAbs(currentPrice - level) <= AlertTolerance)
              {
               table += StringFormat("%-18s | %-8s | %s\n", "Small Quarter", DoubleToString(level,4), SmallQuarterReason);
               intrusionDetected = true;
              }
           }
        }
     }

// If no zones were triggered, still provide full information
   if(!intrusionDetected)
     {
      table = StringFormat("No significant intrusion detected.\nCurrent Price: %s\nMarket consolidating within established quarters.\n", DoubleToString(currentPrice,4));
     }

// Update the label with the commentary table.
   CreateOrUpdateLabel("IntrusionCommentary", table, CORNER_LEFT_UPPER, 10, 10, clrWhite, 14);

// Trigger an alert only once per intrusion event.
   if(intrusionDetected && !intrusionAlerted)
     {
      Alert(table);
      // Alternatively, you could use: PlaySound("alert.wav");
      intrusionAlerted = true;
     }
   if(!intrusionDetected)
      intrusionAlerted = false;

   ChartRedraw();
  }
//+------------------------------------------------------------------+


Ergebnisse

Hier werde ich die Ergebnisse vorstellen, die ich nach dem Testen des Tools in einer realen Marktumgebung erhalten habe, obwohl ich zu diesem Zweck ein Demokonto verwendet habe. Das folgende Chart zeigt den Neuseeländischen Dollar (NZD) im Vergleich zum Amerikanischen Dollar (USD). Der Kurs näherte sich der Unterschreitungsgrenze und löste einen Alarm aus. 

Die Warnmeldung enthielt wichtige Informationen, einschließlich der identifizierten Zone, die in diesem Fall die Unterschreitungszone war. Das spezifische Kursniveau, bei dem diese Zone entdeckt wurde, liegt bei 0,5725. Darüber hinaus enthielt die Warnung eine Analyse der Marktbedingungen auf diesem Niveau, die auf eine unzureichende Aufwärtsdynamik und das Potenzial für eine rückläufige Trendwende hinwies.

NZDUSD

Abb. 3. NZD gegen USD

Nachfolgend finden Sie die Informationen, die auf der Registerkarte „Experten“ des MetaTrader 5 protokolliert werden.

2025.02.25 16:55:37.188 Intrusion Detector EA (NZDUSD,H1)       Alert: Zone               | Price    | Reason
2025.02.25 16:55:37.188 Intrusion Detector EA (NZDUSD,H1)       ----------------------------------------------
2025.02.25 16:55:37.188 Intrusion Detector EA (NZDUSD,H1)       Undershoot         | 0.5725   | Insufficient bullish force; possible bearish reversal.
2025.02.25 16:55:37.188 Intrusion Detector EA (NZDUSD,H1)       

Werfen wir einen Blick auf den Handel, den ich nach dieser Entdeckung und weiteren Analysen durchgeführt habe.

Platzierte Handelsgeschäfte

Abb. 3. Handels-Test

Unten sehen Sie die Endposition des Marktes, obwohl ich meine Handelsgeschäfte schnell geschlossen habe.

Marktbewegung

Abb. 5. Marktbewegung

Abbildung 6 unten ist ein GIF, das einen von mir durchgeführten Test des Währungspaares USD/CAD zeigt, bei dem zwei Zonen identifiziert wurden, in denen der Preis auf die Überschreitung und das große Quartalsniveau reagierte.

USDCAD

Abb. 6. USDCAD



Schlussfolgerung

Unser Expert Advisor dient als leistungsstarker Analyseassistent, der speziell für die Überwachung von Preiszonen in Übereinstimmung mit der Quarters-Theorie entwickelt wurde. Dieses Tool ist besonders wertvoll für Händler, die die „Quarters Theory“ in ihre Marktanalyse einbeziehen. Basierend auf unseren umfangreichen Tests zeichnet sich der EA durch die Erkennung wichtiger Preiszonen, die Ausgabe rechtzeitiger Warnungen und eine effektive Marktüberwachung im Hintergrund aus. Diese Entwicklung stellt einen bedeutenden Fortschritt bei der Automatisierung der Marktanalyse mit Hilfe der Quarters-Theorie dar. Bisher haben wir uns auf die Automatisierung des Ziehens von Vierteln konzentriert, und jetzt sind wir zur Echtzeit-Überwachung von Vierteln übergegangen. Durch diese Verbesserung wird sichergestellt, dass Händler sofort informiert werden, wenn der Preis mit diesen kritischen Niveaus interagiert, zusammen mit einer präzisen Erklärung möglicher Marktveränderungen.

Dies ist jedoch nicht die letzte Etappe unserer Reise. Erwarten Sie weitere Innovationen bei der Anwendung der Theorie der Viertel in der Marktautomatisierung. Dennoch empfehle ich allen Händlern, die dieses Tool nutzen, ihre eigenen Strategien zu integrieren, anstatt sich ausschließlich auf die bereitgestellten Signale zu verlassen. Ein umfassender Ansatz, der Automatisierung mit persönlichem Fachwissen kombiniert, führt zu fundierten Handelsentscheidungen.

DatumName des Werkzeugs BeschreibungVersion Aktualisierungen Hinweis
01/10/24Chart ProjectorSkript zur Überlagerung der Kursentwicklung des Vortages mit Geistereffekt.1.0Erste VeröffentlichungToolkit Nummer 1
18/11/24Analytical CommentEr liefert Informationen zum Vortag in Tabellenform und nimmt die zukünftige Marktentwicklung vorweg.1.0Erste VeröffentlichungToolkit Nummer 2
27/11/24Analytics MasterReguläre Aktualisierung der Marktmetriken alle zwei Stunden. 1.01Zweite VeröffentlichungToolkit Nummer 3
02/12/24Analytics Forecaster Reguläre Aktualisierung der Marktmetriken alle zwei Stunden mit Telegram-Integration.1.1Dritte AuflageToolkit Nummer 4
09/12/24Volatility NavigatorDer EA analysiert die Marktbedingungen anhand der Indikatoren Bollinger Bands, RSI und ATR.1.0Erste VeröffentlichungToolkit Nummer 5
19/12/24Mean Reversion Signal ReaperAnalysiert den Markt anhand der Strategie „Umkehr zur Mitte“ und liefert Signale. 1.0 Erste Veröffentlichung Toolkit Nummer 6 
9/01/25 Signal-Impuls Analysator für mehrere Zeitrahmen.1.0 Erste Veröffentlichung Toolkit Nummer 7 
17/01/25 Metrics Board Bedienfeld mit Taste für die Analyse. 1.0 Erste VeröffentlichungToolkit Nummer 8 
21/01/25External FlowAnalytik durch externe Bibliotheken.1.0 Erste VeröffentlichungToolkit Nummer 9 
27/01/25VWAPVolumengewichteter Durchschnittspreis  1.3 Erste Veröffentlichung Toolkit Nummer 10 
02/02/25 Heikin Ashi Trendglättung und Identifizierung von Umkehrsignalen 1.0 Erste Veröffentlichung Toolkit Nummer 11
04/02/25 FibVWAP Signalerzeugung durch Python-Analyse 1.0 Erste Veröffentlichung Toolkit Nummer 12
14/02/25 RSI DIVERGENCE Kursentwicklung versus RSI-Divergenzen 1.0 Erste Veröffentlichung Toolkit Nummer 13 
17/02/25 Parabolischer Stopp und Umkehr (PSAR) Automatisierung der PSAR-Strategie1.0Erste Veröffentlichung Toolkit Nummer 14
20/02/25 Quarters Drawer ScriptEinzeichnen der Ebenen der Viertel auf dem Chart 1.0 Erste Veröffentlichung Toolkit Nummer 15 
27/02/25Intrusion DetectorErkennen und warnen, wenn der Preis ein Viertel erreicht1.0Erste VeröffentlichungToolkit Nummer 16

Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/17321

Beigefügte Dateien |
Erstellen von selbstoptimierenden Expert Advisor in MQL5 (Teil 6): Stop-Out-Prävention Erstellen von selbstoptimierenden Expert Advisor in MQL5 (Teil 6): Stop-Out-Prävention
Schließen Sie sich unserer heutigen Diskussion an, wenn wir nach einem algorithmischen Verfahren suchen, mit dem wir die Gesamtzahl der Ausstiege aus Gewinngeschäften minimieren können. Das Problem, mit dem wir konfrontiert waren, ist sehr schwierig, und die meisten Lösungen, die in den Diskussionen in der Gemeinschaft genannt wurden, haben keine festen Regeln. Unser algorithmischer Ansatz zur Lösung des Problems erhöhte die Rentabilität unserer Handelsgeschäft und reduzierte den durchschnittlichen Verlust pro Handelsgeschäft. Es müssen jedoch noch weitere Fortschritte gemacht werden, um alle Handelsgeschäfte, die ausgestoppt werden, vollständig herauszufiltern, aber unsere Lösung ist ein guter erster Schritt, den jeder ausprobieren kann.
Erstellen eines Handelsadministrator-Panels in MQL5 (Teil IX): Code Organisation (III): Kommunikationsmodul Erstellen eines Handelsadministrator-Panels in MQL5 (Teil IX): Code Organisation (III): Kommunikationsmodul
Nehmen Sie an einer ausführlichen Diskussion über die neuesten Fortschritte im MQL5-Schnittstellendesign teil, wenn wir das neu gestaltete Kommunikations-Panel vorstellen und unsere Serie über den Aufbau des neuen Admin-Panels unter Verwendung von Modularisierungsprinzipien fortsetzen. Wir werden die Klasse CommunicationsDialog Schritt für Schritt entwickeln und ausführlich erklären, wie man sie von der Klasse Dialog erbt. Außerdem werden wir Arrays und die ListView-Klasse in unserer Entwicklung nutzen. Gewinnen Sie umsetzbare Erkenntnisse, um Ihre MQL5-Entwicklungsfähigkeiten zu verbessern - lesen Sie den Artikel und beteiligen Sie sich an der Diskussion im Kommentarbereich!
Automatisieren von Handelsstrategien in MQL5 (Teil 9): Aufbau eines Expert Advisors für die asiatische Breakout-Strategie Automatisieren von Handelsstrategien in MQL5 (Teil 9): Aufbau eines Expert Advisors für die asiatische Breakout-Strategie
In diesem Artikel erstellen wir einen Expert Advisor in MQL5 für die Asian Breakout Strategy, indem wir das Hoch und das Tief der Sitzung berechnen und die Trendfilterung mit einem gleitenden Durchschnitt anwenden. Wir implementieren ein dynamisches Objekt-Styling, nutzerdefinierte Zeitangaben und ein robustes Risikomanagement. Schließlich demonstrieren wir Techniken für Backtests und Optimierung zur Verfeinerung des Programms.
Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 15): Einführung in die Quarters-Theorie (I) - Quarters Drawer Script Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 15): Einführung in die Quarters-Theorie (I) - Quarters Drawer Script
Unterstützungs- und Widerstandspunkte sind kritische Niveaus, die potenzielle Trendumkehr und -fortsetzungen signalisieren. Obwohl es schwierig sein kann, diese Niveaus zu identifizieren, sind Sie, wenn Sie sie einmal gefunden haben, gut vorbereitet, um sich auf dem Markt zurechtzufinden. Als weitere Hilfe können Sie das in diesem Artikel vorgestellte Tool „Quarters Drawer“ verwenden, mit dem Sie sowohl primäre als auch sekundäre Unterstützungs- und Widerstandsniveaus identifizieren können.