English Русский
preview
Entwicklung eines Toolkits zur Price-Action-Analyse (Teil 63): Automatisierung der Erkennung von steigenden und fallenden Keilen in MQL5

Entwicklung eines Toolkits zur Price-Action-Analyse (Teil 63): Automatisierung der Erkennung von steigenden und fallenden Keilen in MQL5

MetaTrader 5Beispiele |
33 0
Christian Benjamin
Christian Benjamin

Inhalt


Einführung

Wenn man ein Chart öffnet, ist der erste Reflex, nach Strukturen zu suchen. Bekannte Muster helfen dabei, Erwartungen zu formulieren, Risiken zu steuern und sich auf Einstiege mit hoher Wahrscheinlichkeit vorzubereiten. Zu den am häufigsten gehandelten Kursmustern zählen steigende und fallende Keile – Kompressionsformationen, die oft einer Expansion vorausgehen.

Die Herausforderung besteht jedoch nicht darin, zu wissen, dass Keile existieren. Die Herausforderung besteht darin, diese konsistent und objektiv zu identifizieren. Viele Trader, insbesondere diejenigen, die ihre Fähigkeiten in der Chartanalyse weiterentwickeln, haben Schwierigkeiten, eine korrekte Keilformation zu erkennen. Selbst erfahrene Analysten können viel Zeit damit verbringen, Trendlinien zu zeichnen, anzupassen und zu überprüfen – und dabei manchmal eine gültige Formation völlig übersehen. Die subjektive Mustererkennung führt zu Verzögerungen, Inkonsistenzen und Verzerrungen.

Um diesem Problem zu begegnen, stellen wir einen MQL5-Indikator vor, der darauf ausgelegt ist, steigende und fallende Keilformationen direkt im Chart automatisch zu erkennen und darzustellen. Das System identifiziert Pivots, überprüft die Konvergenz der Begrenzungslinien, verhindert strukturelle Überlappungen und überwacht die Bedingungen von Ausbruch oder Scheitern – und setzt so geometrische Theorie in strukturierte algorithmische Logik um.

In diesem Artikel gehen wir Schritt für Schritt vor:

  • Zunächst untersuchen wir die strukturellen Merkmale von steigenden und fallenden Keilen.
  • Anschließend setzen wir diese Theorie in eine praktische MQL5-Implementierung um.
  • Danach überprüfen wir das Verhalten des Systems durch Tests.
  • Abschließend möchten wir noch einige Erkenntnisse und praktische Überlegungen anführen.

Lassen Sie uns zunächst einmal verstehen, wie sich Keilformationen entwickeln und warum sie für die Kursanalyse von Bedeutung sind.


Strukturelle Merkmale von steigenden und fallenden Keilen

Ein Keil ist eine Kursformation, die durch zwei zusammenlaufende Trendlinien definiert ist, welche die Marktbewegung innerhalb einer sich zunehmend verengenden Spanne einschränken. Im Gegensatz zur horizontalen Konsolidierung spiegelt ein Keil eine gerichtete Kompression wider – der Kurs bildet weiterhin höhere Hochs und höhere Tiefs (steigender Keil) oder niedrigere Hochs und niedrigere Tiefs (fallender Keil), doch die Bandbreite der Bewegung zwischen den beiden Begrenzungen verengt sich im Laufe der Zeit. Das entscheidende Merkmal ist nicht einfach nur das Vorhandensein von zwei Linien. Es handelt sich um die messbare Konvergenz der Struktur. Diese Konvergenz deutet auf nachlassende Dynamik und zunehmenden Druck hin und geht häufig einem entscheidenden Ausbruch oder einem strukturellen Scheitern voraus.

Um zu verstehen, wie sich diese Struktur in algorithmische Logik umsetzen lässt, untersuchen wir ihre strukturellen Bestandteile Schritt für Schritt.

1. Preiskompression und konvergierende Trendlinien

Während Phasen kontrollierter Kontraktion bilden sich Keile. Jeder nachfolgende Swing bleibt zwischen zwei Linien begrenzt, die sich allmählich einander annähern.

  • Die obere Grenze stellt den Widerstandsdruck dar.
  • Die untere Grenze stellt den Unterstützungsdruck dar.

Während der Kurs zwischen diesen Begrenzungen schwankt, verringert sich der vertikale Abstand zwischen ihnen. Diese Kompression spiegelt einen Rückgang der Volatilität und eine Straffung der Marktstruktur wider. Die Verengung des Bereichs erfolgt nicht zufällig; sie folgt einer gerichteten Bewegung, deren Ausdehnungskraft zunehmend nachlässt. Gerade diese Konvergenz ist es, die einen Keil von einem parallelen Kanal unterscheidet. In einem Kanal bleiben die Begrenzungen in gleichem Abstand zueinander. In einem Keil ist das nicht der Fall.

Die obige Abbildung zeigt einen steigenden Keil mit sich verengenden oberen und unteren Begrenzungen und einer Richtungsverdichtung (höhere Hochs und höhere Tiefs).

2. Pivot-Struktur und Berührungsvalidierung

Die Stabilität eines Keils hängt von geprüften strukturellen Verankerungen ab. Diese Ankerpunkte sind Swing-Hochs und Swing-Tiefs – Pivot-Punkte, die die oberen und unteren Begrenzungen definieren. Ein gültiger Keil erfordert mehrere bestätigte Berührungspunkte an jeder Begrenzung. Ohne ausreichende Interaktion bleibt die Struktur rein spekulativ. Jeder weitere Pivot-Punkt stärkt die strukturelle Legitimität, da er bestätigt, dass der Kurs die konvergierenden Rahmenbedingungen einhält.

Diese Vorgabe verhindert das willkürliche Zeichnen von Trendlinien und sorgt für die Einhaltung objektiver Regeln bei deren Bildung. Ein Keil lässt sich nicht anhand zweier Punkte vermuten; er wird durch wiederholte strukturelle Wechselwirkungen bestätigt.

3. Steigungsrichtung und Keilklassifizierung

Keile werden anhand der Steigung ihrer Trendlinienbegrenzungen klassifiziert.

In einem steigenden Keil:

  • Beide Trendlinien steigen.
  • Die untere Grenze steigt schneller an als die obere Grenze.
  • Konvergenz entsteht von unten.

In einem fallenden Keil:

  • Beide Trendlinien verlaufen abwärts.
  • Die obere Grenze nimmt schneller ab als die untere Grenze.
  • Die Konvergenz erfolgt von oben.

Die Klassifizierung erfolgt durch den Vergleich der relativen Steigungen der beiden Begrenzungen. Die Konvergenz lässt sich mathematisch nachweisen, wenn die Differenz der Steigungen dazu führt, dass sich die projizierten Geraden an einem zukünftigen Punkt schneiden – der gemeinhin als Scheitelpunkt bezeichnet wird. Diese Steigungsbeziehung ist es, die ein visuelles Muster in messbare Geometrie umwandelt.

4. Ausbruch vs. Scheitern

Sobald die Kompression ein kritisches Stadium erreicht, löst der Kurs die Formation auf.

  • Ein steigender Keil löst sich in der Regel nach unten auf.


  • Ein fallender Keil löst sich in der Regel nach oben auf.

Die Märkte sind jedoch nicht verpflichtet, den Erwartungen zu folgen. Wenn der Kurs in die entgegengesetzte Richtung ausbricht, verliert der Keil seine strukturelle Gültigkeit. Dieses Ergebnis ist kein Zufall; es spiegelt eine Veränderung in der Dynamik des Orderflusses wider. Die Überwachung des Verhaltens nach der Bildung ist daher unerlässlich. Ein Keil ist bei der Identifizierung unvollständig. Seine Gültigkeit hängt davon ab, wie der Kurs auf seine Begrenzungen reagiert.



MQL5-Implementierung

Nachdem wir die strukturelle Theorie hinter Keilformationen erarbeitet haben, besteht der nächste Schritt darin, diese Logik in eine robuste, für den Produktionseinsatz geeignete MQL5-Implementierung umzusetzen. Das Ziel besteht nicht lediglich darin, konvergierende Trendlinien zu zeichnen, sondern eine disziplinierte Non-Repainting-Erkennungslogik zu entwickeln, die signifikante Swing-Punkte identifiziert, die Konvergenz der Begrenzungen mathematisch validiert, strukturelle Konflikte durch intelligente Überlappungserkennung verhindert und Bedingungen für Ausbruch und Scheitern kontinuierlich überwacht, während sich der Kurs in Echtzeit entwickelt. Die Implementierung ist in miteinander verknüpfte Ebenen gegliedert: Konfigurationsparameter, Pivot-Erkennung, Keil-Erkennung, Verwaltung gekapselter Muster, Visualisierung und ereignisgesteuerter Ausführungsablauf.

Das System ist so konzipiert, dass wichtige Pivot-Punkte, Keilsteigungen und Ausbrüche im Chart deutlich sichtbar sind und intuitive Anhaltspunkte für Handelsentscheidungen liefern, während die zugrunde liegende modulare Struktur und die Non-Repainting-Logik dafür sorgen, dass der Code robust, effizient und wartungsfreundlich bleibt.

Eingaben und Konfiguration

Die Implementierung beginnt mit einem klar strukturierten Eingabebereich, der in logische Gruppen unterteilt ist, die sowohl die Erkennungsempfindlichkeit als auch die visuelle Darstellung steuern. Diese Parameter legen fest, wie streng der Algorithmus die Marktstruktur interpretiert und wie die daraus resultierenden Formationen im Chart dargestellt werden.

//+------------------------------------------------------------------+
//| Input parameters for Wedge Pattern indicator                     |
//+------------------------------------------------------------------+
input group "Pattern Detection Rules"
input int    PivotLeft           = 5;             // Pivot Left
input int    PivotRight          = 5;             // Pivot Right
input int    MinTouches          = 3;             // Min. Touches per Line

input group "Visual Design"
input color  RisingColor         = clrRed;        // Rising Wedge (Bearish)
input color  FallingColor        = clrLime;       // Falling Wedge (Bullish)
input int    MaxWedges           = 20;            // Max wedges displayed (oldest removed)
input bool   ExtendLines         = true;          // Extend wedge lines
input int    LineExtensionBars   = 30;            // Bars to extend (if ExtendLines=true)
input ENUM_LINE_STYLE LineStyle  = STYLE_SOLID;   // Line style for wedge lines
input int    LineWidth           = 1;             // Line width (1-5)
input bool   ShowLabels          = true;          // Show pattern labels
input int    LabelFontSize       = 8;             // Label font size
input bool   LabelWithBackground = false;         // Add background rectangle to labels
input color  LabelBgColor        = clrBlack;      // Label background color
input double LabelBgOpacity      = 0.7;           // Background opacity (0.0-1.0)

Die erste Gruppe, Pattern Detection Rules (Regeln zur Mustererkennung), umfasst PivotLeft, PivotRight und MinTouches. Die Pivot-Parameter legen fest, wie viele Kerzen auf beiden Seiten einer infrage kommenden Kerze berücksichtigt werden müssen, um zu bestimmen, ob diese als Swing-Hoch oder Swing-Tief gilt. Eine Erhöhung dieser Werte führt zu stärkeren, konservativeren Pivots, da dadurch ausgeprägtere Swings erforderlich werden, während eine Verringerung dieser Werte die Reaktionsfähigkeit erhöht, allerdings auf Kosten möglicher Störsignale. Der Parameter MinTouches sorgt für eine strukturelle Validierung, indem er eine Mindestanzahl von Pivotpunkten an beiden Begrenzungen vorschreibt, bevor ein Keil als gültig angesehen werden kann. Dadurch wird verhindert, dass schwache oder vorzeitige Formationen akzeptiert werden.

Die zweite Gruppe, Visual Design (Visualisierung), steuert die Darstellung im Chart und das Verhalten von Objekten. RisingColor und FallingColor unterscheiden bärische steigende Keile von bullischen fallenden Keilen. MaxWedges begrenzt die Anzahl der weiterhin sichtbaren historischen Formationen und entfernt automatisch die ältesten Strukturen, um Unübersichtlichkeit zu vermeiden. Mit ExtendLines und LineExtensionBars wird festgelegt, ob und wie weit Begrenzungslinien in zukünftige Bars hineinragen. Zusätzliche Gestaltungsoptionen verbessern die Lesbarkeit und die Optik der Charts, darunter Linienbreite, Stil, Sichtbarkeit der Beschriftungen, Schriftgröße sowie optionale Hintergrundrechtecke mit einstellbarer Deckkraft. Diese Konfigurationsoptionen stellen sicher, dass das System vollständig anpassungsfähig bleibt, ohne dass die Kernlogik der Erkennung geändert werden muss.

Erkennung von Pivots und strukturelle Bestätigung

Sobald die Konfiguration festgelegt ist, beginnt der Erkennungsprozess mit der Isolierung strukturell aussagekräftiger Swing-Punkte. Die Konstruktion des Keils basiert auf sauberen Pivot-Daten und nicht auf rohen Kursschwankungen. Zu diesem Zweck führt die Implementierung eine eigene Pivot-Klasse ein, die den Barindex, den Zeitstempel und den Kurs jedes Pivots kapseln.

//+------------------------------------------------------------------+
//| Pivot point class                                                |
//+------------------------------------------------------------------+
class Pivot : public CObject
  {
public:
   int      index;
   datetime time;
   double   price;

   Pivot(int idx,datetime t,double p) : index(idx),time(t),price(p) {}
  };

Dieser objektorientierte Ansatz vereinfacht die Speicherung, die Speicherverwaltung und den späteren Zugriff auf Strukturen. Die Hilfsfunktionen IsPivotHigh() und IsPivotLow() bewerten jede mögliche Bar, indem sie deren Hoch bzw. Tief mit den benachbarten Bars innerhalb des durch PivotLeft und PivotRight definierten Bereichs vergleichen. Indem Pivot-Punkte erst dann bestätigt werden, wenn sich ausreichend viele umgebende Bars gebildet haben, stellt er sicher, dass nur aussagekräftige Swing-Hochs und -Tiefs die Begrenzungen des Keils definieren. Dieser Ansatz hebt Preisbereiche hervor, in denen Unterstützung und Widerstand bestehen, liefert zuverlässige Signale und verhindert gleichzeitig historische Instabilität in der Erkennungslogik.

//+------------------------------------------------------------------+
//| Check if bar at idx is a pivot high                              |
//+------------------------------------------------------------------+
bool IsPivotHigh(int idx,const double &high[],int left,int right)
  {
   if(idx-left<0) return(false);
   double val=high[idx];
   for(int i=idx-left; i<=idx+right; i++)
     {
      if(i==idx) continue;
      if(i>=ArraySize(high)) return(false);
      if(high[i]>=val) return(false);
     }
   return(true);
  }

//+------------------------------------------------------------------+
//| Check if bar at idx is a pivot low                               |
//+------------------------------------------------------------------+
bool IsPivotLow(int idx,const double &low[],int left,int right)
  {
   if(idx-left<0) return(false);
   double val=low[idx];
   for(int i=idx-left; i<=idx+right; i++)
     {
      if(i==idx) continue;
      if(i>=ArraySize(low)) return(false);
      if(low[i]<=val) return(false);
     }
   return(true);
  }

Ein Pivot-Hoch gilt nur dann als bestätigt, wenn das Hoch der Bar alle umgebenden Hochs in seinem Bewertungsfenster übersteigt, während ein Pivot-Tief niedriger sein muss als alle umgebenden Tiefs. Wichtig ist, dass Pivot-Punkte nicht sofort bestätigt werden. Der Algorithmus verzögert die Validierung, indem er einen potenziellen Index erst dann auswertet, wenn sich die erforderliche Anzahl von Bar auf der rechten Seite gebildet hat. Dieser progressive Bestätigungsmechanismus stellt sicher, dass Pivots nicht neu gezeichnet werden, wodurch die strukturelle Integrität gewahrt bleibt und historische Instabilitäten in erkannten Mustern verhindert werden. Sowohl beim anfänglichen historischen Scan als auch bei den nachfolgenden Aktualisierungen innerhalb von OnCalculate() werden bestätigte Pivots in den dynamischen Containern CArrayObj mit automatischer Speicherverwaltung gespeichert. Diese Filterstufe wandelt Rohpreisdaten in eine stabile Darstellung der Marktstruktur um und bildet so zuverlässige Ankerpunkte für die Begrenzungslinien.

Erkennung von Keilformationen und geometrische Validierung

Sobald genügend Pivots bestätigt wurden, besteht der nächste Schritt darin, festzustellen, ob ihre Anordnung eine für einen Keil charakteristische konvergierende Struktur bildet. Die Erkennung wird sofort ausgelöst, sobald über die Funktion TryDetectWedge() ein neuer Pivot hinzugefügt wird. Die Steigung und die Konvergenz der Begrenzungen bestimmen, ob es sich bei der Formation um einen steigenden oder einen fallenden Keil handelt. Durch die Projektion des theoretischen Scheitelpunkts und die Aussortierung von sich überschneidenden oder bereits überschnittenen Formationen zeigt das System auf dem Chart ausschließlich klare, umsetzbare Muster an und gewährleistet gleichzeitig eine präzise geometrische Validierung im Code.

//+------------------------------------------------------------------+
//| Try to detect a new wedge pattern from recent pivots             |
//+------------------------------------------------------------------+
void TryDetectWedge(int currentBar,const datetime &time[],const double &close[])
  {
   int nHighs=pivotHighs.Total();
   int nLows=pivotLows.Total();
   if(nHighs<MinTouches || nLows<MinTouches) return;

   Pivot *p1h=dynamic_cast<Pivot*>(pivotHighs.At(nHighs-MinTouches));
   Pivot *pNh=dynamic_cast<Pivot*>(pivotHighs.At(nHighs-1));
   Pivot *p1l=dynamic_cast<Pivot*>(pivotLows.At(nLows-MinTouches));
   Pivot *pNl=dynamic_cast<Pivot*>(pivotLows.At(nLows-1));

   if(!p1h || !pNh || !p1l || !pNl) return;

   double upperSlope=(pNh.price-p1h.price)/(pNh.index-p1h.index+1e-10);
   double lowerSlope=(pNl.price-p1l.price)/(pNl.index-p1l.index+1e-10);

   int wedgeType=0;
   if(upperSlope>0 && lowerSlope>0 && lowerSlope>upperSlope) wedgeType=1;
   if(upperSlope<0 && lowerSlope<0 && upperSlope<lowerSlope) wedgeType=2;
   if(wedgeType==0) return;

   double apexX=(p1l.price-p1h.price+upperSlope*p1h.index-lowerSlope*p1l.index)/(upperSlope-lowerSlope+1e-10);
   if((int)MathRound(apexX)<=currentBar) return;

   bool isRising=(wedgeType==1);
   Wedge *w=new Wedge(isRising,p1h.index,p1h.time,p1h.price,pNh.index,pNh.time,pNh.price,
                      p1l.index,p1l.time,p1l.price,pNl.index,pNl.time,pNl.price,
                      upperSlope,lowerSlope,currentBar);

   if(OverlapsExistingWedge(w))
     {
      delete w;
      return;
     }

   w.Draw();
   wedges.Add(w);
   PruneOldWedges();
  }

Diese Kernlogik ermittelt den frühesten und den jüngsten Pivot-Punkt innerhalb des gewünschten Berührungsbereichs. Diese Punkte legen die potenziellen oberen und unteren Begrenzungen des Keils fest. Die Steigungen dieser Begrenzungen werden direkt zwischen den jeweiligen Pivot-Paaren berechnet und liefern so einen numerischen Maßstab für den Winkel und die Richtung jeder Trendlinie. Dieser Schritt stellt sicher, dass der Algorithmus die Konvergenz mathematisch bewerten kann, anstatt sich auf eine visuelle Annäherung zu verlassen. Die Klassifizierung richtet sich ausschließlich nach den Steigungen: Ein steigender Keil liegt vor, wenn beide Begrenzungsgeraden positiv geneigt sind und die untere Begrenzungsgerade steiler ansteigt als die obere, während bei einem abfallenden Keil beide Begrenzungsgeraden negativ geneigt sind und die obere Begrenzungsgerade steiler abfällt als die untere.

Bei der geometrischen Validierung wird zudem der theoretische Scheitelpunkt (Schnittpunkt der beiden Trendlinien) projiziert, und die Formation wird nur akzeptiert, wenn dieser Scheitelpunkt nach der aktuellen Bar liegt. Parallele Linien und Strukturen, die sich bereits schneiden, werden automatisch verworfen. Bevor ein neuer Keil akzeptiert wird, ruft TryDetectWedge() die Funktion OverlapsExistingWedge() auf, die wiederum mithilfe der Methode OverlapsWith() eine präzise Überlappungsprüfung, Bar-für-Bar mit jedem bestehenden aktiven Keil durchführt. Indem diese Überprüfung vor der Erstellung eines neuen Keilobjekts durchgeführt wird, gewährleistet das System die strukturelle Konsistenz im Chart und verhindert das Auftreten mehrerer widersprüchlicher Muster.

Keilstruktur und Erkennungsmechanismus

Sobald eine Formation alle geometrischen Prüfungen und Überlappungsprüfungen innerhalb von TryDetectWedge() bestanden hat, instanziiert das System sie als formales Wedge-Objekt. Die Klasse Wedge fasst alle erforderlichen Informationen zusammen, darunter Start- und Endpunkte für beide Begrenzungen, vorberechnete Steigungen, den Keiltyp (steigend oder fallend), die Formationsbar sowie Flags zum Laufzeitstatus. Eindeutige Objektnamen werden auf der Grundlage von Pivot-Indizes und der Entstehungszeit generiert. Dadurch wird sichergestellt, dass jeder Keil über eine eindeutige Kennung verfügt, und es werden Namenskonflikte auf dem Chart vermieden, selbst wenn mehrere Formationen kurz hintereinander auftreten. Neu instanziierte Keile werden zur Lebenszyklussteuerung einem verwalteten CArrayObj-Container hinzugefügt.

//+------------------------------------------------------------------+
//| Main Wedge pattern class                                         |
//+------------------------------------------------------------------+
class Wedge : public CObject
  {
public:
   bool      isRising;
   int       upperStartIdx,upperEndIdx;
   double    upperStartPrice,upperEndPrice;
   int       lowerStartIdx,lowerEndIdx;
   double    lowerStartPrice,lowerEndPrice;
   double    upperSlope,lowerSlope;
   int       formationBar;
   bool      isBroken,isFailed;

   string    upperLineName,lowerLineName;
   string    labelName,labelBgName;

   double UpperPriceAt(int barIdx) const;
   double LowerPriceAt(int barIdx) const;

   void Draw(void);
   void Update(int currentBar,datetime currentTime,double currentClose);
   void Delete(void);
  };

Dadurch wird sichergestellt, dass jedes Muster erfasst, auf dem Chart eingezeichnet und im Verlauf der Kursentwicklung aktualisiert wird, wodurch eine Echtzeitverbindung zwischen der Erkennungslogik und der Visualisierung aufrechterhalten wird.

Visualisierung, Objektidentität und dynamische Zustandsüberwachung

Sobald ein Keil validiert und instanziiert wurde, konzentriert sich das System auf die visuelle Darstellung und die fortlaufende Überwachung. Jedes Wedge-Objekt kapselt nicht nur seine geometrischen Daten, sondern auch seine visuellen Kennungen und seinen Zustand. Die Methode Draw() übernimmt die Darstellung jedes Keils im Chart, indem sie gestaltete Trendlinien für die obere und untere Begrenzung unter Verwendung der konfigurierten Farben, Breite, des Stils und der optionalen Vorwärtsverlängerung erstellt. Die oberen und unteren Begrenzungslinien werden gestaltet und optional erweitert, um eine klare visuelle Orientierung zu bieten. So wird sichergestellt, dass die Struktur des Keils auf einen Blick erkennbar ist, während der Code die Erstellung und Gestaltung der Objekte dynamisch verwaltet.

//+------------------------------------------------------------------+
//| Draw wedge trendlines and optional label                         |
//+------------------------------------------------------------------+
void Wedge::Draw(void)
  {
   color clr=isRising?RisingColor:FallingColor;
   
   //--- Upper trend line
   if(ExtendLines)
     {
      int upperExtIdx=upperEndIdx+LineExtensionBars;
      datetime upperExtTime=upperEndTime+PeriodSeconds(PERIOD_CURRENT)*LineExtensionBars;
      double upperExtPrice=UpperPriceAt(upperExtIdx);
      ObjectCreate(0,upperLineName,OBJ_TREND,0,upperStartTime,upperStartPrice,upperExtTime,upperExtPrice);
     }
   else
      ObjectCreate(0,upperLineName,OBJ_TREND,0,upperStartTime,upperStartPrice,upperEndTime,upperEndPrice);

   ObjectSetInteger(0,upperLineName,OBJPROP_COLOR,clr);
   ObjectSetInteger(0,upperLineName,OBJPROP_WIDTH,LineWidth);
   ObjectSetInteger(0,upperLineName,OBJPROP_STYLE,LineStyle);
   ObjectSetInteger(0,upperLineName,OBJPROP_RAY_RIGHT,false);

   //--- Lower trend line (identical logic) + label with formation date and optional background rectangle
  }

Formationsbeschriftungen zeigen den Keiltyp und den Formationszeitpunkt an; optional kann ein halbtransparentes Hintergrundrechteck hinzugefügt werden, um die Lesbarkeit auf dichten Charts zu verbessern. Die dynamische Statusüberwachung erfolgt über die Methode Update(), die bei jeder neuen Bar die Grenzinteraktionen mithilfe der Projektionshilfsfunktionen UpperPriceAt() und LowerPriceAt() auswertet. Die Ausbruchserkennung nutzt einen kleinen Volatilitätspuffer, um Rauschen und Spread herauszufiltern. Ausbruch und Scheitern werden erst nach eindeutigen Schlusskursen außerhalb der Begrenzungen markiert, wodurch die Signale im Chart aussagekräftig werden, während der Aktualisierungsmechanismus effizient nur aktive Keile auswertet.

//+------------------------------------------------------------------+
//| Update wedge status - check for breakout or failure              |
//+------------------------------------------------------------------+
void Wedge::Update(int currentBar,datetime currentTime,double currentClose)
  {
   if(isBroken || isFailed) return;

   double upperNow=UpperPriceAt(currentBar);
   double lowerNow=LowerPriceAt(currentBar);

   bool upperBreak=currentClose>upperNow+Point()*3;
   bool lowerBreak=currentClose<lowerNow-Point()*3;

   if((isRising && lowerBreak) || (!isRising && upperBreak))
     {
      isBroken=true;
      //--- Update label to BREAKOUT
     }
   else if((isRising && upperBreak) || (!isRising && lowerBreak) || upperNow<=lowerNow)
     {
      isFailed=true;
      //--- Update label to FAILED
     }
  }

Gemeinsam bilden die Mechanismen Draw(), Update() und PruneOldWedges() eine robuste Visualisierungs- und Überwachungsebene, die die Erkennung von Strukturen mit einer intuitiven Chart-Interpretation in Echtzeit verbindet. Wenn ein Keil nicht mehr benötigt wird, entfernt seine Methode Delete() alle zugehörigen Chartobjekte vollständig.

//+------------------------------------------------------------------+
//| Remove oldest wedges when limit is exceeded                      |
//+------------------------------------------------------------------+
void PruneOldWedges(void)
  {
   while(wedges.Total()>MaxWedges)
     {
      Wedge *oldest=dynamic_cast<Wedge*>(wedges.At(0));
      if(oldest) oldest.Delete();
      wedges.Delete(0);
     }
  }

Ereignisgesteuerter Ausführungsablauf

Das Keilerkennungssystem ist so konzipiert, dass es vollständig innerhalb des ereignisgesteuerten MQL5-Frameworks arbeitet und dabei die Lebenszyklusfunktionen der Plattform nutzt, um Effizienz und Zuverlässigkeit zu gewährleisten. Die Initialisierung erfolgt in der Funktion OnInit(), wo die CArrayObj-Container für Pivots und Wedges mit aktivierter automatischer Speicherverwaltung angelegt werden. Diese Konfiguration stellt sicher, dass Objekte sicher und ohne Speicherlecks erstellt und gelöscht werden. Wenn der Indikator aus einem Chart entfernt wird, wird die Funktion OnDeinit() ausgelöst, um alle keilbezogenen Chart-Objekte zu bereinigen und den zugewiesenen Speicher freizugeben, sodass der Chart sauber zurückbleibt.

Die Hauptverarbeitung findet in der Funktion OnCalculate() statt. Im ersten Ausführungszyklus wird ein vollständiger historischer Durchlauf der Kursreihe durchgeführt, um mithilfe von IsPivotHigh() und IsPivotLow() erste Pivot-Punkte zu ermitteln und über TryDetectWedge() alle potenziellen Keilformationen zu identifizieren. Die inkrementelle Auswertung stellt sicher, dass neue Bars sofort erkannt und Statusaktualisierungen ausgelöst werden, wodurch die Leistung erhalten bleibt und gleichzeitig eine aktuelle, zuverlässige Darstellung der Keilentwicklungen im Chart gewährleistet wird.

//+------------------------------------------------------------------+
//| Main indicator calculation function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[])
  {
   ArraySetAsSeries(time,false);
   ArraySetAsSeries(high,false);
   ArraySetAsSeries(low,false);
   ArraySetAsSeries(close,false);

   if(prev_calculated==0)
     {
      ObjectsDeleteAll(0,"WEDGE_");
      pivotHighs.Clear();
      pivotLows.Clear();
      wedges.Clear();

      int startBar=PivotRight;
      int endBar=rates_total-PivotRight-1;

      for(int i=startBar; i<=endBar; i++)
        {
         bool newPivot=false;
         if(IsPivotHigh(i,high,PivotLeft,PivotRight))
           {
            pivotHighs.Add(new Pivot(i,time[i],high[i]));
            newPivot=true;
           }
         if(IsPivotLow(i,low,PivotLeft,PivotRight))
           {
            pivotLows.Add(new Pivot(i,time[i],low[i]));
            newPivot=true;
           }
         if(newPivot) TryDetectWedge(i,time,close);
        }
     }

   int start=(prev_calculated>0)?prev_calculated-1:0;
   for(int i=start; i<rates_total; i++)
     {
      int possibleIdx=i-PivotRight;
      if(possibleIdx<0) continue;

      bool newPivot=false;
      if(IsPivotHigh(possibleIdx,high,PivotLeft,PivotRight))
        {
         pivotHighs.Add(new Pivot(possibleIdx,time[possibleIdx],high[possibleIdx]));
         newPivot=true;
        }
      if(IsPivotLow(possibleIdx,low,PivotLeft,PivotRight))
        {
         pivotLows.Add(new Pivot(possibleIdx,time[possibleIdx],low[possibleIdx]));
         newPivot=true;
        }
      if(newPivot) TryDetectWedge(possibleIdx,time,close);
     }

   if(rates_total>0)
     {
      int currentBar=rates_total-1;
      for(int j=0; j<wedges.Total(); j++)
        {
         Wedge *w=dynamic_cast<Wedge*>(wedges.At(j));
         if(w) w.Update(currentBar,time[currentBar],close[currentBar]);
        }
     }

   PruneOldWedges();
   return(rates_total);
  }

Bei nachfolgenden Aktualisierungen wertet das System nur neu abgeschlossene Bars aus, was die Recheneffizienz erheblich verbessert. Neu bestätigte Pivots lösen sofort die Keilerkennungslogik aus. Gleichzeitig werden alle vorhandenen Keile über ihre Update()-Methoden mit dem aktuellen Schlusskurs aktualisiert, was eine Echtzeit-Bewertung der Bedingungen von Ausbruch oder Scheitern ermöglicht. Der schrittweise Ansatz vermeidet überflüssige Neuberechnungen und gewährleistet gleichzeitig ein zeitnahes visuelles Feedback zu sich entwickelnden Mustern. Die Funktion PruneOldWedges() wird nach jeder Aktualisierung ausgeführt, um eine optimale Leistung und die Übersichtlichkeit des Charts zu gewährleisten.

Zusammenfassung

Diese MQL5-Implementierung wandelt die theoretische Keilstruktur in einen disziplinierten, nicht nachzeichnenden Erkennungsmechanismus um, der auf mathematisch validierter Konvergenz basiert. Durch die Isolierung signifikanter Pivot-Punkte mithilfe von IsPivotHigh() und IsPivotLow(), die Berechnung von Grenzsteigungen innerhalb von TryDetectWedge(), die Projektion von Scheitelpunkt-Schnittpunkten, die Vermeidung geometrischer Überlappungskonflikte mittels OverlapsWith() sowie die dynamische Verwaltung des Ausbruchsstatus mithilfe von Update() gewährleistet das System die strukturelle Integrität unter Echtzeit-Marktbedingungen. Das objektorientierte Design mit den Funktionen Draw() und PruneOldWedges() sowie die kontrollierte Lebenszyklusverwaltung in OnInit() und OnDeinit() in Verbindung mit konfigurierbaren Parametern machen den Indikator sowohl analytisch robust als auch erweiterbar für die Integration in umfassendere Handelsframeworks.


Validierung und Verhaltensanalyse

In diesem Abschnitt wird der Test- und Validierungsprozess vorgestellt, mit dem die Leistung und Robustheit des Keilformationsindikators unter realen Bedingungen bewertet wird. An dieser Stelle nehmen wir die Feinabstimmung der Eingabeparameter vor, um sie optimal an unterschiedliche Handelsbedingungen, Zeitrahmen und Marktphasen anzupassen.

Der Indikator wurde während der Entwicklungs- und Optimierungsphase Anfang 2026 gründlich validiert. Die Tests kombinierten ausgewählte historische Zeiträume mit umfangreichen Echtzeit-Forward-Tests anhand von Live-Charts. Wichtige Handelsinstrumente, darunter EURUSD, GBPUSD, USDJPY, AUDUSD und Gold (XAUUSD), wurden über verschiedene Zeitrahmen von M15 bis H4 hinweg herangezogen, um das Verhalten sowohl unter volatilen als auch unter trendorientierten Marktbedingungen zu bewerten.

Die folgende Konfiguration diente als primäre Ausgangsbasis:

//+------------------------------------------------------------------+
//| Default parameters used during validation                        |
//+------------------------------------------------------------------+
input group "Pattern Detection Rules"
input int PivotLeft   = 5;   // Pivot Left
input int PivotRight  = 5;   // Pivot Right
input int MinTouches  = 3;   // Min. Touches per Line

input group "Visual Design"
input color RisingColor  = clrRed;     // Rising Wedge (Bearish)
input color FallingColor = clrLime;    // Falling Wedge (Bullish)
input int   MaxWedges    = 20;         // Max wedges displayed (oldest removed)
input bool  ExtendLines  = true;       // Extend wedge lines

Beispiele anhand von Echtzeit-Charts veranschaulichen das Verhalten des Indikators deutlich:

  • Zuverlässige Erkennung und Klassifizierung: Das System erkennt zuverlässig gültige steigende und fallende Keile und unterscheidet dabei anhand eines Steigungsvergleichs korrekt zwischen bullischen und bärischen Strukturen.
  • Schnelle Rückmeldung bei Ausbrüchen: Die richtungsabhängige Methode Update() kennzeichnet Ausbruch und Scheitern präzise mit eindeutigen Bezeichnungen (BREAKOUT oder FAILED) und hilft Händlern so, schnell zu reagieren.
  • Übersichtlichkeit im Chart: Die Logik zur Vermeidung von Überschneidungen (OverlapsWith() und OverlapsExistingWedge()) sorgt dafür, dass das Chart auch dann übersichtlich bleibt, wenn mehrere potenzielle Muster auftreten.

Die folgende Abbildung zeigt ein typisches Live-Beispiel für den EURUSD-Chart auf der M30-Zeitbasis, in dem mehrere Keilformationen und die darauffolgenden Ausbrüche hervorgehoben sind.

Die folgende Animation zeigt den Keil-Mechanismus in Echtzeit auf dem EURUSD-Chart im 30-Minuten-Zeitrahmen. In diesem Beispiel liegt der Schwerpunkt eher auf dem beobachtbaren Verhalten als auf den internen Abläufen.

Dabei zeigen sich mehrere wesentliche Merkmale:

  1. Keilformationen treten erst nach Erreichen der strukturellen Reife auf.
  2. Erkannte Muster bleiben nach ihrer Bestätigung stabil.
  3. Die Ergebnisse des Ausbruchs werden unmittelbar nach deren Abschluss festgehalten.

Im Verlauf der Sequenz bilden sich mehrere Keilformationen, die sich unabhängig voneinander auflösen. Einige enden in einer gerichteten Expansion, während andere noch vor einer Anschlussbewegung invalidiert werden. Jedes Ergebnis wird zum Zeitpunkt der Strukturauflösung eindeutig gekennzeichnet, was eine sofortige Auswertung ohne manuelle Neuanalyse ermöglicht. Die Aufzeichnung veranschaulicht zudem die Steuerung des Lebenszyklus von Mustern. Wenn sich der Kurs in neue strukturelle Phasen bewegt, schließen frühere Keilformationen sauber ab, ohne Reste zu hinterlassen, wodurch die Übersichtlichkeit des Charts auch bei anhaltender Volatilität gewahrt bleibt. Wichtig ist, dass das Beispiel verdeutlicht, dass das System Ausbrüche nicht vorhersagt – es reagiert erst, sobald die Randbedingungen eindeutig erfüllt sind. Dadurch wird sichergestellt, dass visuelle Signale tatsächlichen strukturellen Ereignissen entsprechen und nicht auf prognostizierten Annahmen beruhen.

Die Animation dient somit als praktische Bestätigung dafür, dass sich der Mechanismus unter Live-Bedingungen deterministisch verhält und dabei Stabilität, Übersichtlichkeit und Reaktionsfähigkeit beibehält, während sich der Kurs entwickelt.

Die Live-Demonstration unterstreicht, dass die Umsetzung nicht nur theoretischer Natur ist – sie funktioniert auch unter dynamischen Bedingungen zuverlässig, gewährleistet die strukturelle Integrität und liefert gleichzeitig umsetzbares Feedback, während sich der Kurs entwickelt.



Schlussfolgerung

Wir haben in MQL5 einen strukturell durchdachten Mechanismus zur Erkennung von Keilformationen entwickelt und implementiert, der weit über die einfache Darstellung visueller Muster hinausgeht. Das System identifiziert bestätigte Pivot-Strukturen, überprüft die Konvergenz der Begrenzungen mathematisch, verhindert strukturelle Überschneidungen durch intelligente Filterung und überwacht Zustände von Ausbruch oder Scheitern innerhalb eines übersichtlichen, objektorientierten Lebenszyklus-Rahmens.

Durch bewusste architektonische Entscheidungen – darunter gekapselte Pivot- und Wedge-Klassen, die dynamische Verwaltung von CArrayObj sowie strenge Bestätigungsregeln – gewährleistet der Indikator unter realen Marktbedingungen ein deterministisches Verhalten. Tests mit verschiedenen Instrumenten und über unterschiedliche Zeitrahmen hinweg haben eine stabile Erkennung, eine zeitnahe strukturelle Auflösung und eine gleichbleibende Übersichtlichkeit der Charts ohne verzerrende Vorwegnahme gezeigt. Diese Implementierung dient nicht als eigenständige Entscheidungsmaschine, sondern lässt sich am besten als Komponente zur Strukturanalyse innerhalb eines umfassenderen Handelsrahmens einsetzen. Händlern wird empfohlen, das Verhalten des Systems unter ihren eigenen Marktbedingungen zu überprüfen und es in bestehende Strategien, Risikomodelle und Bestätigungsinstrumente zu integrieren, um die kontextbezogene Analyse der Kursentwicklung zu verbessern.

Auf diese Weise entwickeln sich Keilformationen von subjektiven visuellen Mustern zu objektiv definierten, zustandsorientierten Strukturen, die disziplinierte Handelsmethoden ergänzen können.

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

Beigefügte Dateien |
WedgePattern.mq5 (19.94 KB)
PD-Arrays meistern: Optimierung des Handels mit Ungleichgewichten in PD-Arrays PD-Arrays meistern: Optimierung des Handels mit Ungleichgewichten in PD-Arrays
Dieser Artikel befasst sich mit einem spezialisierten, trendfolgenden EA, der deutlich machen soll, wie sich Setups, die sich aus Ungleichgewichten in Premium-/Discount-Bereichen (PD-Arrays) ergeben, definieren und nutzen lassen. In diesem Artikel wird ein EA ausführlich vorgestellt, der speziell für Trader entwickelt wurde, die PD-Arrays und Ungleichgewichte als Einstiegskriterien für ihre Trades und Handelsentscheidungen optimieren und nutzen möchten. Außerdem wird untersucht, wie sich Premium- und Discount-Zonen korrekt ermitteln und charakterisieren lassen und wie man sie jeweils validieren und nutzen kann, wenn sie unter den entsprechenden Marktbedingungen auftreten, um so die sich aus solchen Szenarien ergebenden Chancen bestmöglich zu nutzen.
MQL5-Handelswerkzeuge (Teil 23): Kameragesteuerte 3D-Diagramme mit DirectX-Unterstützung für Einblicke in die Verteilungen MQL5-Handelswerkzeuge (Teil 23): Kameragesteuerte 3D-Diagramme mit DirectX-Unterstützung für Einblicke in die Verteilungen
In diesem Artikel haben wir DirectX-3D in den MQL5-Viewer für die Binomialverteilung integriert. Damit ermöglichen wir umschaltbare 2D-/3D-Modi mit kameragesteuerter Drehung, Zoom und automatischer Anpassung für eine anschaulichere Analyse. Wir stellen 3D-Histogrammbalken, Bodenebenen und Achsen neben der Kurve der theoretischen Wahrscheinlichkeitsmassfunktion dar und behalten dabei 2D-Elemente wie Statistikpanel, Legenden sowie anpassbare Designs, Farbverläufe und Beschriftungen bei.
Eine alternative Log-datei mit der Verwendung der HTML und CSS Eine alternative Log-datei mit der Verwendung der HTML und CSS
In diesem Artikel werden wir eine sehr einfache, aber leistungsfähige Bibliothek zur Erstellung der HTML-Dateien schreiben, dabei lernen wir auch, wie man eine ihre Darstellung einstellen kann (nach seinem Geschmack) und sehen wir, wie man es leicht in seinem Expert Advisor oder Skript hinzufügen oder verwenden kann.
Implementierung des Truncated-Newton-Conjugate-Gradient-Algorithmus in MQL5 Implementierung des Truncated-Newton-Conjugate-Gradient-Algorithmus in MQL5
Dieser Artikel implementiert einen Truncated-Newton-Conjugate-Gradient (TNC) Optimierer mit Box-Beschränkungen in MQL5 und beschreibt detailliert seine Kernkomponenten: Skalierung, Projektion auf Grenzen, Liniensuche und Hessematrix-Vektor-Produkte mittels finiter Differenzen. Es stellt eine Zielfunktions-Wrapperklasse bereit, die analytische oder numerische Ableitungen unterstützt, und validiert die Implementierung am Rosenbrock-Benchmark. Ein Beispiel für eine logistische Regression veranschaulicht, wie TNC als weitgehend austauschbare Alternative zu LBFGS eingesetzt werden kann.