Untersuchung von Techniken zur Analyse der Kerzen (Teil III): Eine Bibliothek für die Musterbearbeitung

Alexander Fedosov | 17 Mai, 2019

Inhaltsverzeichnis

Einführung

Wir haben uns bereits mit Techniken der Kerzenanalyse beschäftigt: Die Aktualität der Muster unter aktuellen Marktbedingungen wurde im ersten Artikel überprüft, und im zweiten Artikel wurde versucht, diese Untersuchung zu erweitern. Anhand der Bewertungskriterien der Entwicklung wir eine Vielzahl von möglichen Musterkombinationen untersucht, getestet und verglichen. Zu diesem Zweck haben wir einen benutzerdefinierten Pattern Analyzer mit einer Vielzahl von Einstellungsmöglichkeiten zum Studium von Mustern entwickelt. Die Theorie und Forschung kann jedoch nur Informationen und Schlussfolgerungen liefern. Die logische Fortsetzung der Aufgabe ist es, sie unter realen Bedingungen einzusetzen.

Daher ist der Zweck dieses Artikels, ein nutzerdefiniertes Werkzeug zu erstellen, das es den Nutzern ermöglicht, die gesamte Bandbreite an Informationen über zuvor diskutierte Muster zu erhalten und zu verwenden. Wir werden eine Bibliothek erstellen, die Sie in Ihren eigenen Indikatoren, Handelspanels, Expert Advisors, etc. verwenden können.    


Bibliotheksstruktur

Bevor wir mit der Erstellung der Bibliotheksstruktur, der Klassen und Verbindungen beginnen, definieren wir die Daten, die wir verwenden werden. Das heißt, wir müssen die Methoden, die für die Eingabedaten verantwortlich sind, und die Methoden, die die Ergebnisse liefern, trennen. Die allgemeine Bibliotheksstruktur basiert auf der in den vorangegangenen Artikeln entwickelten visuellen Lösung — dem Pattern Analyzer. 

Beginnen wir mit den Eingabeparameter der Anwendung, die das Ergebnis beim Testen der Muster beeinflussen können.

Abb.1 Eingabeparameter in der Registerkarte Einstellung.

Block 1. Dieser Block enthält die Liste der Kerzentypen, aus denen die vorhandenen und generierten Muster bestehen. Jeder der Typen hat seine Einstellungen, die Sie einsehen können, indem Sie auf das Zahnradsymbol in der oberen rechten Ecke des Kerzenmusters klicken. Die Kerzentypen 1-5 haben nur eine Einstellung, während Hammer zwei hat. 

Block 2. Gewichtskoeffizienten. Es gibt drei Parameter К1, К2, К3, die das Ergebnis der Bewertung der Mustereffizienz beeinflussen. 

Block 3. Schwellenwert Trendwert in Punkten. 

Block 4. Kerzen zum Testen der erstellten Muster. Hier benötigen wir Sequenznummern oder die Kerzenindizes. Anhand dieser Daten können wir Informationen über jedes Muster beliebiger Größe, bis zu drei Kerzen, ermitteln.

Block 5. Anzahl der Kerzen im Muster. Diese Einstellung gilt nur für nutzerdefinierte Muster. 

Dann lassen Sie uns die Registerkarte Analysieren und die darin enthaltenen Eingabeparameter ansehen.

Abb.2 Die Eingabeparameter der Registerkarte Analysieren.

Block 6. Dieser Block enthält Einstellungen des aktuellen Zeitrahmens und der Zeitspanne, die für die Musteranalyse verwendet werden. 

Block 7. Namen bestehender Muster. Es gibt auch ein Eingabefeld, das nicht aus der Anwendung heraus bearbeitet werden kann, aber für den Zugriff auf ein Muster und die Beschaffung von Informationen darüber erforderlich ist.

Lassen Sie uns hier die Daten aufzählen, die aus der Musteranalyse gewonnen werden können. Dies ist notwendig, um eine korrekte Struktur von Methoden in einer Klasse zu erzeugen.

Bibliotheksentwicklung

Nachdem wir die grundlegenden Punkte festgelegt haben, fahren wir mit dem Erstellen der Bibliothek fort. Beginnen wir mit dem Erstellen einer Datei mit den erforderlichen Enumerationen Enums.mqh..

//+------------------------------------------------------------------+
//|                                                        Enums.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                           https://www.mql5.com/en/users/alex2356 |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Kerzentyp                                                        |
//+------------------------------------------------------------------+
enum TYPE_CANDLESTICK
  {
   CAND_NONE,           // Undefiniert
   CAND_MARIBOZU,       // Marubozu
   CAND_DOJI,           // Doji
   CAND_SPIN_TOP,       // Spinning Top
   CAND_HAMMER,         // Hammer
   CAND_INVERT_HAMMER,  // Inverted Hammer
   CAND_LONG,           // Lang
   CAND_SHORT           // Kurz
  };
//+------------------------------------------------------------------+
//| Mustertyp                                                        |
//+------------------------------------------------------------------+
enum TYPE_PATTERN
  {
   NONE,
   HUMMER,
   INVERT_HUMMER,
   HANDING_MAN,
   SHOOTING_STAR,
   ENGULFING_BULL,
   ENGULFING_BEAR,
   HARAMI_BULL,
   HARAMI_BEAR,
   HARAMI_CROSS_BULL,
   HARAMI_CROSS_BEAR,
   DOJI_STAR_BULL,
   DOJI_STAR_BEAR,
   PIERCING_LINE,
   DARK_CLOUD_COVER
  };
//+------------------------------------------------------------------+
//| Trendtype                                                        |
//+------------------------------------------------------------------+
enum TYPE_TREND
  {
   UPPER,               //Aufwärtstrend
   DOWN,                //Abwärtstrend
   FLAT                 //Seitwärtsbewegung
  };
//+------------------------------------------------------------------+

Hier werden wir die Liste der einfachen verwendeten Kerzentypen, die Typen der vorhandenen Muster sowie die Art des Trends bestimmen - die Daten werden benötigt, um bestehende Muster auf dem Chart zu identifizieren.

Danach erstellen wir die Datei Pattern.mqh. Die Klasse CPattern wird in ihr erstellt, und in ihrem 'private' Abschnitt werden wir Variablen für die im vorherigen Abschnitt erwähnten Parameter deklarieren. Außerdem müssen wir die Datei mit den Enumerationen einbinden.

//+------------------------------------------------------------------+
//|                                                      Pattern.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                           https://www.mql5.com/en/users/alex2356 |
//+------------------------------------------------------------------+
#include "Enums.mqh"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CPattern
  {
private:
   //--- Gewicht
   double            m_k1;
   double            m_k2;
   double            m_k3;
   //--- Schwellenwert des Trends in Punkten
   int               m_threshold_value;
   //--- Koeffizienteneinstellung einer langen Kerze
   double            m_long_coef;
   //--- Koeffizienteneinstellung einer kurzen Kerze
   double            m_short_coef;
   //--- Koeffizienteneinstellung einer Doij-Kerze
   double            m_doji_coef;
   //--- Koeffizienteneinstellung einer Marubozu-Kerze
   double            m_maribozu_coef;
   //--- Koeffizienteneinstellung einer Spinning Top-Kerze
   double            m_spin_coef;
   //--- Koeffizienteneinstellung einer Hammer-Kerze
   double            m_hummer_coef1;
   double            m_hummer_coef2;
   //--- Zeitspanne für die voreingestellten Muster
   int               m_range_total;
   //--- Periodenlänge zur Trendbestimmung
   int               m_trend_period;
   //--- Gefundene Muster
   int               m_found;
   //--- Auftreten der Muster
   double            m_coincidence;
   //--- Wahrscheinlichkeit eine Auf- oder Abwärtsbewegung
   double            m_probability1;
   double            m_probability2;
   //--- Effizienz
   double            m_efficiency1;
   double            m_efficiency2;
   //--- Einfache Kerzenmuster
   struct CANDLE_STRUCTURE
     {
      double            m_open;
      double            m_high;
      double            m_low;
      double            m_close;                      // OHLC
      TYPE_TREND        m_trend;                      // Trend
      bool              m_bull;                       // Aufwärtskerze
      double            m_bodysize;                   // Körpergröße
      TYPE_CANDLESTICK  m_type;                       // Kerzentyp
     };
   //--- Eigenschaften der Effizienzbewertung der Muster
   struct RATING_SET
     {
      int               m_a_uptrend;
      int               m_b_uptrend;
      int               m_c_uptrend;
      int               m_a_dntrend;
      int               m_b_dntrend;
      int               m_c_dntrend;
     };

Wie aus dem obigen Code ersichtlich ist, wurden zwei Strukturen in unser Programm aufgenommen. Die erste Struktur, CANDLE_STRUCTURE, wird für die Bestimmung des Kerzentyps auf dem Chart benötigt. Beachten Sie, dass in dieser Struktur zwei Arten von Trendaufzählungen verwendet werden: TYPE_TREND und TYPE_CANDLESTICK aus der Datei Enums.mqh, die zuvor besprochen wurde und für diese Struktur erstellt wurde. Die zweite Struktur, RATING_SET, speichert Datensätze der Schätzungen von Preisbewegungen nach dem Auftreten des Musters. Bitte lesen Sie den ersten Artikel für weitere Details.

Betrachten Sie nun den Teil des öffentlichen Teils der Klasse, der die Methoden zum Anpassen und Abrufen der Werte von Eingabeparametern beschreibt, die im Abschnitt Bibliotheksstruktur beschrieben sind.

public:
                     CPattern(void);
                    ~CPattern(void);
   //--- setzen und Rückgabe des Gewichtskoeffizient
   void              K1(const double k1)                             { m_k1=k1;                       }
   double            K1(void)                                        { return(m_k1);                  }
   void              K2(const double k2)                             { m_k2=k2;                       }
   double            K2(void)                                        { return(m_k2);                  }
   void              K3(const double k3)                             { m_k3=k3;                       }
   double            K3(void)                                        { return(m_k3);                  }
   //--- Setzen und Rückgabe des Schwellenwerts des Trends
   void              Threshold(const int threshold)                  { m_threshold_value=threshold;   }
   int               Threshold(void)                                 { return(m_threshold_value);     }
   //--- Setzen und Rückgabe der Einstellung einer langen Kerze
   void              Long_coef(const double long_coef)               { m_long_coef=long_coef;         }
   double            Long_coef(void)                                 { return(m_long_coef);           }
   //--- Setzen und Rückgabe der Einstellung einer kurzen Kerze
   void              Short_coef(const double short_coef)             { m_short_coef=short_coef;       }
   double            Short_coef(void)                                { return(m_short_coef);          }
   //--- Setzen und Rückgabe der Einstellung einer Doij-Kerze
   void              Doji_coef(const double doji_coef)               { m_doji_coef=doji_coef;         }
   double            Doji_coef(void)                                 { return(m_doji_coef);           }
   //--- Setzen und Rückgabe der Einstellung einer Marubozu-Kerze
   void              Maribozu_coef(const double maribozu_coef)       { m_maribozu_coef=maribozu_coef; }
   double            Maribozu_coef(void)                             { return(m_maribozu_coef);       }
   //--- Setzen und Rückgabe der Einstellung einer Spinning Top-Kerze
   void              Spin_coef(const double spin_coef)               { m_spin_coef=spin_coef;         }
   double            Spin_coef(void)                                 { return(m_spin_coef);           }
   //--- Setzen und Rückgabe der Einstellung einer Hammer-Kerze
   void              Hummer_coef1(const double hummer_coef1)         { m_hummer_coef1=hummer_coef1;   }
   void              Hummer_coef2(const double hummer_coef2)         { m_hummer_coef2=hummer_coef2;   }
   double            Hummer_coef1(void)                              { return(m_hummer_coef1);        }
   double            Hummer_coef2(void)                              { return(m_hummer_coef2);        }
   //--- Setzen und Rückgabe der Zeitspanne der voreingestellten Parameter
   void              Range(const int range_total)                    { m_range_total=range_total;     }
   int               Range(void)                                     { return(m_range_total);         }
   //--- Setzen und Rückgabe der Anzahl der Kerzen für die Trendberechnung  
   void              TrendPeriod(const int period)                   { m_trend_period=period;         }
   int               TrendPeriod(void)                               { return(m_trend_period);        }

Im Klassenkonstruktor werden wir die Standardparameter, wie sie in der Anwendung angegeben sind, in den Registerkarten der Einstellungen beschreiben.

//+------------------------------------------------------------------+
//| Konstruktor                                                      |
//+------------------------------------------------------------------+
CPattern::CPattern(void) : m_k1(1),
                           m_k2(0.5),
                           m_k3(0.25),
                           m_threshold_value(100),
                           m_long_coef(1.3),
                           m_short_coef(0.5),
                           m_doji_coef(0.04),
                           m_maribozu_coef(0.01),
                           m_spin_coef(1),
                           m_hummer_coef1(0.1),
                           m_hummer_coef2(2),
                           m_range_total(8000),
                           m_trend_period(5)
  {
  }

Der zweite Teil des 'public' Abschnitts der Klasse CPattern beschreibt die Methoden zur Verarbeitung der deklarierten Eingabeparameter und zum Erhalten der Eigenschaften und Merkmale der Muster.

Lassen Sie uns jede im Detail betrachten. Es ist wichtig, den Funktionsalgorithmus zu verstehen, um ihn bei der Erstellung von Indikatoren, Handelspanels oder Expert Advisors effizient einsetzen zu können.

CandleType

Die Methode gibt den Typ der ausgewählten Kerze aus vorhandenen Mustern, die in TYPE_CANDLESTICK aufgeführt sind, zurück.
TYPE_CANDLESTICK  CandleType(const string symbol,const ENUM_TIMEFRAMES timeframe,const int shift);

Parameter

Rückgabewert

Der Typ der gewählten Kerze aus der Enumeration TYPE_CANDLESTICK.

//+------------------------------------------------------------------+
//| Kerzentyp                                                        |
//+------------------------------------------------------------------+
enum TYPE_CANDLESTICK
  {
   CAND_NONE,           // Undefiniert
   CAND_MARIBOZU,       // Marubozu
   CAND_DOJI,           // Doji
   CAND_SPIN_TOP,       // Spinning Top
   CAND_HAMMER,         // Hammer
   CAND_INVERT_HAMMER,  // Inverted Hammer
   CAND_LONG,           // Lang
   CAND_SHORT           // Kurz
  };

Umsetzung

//+------------------------------------------------------------------+
//| Rückgabe des Typs der ausgewählten Kerze                         |
//+------------------------------------------------------------------+
TYPE_CANDLESTICK CPattern::CandleType(const string symbol,const ENUM_TIMEFRAMES timeframe,const int shift)
  {
   CANDLE_STRUCTURE res;
   if(GetCandleType(symbol,timeframe,res,shift))
      return(res.m_type);
   return(CAND_NONE);
  }
//+------------------------------------------------------------------+
//| Erkennen des Kerzentyps                                          |
//+------------------------------------------------------------------+
bool CPattern::GetCandleType(const string symbol,const ENUM_TIMEFRAMES timeframe,CANDLE_STRUCTURE &res,const int shift)
  {
   MqlRates rt[];
   int aver_period=m_trend_period;
   double aver=0;
   SymbolSelect(symbol,true);
   int copied=CopyRates(symbol,timeframe,shift,aver_period+1,rt);
//--- Abrufen der Details der vorherigen Kerze
   if(copied<aver_period)
      return(false);
//---
   res.m_open=rt[aver_period].open;
   res.m_high=rt[aver_period].high;
   res.m_low=rt[aver_period].low;
   res.m_close=rt[aver_period].close;

//--- Bestimmen der Trendrichtung
   for(int i=0;i<aver_period;i++)
      aver+=rt[i].close;
   aver/=aver_period;

   if(aver<res.m_close)
      res.m_trend=UPPER;
   if(aver>res.m_close)
      res.m_trend=DOWN;
   if(aver==res.m_close)
      res.m_trend=FLAT;
//--- Bestimmen, ob es eine Auf- oder Abwärtskerze ist
   res.m_bull=res.m_open<res.m_close;
//--- Ermitteln der absoluten Größe des Kerzenkörpers
   res.m_bodysize=MathAbs(res.m_open-res.m_close);
//--- Ermitteln des Kerzenkörpers
   double shade_low=res.m_close-res.m_low;
   double shade_high=res.m_high-res.m_open;
   if(res.m_bull)
     {
      shade_low=res.m_open-res.m_low;
      shade_high=res.m_high-res.m_close;
     }
   double HL=res.m_high-res.m_low;
//--- Berechnen der durchschnittlichen Körpergröße der vorherigen Kerze
   double sum=0;
   for(int i=1; i<=aver_period; i++)
      sum=sum+MathAbs(rt[i].open-rt[i].close);
   sum=sum/aver_period;

//--- Bestimmen des Kerzentyps   
   res.m_type=CAND_NONE;
//--- lang 
   if(res.m_bodysize>sum*m_long_coef)
      res.m_type=CAND_LONG;
//--- kurz 
   if(res.m_bodysize<sum*m_short_coef)
      res.m_type=CAND_SHORT;
//--- Doji
   if(res.m_bodysize<HL*m_doji_coef)
      res.m_type=CAND_DOJI;
//--- Marubozu
   if((shade_low<res.m_bodysize*m_maribozu_coef || shade_high<res.m_bodysize*m_maribozu_coef) && res.m_bodysize>0)
      res.m_type=CAND_MARIBOZU;
//--- Hammer
   if(shade_low>res.m_bodysize*m_hummer_coef2 && shade_high<res.m_bodysize*m_hummer_coef1)
      res.m_type=CAND_HAMMER;
//--- invertierter Hammer
   if(shade_low<res.m_bodysize*m_hummer_coef1 && shade_high>res.m_bodysize*m_hummer_coef2)
      res.m_type=CAND_INVERT_HAMMER;
//--- Spinning Top
   if(res.m_type==CAND_SHORT && shade_low>res.m_bodysize*m_spin_coef && shade_high>res.m_bodysize*m_spin_coef)
      res.m_type=CAND_SPIN_TOP;
//---
   ArrayFree(rt);
   return(true);
  }

Die Methode zur Kerzenerkennung GetCandleType() wird von der 'public' Methode GetCandleType() verwendet. GetCandleType() ist eine 'private' Methode. Deren Argumente beinhalten das aktuelle Symbol, den Zeitrahmen und die Kerzennummer sowie einen Zeiger auf die Struktur. Auf der Grundlage dieser Parameter wird die Musterberechnung und -identifikation durchgeführt.

PatternType

Diese Funktion erkennt den Mustertyp der ausgewählten Kerze. Sie hat 5 Methodenüberladungen, da Argumente entweder vorhandene Muster aus der TYPE_PATTERN Aufzählung oder generierte Muster aus einem, zwei oder drei Kerzenleuchtern sein können. Ein Argument kann auch ein Array von Mustern aus der Enumeration TYPE_PATTERN sein.

   //--- Erkennen des Mustertyps
   bool              PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,int shift);
   bool              PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index,const int shift);
   bool              PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,const int shift);
   bool              PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,const int shift);
   //--- Erkennen einer Reihe von Mustern
   bool              PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN &pattern[],int shift);

Parameter

Ein Zeiger auf den Array der bestehenden Muster aus der Liste TYPE_PATTERN.

//+------------------------------------------------------------------+
//| Mustertyp                                                        |
//+------------------------------------------------------------------+
enum TYPE_PATTERN
  {
   NONE,
   HUMMER,
   INVERT_HUMMER,
   HANDING_MAN,
   SHOOTING_STAR,
   ENGULFING_BULL,
   ENGULFING_BEAR,
   HARAMI_BULL,
   HARAMI_BEAR,
   HARAMI_CROSS_BULL,
   HARAMI_CROSS_BEAR,
   DOJI_STAR_BULL,
   DOJI_STAR_BEAR,
   PIERCING_LINE,
   DARK_CLOUD_COVER
  };

Rückgabewert

Ein boolscher Wert

Umsetzung

Da es 5 verschiedene Methodenimplementierungen von PatternType gibt, werden wir sie separat mit den verschiedenen Argumenten analysieren. Die erste von ihnen sucht nach einem vorhandenen Muster aus der Enumeration TYPE_PATTERN. Wie unten zu sehen ist, geschieht dies mit der 'private' Methode CheckPattern.

//+------------------------------------------------------------------+
//| Erkennen der vordefinierten Muster                               |
//+------------------------------------------------------------------+
bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,const int shift)
  {
   if(CheckPattern(symbol,timeframe,shift)==pattern)
      return(true);
   return(false);
  }
//+------------------------------------------------------------------+
//| Prüfen und Rückgabe des Mustertyps                               |
//+------------------------------------------------------------------+
TYPE_PATTERN CPattern::CheckPattern(const string symbol,const ENUM_TIMEFRAMES timeframe,int shift)
  {
   CANDLE_STRUCTURE cand1,cand2;
   TYPE_PATTERN pattern=NONE;
   ZeroMemory(cand1);
   ZeroMemory(cand2);
   GetCandleType(symbol,timeframe,cand2,shift);                                           // Vorherige Kerze
   GetCandleType(symbol,timeframe,cand1,shift-1);                                         // Aktuelle Kerze
//--- Inverted Hammer, Aufwärtsmuster
   if(cand2.m_trend==DOWN &&                                                              // Prüfen der Trendrichtung
      cand2.m_type==CAND_INVERT_HAMMER)                                                   // Prüfen des "Inverted Hammer"
      pattern=INVERT_HUMMER;
//--- Hanging man, abwärts
   else if(cand2.m_trend==UPPER && // Prüfen der Trendrichtung
      cand2.m_type==CAND_HAMMER) // Checking "Hammer"
      pattern=HANDING_MAN;
//--- Hammer, Aufwärtsmuster
   else if(cand2.m_trend==DOWN && // Prüfen der Trendrichtung
      cand2.m_type==CAND_HAMMER) // Checking "Hammer"
      pattern=HUMMER;
//--- Shooting Star, Abwärtsmuster
   else if(cand1.m_trend==UPPER && cand2.m_trend==UPPER && // Prüfen der Trendrichtung
      cand2.m_type==CAND_INVERT_HAMMER && cand1.m_close<=cand2.m_open) // Prüfen "Inverted Hammer"
      pattern=SHOOTING_STAR;
//--- Engulfing, Aufwärtsmuster
   else if(cand1.m_trend==DOWN && cand1.m_bull && cand2.m_trend==DOWN && !cand2.m_bull && // Prüfen der Trendrichtung und der Kerzenrichtung
      cand1.m_bodysize>cand2.m_bodysize &&
      cand1.m_close>=cand2.m_open && cand1.m_open<cand2.m_close)
      pattern=ENGULFING_BULL;
//--- Engulfing, Abwärtsmuster
   else if(cand1.m_trend==UPPER && cand1.m_bull && cand2.m_trend==UPPER && !cand2.m_bull && //Prüfen der Trendrichtung und der Kerzenrichtung
      cand1.m_bodysize<cand2.m_bodysize &&
      cand1.m_close<=cand2.m_open && cand1.m_open>cand2.m_close)
      pattern=ENGULFING_BEAR;
//--- Harami Cross, aufwärts
   else if(cand2.m_trend==DOWN && !cand2.m_bull && // Prüfen der Trendrichtung und der Kerzenrichtung
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && cand1.m_type==CAND_DOJI && // Prüfen der erste langen Kerze und der Doji-Kerze
      cand1.m_close<cand2.m_open && cand1.m_open>=cand2.m_close) // Doji ist innerhalb des Körpers der ersten Kerze
      pattern=HARAMI_CROSS_BULL;
//--- Harami Cross, Abwärtsmuster
   else if(cand2.m_trend==UPPER && cand2.m_bull && // Prüfen der Trendrichtung und der Kerzenrichtung
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && cand1.m_type==CAND_DOJI && // Prüfen der erste langen Kerze und der Doji-Kerze
      cand1.m_close>cand2.m_open && cand1.m_open<=cand2.m_close) // Doji ist innerhalb des Körpers der ersten Kerze 
      pattern=HARAMI_CROSS_BEAR;
//--- Harami, aufwärts
   else if(cand1.m_trend==DOWN && cand1.m_bull && !cand2.m_bull && // Prüfen der Trendrichtung und der Kerzenrichtung
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && // Prüfen auf eine lange erste Kerze
      cand1.m_type!=CAND_DOJI && cand1.m_bodysize<cand2.m_bodysize && // The second candle is not Doji and first candlestick body is larger than that of the second one
                    cand1.m_close<cand2.m_open && cand1.m_open>=cand2.m_close) // Körper der zweiten Kerze ist innerhalb des Körpers der ersten Kerze
                    pattern=HARAMI_BULL;
//--- Harami, abwärts
   else if(cand1.m_trend==UPPER && !cand1.m_bull && cand2.m_bull && // Prüfen der Trendrichtung und der Kerzenrichtung
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && // Prüfen auf eine lange erste Kerze

      cand1.m_type!=CAND_DOJI && cand1.m_bodysize<cand2.m_bodysize && // The second candle is not Doji and first candlestick body is larger than that of the second one
                    cand1.m_close>cand2.m_open && cand1.m_open<=cand2.m_close) // Körper der zweiten Kerze ist innerhalb des Körpers der ersten Kerze 
                    pattern=HARAMI_BEAR;
//--- Doji Star, aufwärts
   else if(cand1.m_trend==DOWN && !cand2.m_bull && // Prüfen der Trendrichtung und der Kerzenrichtung
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && cand1.m_type==CAND_DOJI && // Prüfen der erste langen Kerze und der Doji-Kerze
      cand1.m_close<=cand2.m_open) // Der Eröffnungspreis der Doji-Kerze ist kleiner oder gleich dem Schlusskurs der ersten Kerze
      pattern=DOJI_STAR_BULL;
//--- Doji Star, abwärts
   else if(cand1.m_trend==UPPER && cand2.m_bull && // Prüfen der Trendrichtung und der Kerzenrichtung
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && cand1.m_type==CAND_DOJI && // Prüfen der erste langen Kerze und der Doji-Kerze
      cand1.m_open>=cand2.m_close) // Der Eröffnungspreis der Doji-Kerze ist größer oder gleich dem Schlusskurs der ersten Kerze
      pattern=DOJI_STAR_BEAR;
//--- Piercing, Aufwärtsmuster
   else if(cand1.m_trend==DOWN && cand1.m_bull && !cand2.m_bull && // Prüfen der Trendrichtung und der Kerzenrichtung
      (cand1.m_type==CAND_LONG || cand1.m_type==CAND_MARIBOZU) && (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && // Prüfen auf eine langen Kerze
      cand1.m_close>(cand2.m_close+cand2.m_open)/2 && // 2te Kerze schließt über der Mitte der ersten Kerze
      cand2.m_open>cand1.m_close && cand2.m_close>=cand1.m_open)
      pattern=PIERCING_LINE;
//--- Dark Cloud Cover, abwärts
   else if(cand1.m_trend==UPPER && !cand1.m_bull && cand2.m_bull && // Prüfen der Trendrichtung und der Kerzenrichtung
      (cand1.m_type==CAND_LONG || cand1.m_type==CAND_MARIBOZU) && (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && // Prüfen auf eine langen Kerze
      cand1.m_close<(cand2.m_close+cand2.m_open)/2 && // 2te Kerze schließt unter der Mitte der ersten Kerzenkörper
      cand1.m_close<cand2.m_open && cand2.m_close<=cand1.m_open)
      pattern=DARK_CLOUD_COVER;
   return(pattern);
  }
//+------------------------------------------------------------------+

Der nächste Typ der Methode von PatternType unterscheidet sich von der vorherigen dadurch, dass anstelle des Arguments des Mustertyps ein Array mit den gesuchten Mustern übergeben wird:

//+------------------------------------------------------------------+
//| Erkennen des Arrays aus Mustern                                  |
//+------------------------------------------------------------------+
bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN &pattern[],int shift)
  {
   for(int i=0;i<ArraySize(pattern);i++)
     {
      if(CheckPattern(symbol,timeframe,shift)==pattern[i])
         return(true);
     }
   return(false);
  }

Als Nächstes betrachten wir die Implementierung der Methode PatternType für die Arbeit mit Mustern, die aus den einfachen Kerzentypen generiert wurden. Es gibt drei Arten dieser Muster: bestehend aus einem, zwei oder drei Kerzen. Betrachten wir sie eine nach der anderen:

//+------------------------------------------------------------------+
//| Erkennen eines Musters mit dem Kerzenindex                       |
//+------------------------------------------------------------------+
bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index,int shift)
  {
//--- Verifizieren des Kerzenindex
   if(index<0 || index>11)
      return(false);
//---
   CANDLE_STRUCTURE cand,cur_cand;
   RATING_SET ratings;
   ZeroMemory(cand);
   IndexToPatternType(cand,index);
//--- Abrufen des abrufen Kerzentyps
   GetCandleType(symbol,timeframe,cur_cand,shift);                                // Aktuelle Kerze
//---
   if(cur_cand.m_type==cand.m_type && cur_cand.m_bull==cand.m_bull)
      return(true);
   return(false);
  }

Dies ist die Implementierung einer Methode, die nach Mustern aus nur einer Kerze sucht. Die Methode ist der Methode CandleType() sehr ähnlich ist, obwohl Art und Umfang der übergebenen Argumente unterschiedlich sind. Achten Sie auf die 'private' Methode IndextoPatternType(), die früher nicht verwendet wurde:

   //--- Konvertiert den Kerzenindex in dessen Typ.
   void              IndexToPatternType(CANDLE_STRUCTURE &res,int index);

Sie konvertiert den Index eines einfachen Kerzentyps in dessen Typ und übergibt ihn der angegebenen Struktur.

Hier ist die Methode für ein Muster aus zwei Kerzen:

//+------------------------------------------------------------------+
//| Erkennen eines Musters mit dem Kerzenindex                       |
//+------------------------------------------------------------------+
bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int shift)
  {
//--- Verifizieren des Kerzenindex
   if(index1<0 || index1>11 || index2<0 || index2>11)
      return(false);
//---
   CANDLE_STRUCTURE cand1,cand2,cand3,cur_cand,prev_cand;
   RATING_SET ratings;
   ZeroMemory(cand1);
   ZeroMemory(cand2);
   IndexToPatternType(cand1,index1);
   IndexToPatternType(cand2,index2);
//--- Abrufen des abrufen Kerzentyps
   GetCandleType(symbol,timeframe,prev_cand,shift+1);                             // Vorherige Kerze
   GetCandleType(symbol,timeframe,cur_cand,shift);                                // Aktuelle Kerze
//---
   if(cur_cand.m_type==cand1.m_type && cur_cand.m_bull==cand1.m_bull && 
      prev_cand.m_type==cand2.m_type && prev_cand.m_bull==cand2.m_bull)
      return(true);
   return(false);
  }

Die Code-Implementierung ist sehr ähnlich wie vorher. Bitte beachten Sie jedoch, dass bei der Auswahl des Kerzenindex für die Analyse folgendes Merkmal berücksichtigt werden sollte: Da das Muster aus zwei Kerzen besteht, wird der Kerzentyp mit 'index1' um 'shift' und für index2 - um 'shift+1' verschoben. Die gleiche Besonderheit betrifft die Methodenimplementierung für drei Kerzenmuster:

//+------------------------------------------------------------------+
//| Erkennen eines Musters mit dem Kerzenindex                       |
//+------------------------------------------------------------------+
bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,int shift)
  {
   CANDLE_STRUCTURE cand1,cand2,cand3,cur_cand,prev_cand,prev_cand2;
   RATING_SET ratings;
//---
   ZeroMemory(cand1);
   ZeroMemory(cand2);
   ZeroMemory(cand3);
//---
   IndexToPatternType(cand1,index1);
   IndexToPatternType(cand2,index2);
   IndexToPatternType(cand3,index3);

//--- Abrufen des abrufen Kerzentyps
   GetCandleType(symbol,timeframe,prev_cand2,shift+2);                            // Vorherige Kerze
   GetCandleType(symbol,timeframe,prev_cand,shift+1);                             // Vorherige Kerze
   GetCandleType(symbol,timeframe,cur_cand,shift);                                // Aktuelle Kerze
//---
   if(cur_cand.m_type==cand1.m_type && cur_cand.m_bull==cand1.m_bull && 
      prev_cand.m_type==cand2.m_type && prev_cand.m_bull==cand2.m_bull && 
      prev_cand2.m_type==cand3.m_type && prev_cand2.m_bull==cand3.m_bull)
      return(true);
   return(false);
  }

Found

Die Methode liefert die Anzahl der gefundenen Muster des angegebenen Typs zurück. Sie hat 3 Methodenüberladungen für bestehende Muster TYPE_PATTERN, sowie für generierte Muster, bestehend aus 1-3 einfachen Kerzentypen.

   //--- Gibt die Anzahl der gefundenen Muster des angegebenen Typs zurück.
   int               Found(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern);
   int               Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index);
   int               Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2);
   int               Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3);

Parameter

  • symbol  Ausgewähltes Symbol der Suche.
  • timeframe  Ausgewählter Zeitrahmen.
  • patternExistierende Mustertypen aus TYPE_PATTERN.
  • index,index1,index2,index3 Index der einfachen Kerzentypen (Block 4 in Abb.1).

Rückgabewert

Anzahl der gefundenen Muster des angegebenen Typs.

Umsetzung

Die Umsetzung dieser Methode ist ziemlich einfach. Die wichtigsten Operationen im Zusammenhang mit der Erhebung von Statistiken werden mit der 'private' Methode PatternStat() durchgeführt.

//+------------------------------------------------------------------+
//| Gibt die Anzahl der gefundenen Muster des angegebenen Typs zurück|
//+------------------------------------------------------------------+
int CPattern::Found(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern)
  {
   PatternStat(symbol,timeframe,pattern);
   return(m_found);
  }
//+------------------------------------------------------------------+
//| Gibt die Anzahl der gefundenen Muster des angegebenen Typs zurück|
//+------------------------------------------------------------------+
int CPattern::Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1)
  {
   PatternStat(symbol,timeframe,index1);
   return(m_found);
  }
//+------------------------------------------------------------------+
//| Gibt die Anzahl der gefundenen Muster des angegebenen Typs zurück|
//+------------------------------------------------------------------+
int CPattern::Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2)
  {
   PatternStat(symbol,timeframe,index1,index2);
   return(m_found);
  }
//+------------------------------------------------------------------+
//| Gibt die Anzahl der gefundenen Muster des angegebenen Typs zurück|
//+------------------------------------------------------------------+
int CPattern::Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3)
  {
   PatternStat(symbol,timeframe,index1,index2,index3);
   return(m_found);
  }

Die Methode PatternStat() hat zwei Typen: für bestehende und für erzeugte Muster. Untersuchen wir die Details. Der Erste ist gedacht für Muster vom Typ der Enumeration TYPE_PATTERN:

//+------------------------------------------------------------------+
//| Abrufen der Statistik der gegebenen Muster                       |
//+------------------------------------------------------------------+
CPattern::PatternStat(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern)
  {
//---
   int pattern_counter=0;
//---
   RATING_SET pattern_coef={0,0,0,0,0,0};
//---
   for(int i=m_range_total;i>4;i--)
     {
      if(CheckPattern(symbol,timeframe,i)==pattern)
        {
         pattern_counter++;
         if(pattern==HUMMER || pattern==INVERT_HUMMER || pattern==HANDING_MAN)
            GetCategory(symbol,timeframe,pattern_coef,i-3);
         else
            GetCategory(symbol,timeframe,pattern_coef,i-4);
        }
     }
//---
   CoefCalculation(pattern_coef,pattern_counter);
  }

Der zweite wird für erzeugte Muster mit den Indices der einfachen Kerzentypen.

//+------------------------------------------------------------------+
//| Abrufen der Statistik der gegebenen Muster                       |
//+------------------------------------------------------------------+
void CPattern::PatternStat(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2=0,int index3=0)
  {
   CANDLE_STRUCTURE cand1,cand2,cand3,cur_cand,prev_cand,prev_cand2;
   RATING_SET rating={0,0,0,0,0,0};
   int pattern_total=0,pattern_size=1;
//---
   ZeroMemory(cand1);
   ZeroMemory(cand2);
   ZeroMemory(cand3);
   ZeroMemory(cur_cand);
   ZeroMemory(prev_cand);
   ZeroMemory(prev_cand2);
//---
   if(index2>0)
      pattern_size=2;
   if(index3>0)
      pattern_size=3;
//---
   if(pattern_size==1)
      IndexToPatternType(cand1,index1);
   else if(pattern_size==2)
     {
      IndexToPatternType(cand1,index1);
      IndexToPatternType(cand2,index2);
     }
   else if(pattern_size==3)
     {
      IndexToPatternType(cand1,index1);
      IndexToPatternType(cand2,index2);
      IndexToPatternType(cand3,index3);
     }
//---
   for(int i=m_range_total;i>5;i--)
     {
      if(pattern_size==1)
        {
         //--- Abrufen des abrufen Kerzentyps
         GetCandleType(symbol,timeframe,cur_cand,i);                                       // Aktuelle Kerze
         //---
         if(cur_cand.m_type==cand1.m_type && cur_cand.m_bull==cand1.m_bull)
           {
            pattern_total++;
            GetCategory(symbol,timeframe,rating,i-3);
           }
        }
      else if(pattern_size==2)
        {
         //--- Abrufen des abrufen Kerzentyps
         GetCandleType(symbol,timeframe,prev_cand,i);                                        // Vorherige Kerze
         GetCandleType(symbol,timeframe,cur_cand,i-1);                                       // Aktuelle Kerze
         //---

         if(cur_cand.m_type==cand1.m_type && cur_cand.m_bull==cand1.m_bull && 
            prev_cand.m_type==cand2.m_type && prev_cand.m_bull==cand2.m_bull)
           {
            pattern_total++;
            GetCategory(symbol,timeframe,rating,i-4);
           }
        }
      else if(pattern_size==3)
        {
         //--- Abrufen des abrufen Kerzentyps
         GetCandleType(symbol,timeframe,prev_cand2,i);                                       // Vorherige Kerze
         GetCandleType(symbol,timeframe,prev_cand,i-1);                                      // Vorherige Kerze
         GetCandleType(symbol,timeframe,cur_cand,i-2);                                       // Aktuelle Kerze
         //---
         if(cur_cand.m_type==cand1.m_type && cur_cand.m_bull==cand1.m_bull && 
            prev_cand.m_type==cand2.m_type && prev_cand.m_bull==cand2.m_bull && 
            prev_cand2.m_type==cand3.m_type && prev_cand2.m_bull==cand3.m_bull)
           {
            pattern_total++;
            GetCategory(symbol,timeframe,rating,i-5);
           }
        }
     }
//---
   CoefCalculation(rating,pattern_total);
  }

Diese beiden Umsetzungen der Methode beinhalten eine neue Methode. Das ist die 'private' Methode CoefCalculation():

   //--- Berechnen der Koeffizienten 
   bool              CoefCalculation(RATING_SET &rate,int found);

Sie verarbeitet alle Ergebnisse, die bei der Suche und dem Testen von Mustern erzielt wurden. Ihre Argumente enthalten einen Zeiger auf die Struktur RATING_SET, die für die Sammlung von Daten über die Ergebnisse der Mustereffizienzprüfung und die Anzahl der gefundenen Muster verantwortlich ist. Alle anderen Parameter und Eigenschaften der analysierten Muster werden mit der Methode CoefCalculation() berechnet.

//+------------------------------------------------------------------+
//| Berechnung der Effizienz der Bewertungskoeffizienten             |
//+------------------------------------------------------------------+
bool CPattern::CoefCalculation(RATING_SET &rate,int found)
  {
   int sum1=0,sum2=0;
   sum1=rate.m_a_uptrend+rate.m_b_uptrend+rate.m_c_uptrend;
   sum2=rate.m_a_dntrend+rate.m_b_dntrend+rate.m_c_dntrend;
//---
   m_probability1=(found>0)?NormalizeDouble((double)sum1/found*100,2):0;
   m_probability2=(found>0)?NormalizeDouble((double)sum2/found*100,2):0;
   m_efficiency1=(found>0)?NormalizeDouble((m_k1*rate.m_a_uptrend+m_k2*rate.m_b_uptrend+m_k3*rate.m_c_uptrend)/found,3):0;
   m_efficiency2=(found>0)?NormalizeDouble((m_k1*rate.m_a_dntrend+m_k2*rate.m_b_dntrend+m_k3*rate.m_c_dntrend)/found,3):0;
   m_found=found;
   m_coincidence=((double)found/m_range_total*100);
   return(true);
  }

Koinzidenz

Liefert die Häufigkeit des Auftretens der Muster. Sie hat 3 Methodenüberladungen für bestehende Muster TYPE_PATTERN, sowie für generierte Muster, bestehend aus 1-3 einfachen Kerzentypen.

   //--- Liefert die Häufigkeit des Auftretens der Muster
   double            Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern);
   double            Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index);
   double            Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2);
   double            Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3);

Parameter

  • symbolSymbol selected for search.
  • timeframeausgewählter Zeitrahmen.
  • patternExistierende Mustertypen aus TYPE_PATTERN.
  • index,index1,index2,index3Index der einfachen Kerzentypen (Block 4 in Abb.1).

Rückgabewert

Die Häufigkeit des Auftretens der Muster in Prozenten

Umsetzung

Ähnlich der Methode Found(). Der einzige Unterschied besteht darin, dass er den Wert der Variable m_coincidence zurückgibt.

//+------------------------------------------------------------------+
//| Liefert die Häufigkeit des Auftretens der Muster                 |
//+------------------------------------------------------------------+
double CPattern::Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern)
  {
   PatternStat(symbol,timeframe,pattern);
   return(m_coincidence);
  }
//+------------------------------------------------------------------+
//| Liefert die Häufigkeit des Auftretens der Muster                 |
//+------------------------------------------------------------------+
double CPattern::Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1)
  {
   PatternStat(symbol,timeframe,index1);
   return(m_coincidence);
  }
//+------------------------------------------------------------------+
//| Liefert die Häufigkeit des Auftretens der Muster                 |
//+------------------------------------------------------------------+
double CPattern::Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2)
  {
   PatternStat(symbol,timeframe,index1,index2);
   return(m_coincidence);
  }
//+------------------------------------------------------------------+
//| Liefert die Häufigkeit des Auftretens der Muster                 |
//+------------------------------------------------------------------+
double CPattern::Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3)
  {
   PatternStat(symbol,timeframe,index1,index2,index3);
   return(m_coincidence);
  }

Wahrscheinlichkeit

Gibt die prozentuale Wahrscheinlichkeit einer Bewegung nach dem angegebenen Muster zurück. Sie hat 3 Methodenüberladungen für bestehende Muster TYPE_PATTERN, sowie für generierte Muster, bestehend aus 1-3 einfachen Kerzentypen.

   //--- Gibt die Wahrscheinlichkeit einer Bewegung nach dem angegebenen Muster zurück. 
   double            Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,TYPE_TREND trend);
   double            Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index,TYPE_TREND trend);
   double            Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,TYPE_TREND trend);
   double            Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,TYPE_TREND trend);

Parameter

  • symbolAusgewähltes Symbol der Suche.
  • timeframeausgewählter Zeitrahmen.
  • patternExistierende Mustertypen aus TYPE_PATTERN.
  • index,index1,index2,index 3Index der einfachen Kerzentypen (Block 4 in Abb.1).

  • trendTYPE_TREND
//+------------------------------------------------------------------+
//| Trendtype                                                        |
//+------------------------------------------------------------------+
enum TYPE_TREND
  {
   UPPER,               //Aufwärtstrend
   DOWN,                //Abwärtstrend
   FLAT                 //Seitwärtsbewegung
  };
//+------------------------------------------------------------------+

Rückgabewert

Die prozentuale Wahrscheinlichkeit einer Bewegung nach dem gegebenen Muster.

Umsetzung

Ähnlich der Methode Found(). Der einzige Unterschied besteht darin, dass er den Wert der Variable m_coincidence oder m_probability2 je nach dem ausgewählten Trendtyp zurückgibt.

//+------------------------------------------------------------------+
//| Liefert die Wahrscheinlichkeit einer Bewegung nach dem Muster.   |
//+------------------------------------------------------------------+
double CPattern::Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,pattern);
   if(trend==UPPER)
      return(m_probability1);
   if(trend==DOWN)
      return(m_probability2);
   return(0);
  }
//+------------------------------------------------------------------+
//| Liefert die Wahrscheinlichkeit einer Bewegung nach dem Muster.   |
//+------------------------------------------------------------------+
double CPattern::Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,index1);
   if(trend==UPPER)
      return(m_probability1);
   if(trend==DOWN)
      return(m_probability2);
   return(0);
  }
//+------------------------------------------------------------------+
//| Liefert die Wahrscheinlichkeit einer Bewegung nach dem Muster.   |
//+------------------------------------------------------------------+
double CPattern::Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,index1,index2);
   if(trend==UPPER)
      return(m_probability1);
   if(trend==DOWN)
      return(m_probability2);
   return(0);
  }
//+------------------------------------------------------------------+
//| Liefert die Wahrscheinlichkeit einer Bewegung nach dem Muster.   |
//+------------------------------------------------------------------+
double CPattern::Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,index1,index2,index3);
   if(trend==UPPER)
      return(m_probability1);
   if(trend==DOWN)
      return(m_probability2);
   return(0);
  }

Efficiency

Die Methode gibt den Effizienzkoeffizienten zurück. Sie hat 3 Methodenüberladungen für bestehende Muster TYPE_PATTERN, sowie für generierte Muster, bestehend aus 1-3 einfachen Kerzentypen.

   //--- Rückgabe des Effizienzkoeffizienten der Muster 
   double            Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,TYPE_TREND trend);
   double            Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index,TYPE_TREND trend);
   double            Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,TYPE_TREND trend);
   double            Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,TYPE_TREND trend);

Parameter

  • symbolAusgewähltes Symbol der Suche.
  • timeframeausgewählter Zeitrahmen.
  • patternExistierende Mustertypen aus TYPE_PATTERN.
  • index,index1,index2,index3Index der einfachen Kerzentypen (Block 4 in Abb.1).
  • trendTrendtyp, TYPE_TREND
//+------------------------------------------------------------------+
//| Trendtype                                                        |
//+------------------------------------------------------------------+
enum TYPE_TREND
  {
   UPPER,               //Aufwärtstrend
   DOWN,                //Abwärtstrend
   FLAT                 //Seitwärtsbewegung
  };
//+------------------------------------------------------------------+

Rückgabewert

Den Effizienzkoeffizienten eines Musters.

Umsetzung

Ähnlich der Methode Found(). Der einzige Unterschied besteht darin, dass er den Wert der Variablen m_efficiency1 oder m_efficiency2 in Abhängigkeit von des gewählten Trendtyps zurückgibt.

//+------------------------------------------------------------------+
//| Liefert die Wahrscheinlichkeit einer Bewegung nach dem Muster.   |
//+------------------------------------------------------------------+
double CPattern::Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,pattern);
   if(trend==UPPER)
      return(m_efficiency1);
   if(trend==DOWN)
      return(m_efficiency2);
   return(0);
  }
//+------------------------------------------------------------------+
//| Liefert die Wahrscheinlichkeit einer Bewegung nach dem Muster.   |
//+------------------------------------------------------------------+
double CPattern::Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,index1);
   if(trend==UPPER)
      return(m_efficiency1);
   if(trend==DOWN)
      return(m_efficiency2);
   return(0);
  }
//+------------------------------------------------------------------+
//| Liefert die Wahrscheinlichkeit einer Bewegung nach dem Muster.   |
//+------------------------------------------------------------------+
double CPattern::Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,index1,index2);
   if(trend==UPPER)
      return(m_efficiency1);
   if(trend==DOWN)
      return(m_efficiency2);
   return(0);
  }
//+------------------------------------------------------------------+
//| Liefert die Wahrscheinlichkeit einer Bewegung nach dem Muster.   |
//+------------------------------------------------------------------+
double CPattern::Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,index1,index2,index3);
   if(trend==UPPER)
      return(m_efficiency1);
   if(trend==DOWN)
      return(m_efficiency2);
   return(0);
  }

Praktische Verwendung

Nachdem wir uns Werkzeuge für die Arbeit mit Mustern angesehen haben, lassen Sie uns zwei Indikatoren und einen Expertenberater erstellen, um Beispiele für die Nutzung der Bibliotheken zu demonstrieren.

CandleDetector

Beginnen wir mit dem Indikator, der auf einem Chart eine Kerze des ausgewählten Typs aus der Aufzählung TYPE_CANDLESTICK zeigt. Erstellen Sie den Ordner Pattern im Ordner Indicators. Erstellen Sie in diesem Ordner die Datei CandleDetector.mq5, der der Name des zu erstellenden Indikators ist. Lassen Sie uns die Bibliothek Pattern.mqh für Musteroperationen einbinden und erste Eigenschaften des zukünftigen Indikators einstellen:

//+------------------------------------------------------------------+
//|                                               CandleDetector.mq5 |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                           https://www.mql5.com/en/users/alex2356 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://www.mql5.com/en/users/alex2356"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
#include <Pattern/Pattern.mqh>
//+----------------------------------------------+
//|  Parameter der Indikatordarstellung          |
//+----------------------------------------------+
//---- Zeichnen des Indikators mit Pfeilen
#property indicator_type1   DRAW_ARROW
//---- Linienbreite des Indikators
#property indicator_width1  1

Der nächste Schritt besteht darin, die wichtigsten Einstellungen festzulegen, die sich auf die Anzeige dieses oder jenes Kerzentyps auswirkt. 

//+----------------------------------------------+
//| Indikator Eingabeparameter                   |
//+----------------------------------------------+
input TYPE_CANDLESTICK  CandleType=1;                 // Kerzentyp
input color             LabelColor=clrCrimson;
input double            LongCoef=1.3;
input double            ShortCoef=0.5;
input double            DojiCoef=0.04;
input double            MaribozuCoef=0.01;
input double            SpinCoef=1;
input double            HummerCoef1=0.1;
input double            HummerCoef2=2;
input int               TrendPeriod=5; 

Als Nächstes konfigurieren Sie bei der Initialisierung das Erscheinungsbild des Indikators und bestimmen alle Werte aus den Eingabeparametern für die Suche.

//+------------------------------------------------------------------+
//| Initialisierungsfunktion des nutzerdefinierten Indikators        |
//+------------------------------------------------------------------+
int OnInit()
  {
//---- Initialisieren der Variablen zu Beginn der Berechnung
   min_rates_total=TrendPeriod+1;
//---- Definieren der Genauigkeit der dargestellten Indikatorwerte
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);

//---- Setzen des dynamischen Arrays Signal[] als Indikatorpuffer
   SetIndexBuffer(0,Signal,INDICATOR_DATA);
//---- Starte die Indikatordarstellung ab 1
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,min_rates_total);
//---- Setzen der Indices der Puffer als Zeitreihen   
   ArraySetAsSeries(Signal,true);
//---- Setzen der Indikatorwerte, die nicht auf dem Chart dargestellt werden
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE);
//---- Symbol des Indikators
   PlotIndexSetInteger(0,PLOT_ARROW,108);
//---
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,LabelColor);
//----
   Pat.Long_coef(LongCoef);
   Pat.Short_coef(ShortCoef);
   Pat.Doji_coef(DojiCoef);
   Pat.Maribozu_coef(MaribozuCoef);
   Pat.Spin_coef(SpinCoef);
   Pat.Hummer_coef1(HummerCoef1);
   Pat.Hummer_coef2(HummerCoef2);
   Pat.TrendPeriod(TrendPeriod);
   return(INIT_SUCCEEDED);
  }

Achten Sie auf die Methode CandleType() — sie wird verwendet, um nach dem ausgewählten Kerzentyp im Diagramm zu suchen.

//+------------------------------------------------------------------+
//| Funktion des nutzerdefinierten Indikators                        |
//+------------------------------------------------------------------+
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[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---- Prüfen, ob es genug Bars für die Berechnung gibt
   if(rates_total<min_rates_total)
      return(0);
//---- Deklarieren der lokalen Variablen 
   int limit,bar;
//---- Setzen der Indices der Arrays als Zeitreihen  
   ArraySetAsSeries(low,true);
//---- Berechnen des 'ersten' Index der Bars für die Neuberechnung
   if(prev_calculated>rates_total || prev_calculated<=0)          // Prüfen auf den Erststart der Indikatorberechnung
      limit=rates_total-min_rates_total;                          // Startindex für die Berechnung der aller Bars
   else
      limit=rates_total-prev_calculated;                          // Startindex für die Berechnung der neuen Bars
//---- Hauptschleife der Indikatorberechnung
   for(bar=limit; bar>=0; bar--)
     {
      Signal[bar]=0.0;
      if(Pat.CandleType(Symbol(),PERIOD_CURRENT,bar)==CandleType)
         Signal[bar]=low[bar]-200*_Point;
     }
   return(rates_total);
  }
//+------------------------------------------------------------------+

Ein Beispiel für die Arbeit des Indikators ist in Abb.3 (Suche nach einer langen Kerze) dargestellt.

Abb.3 Das Funktionsbeispiel des Indikators CandleDetector.

PatternDetector

Der zweite Indikator sucht nach einem bestimmten Muster aus der Enumeration TYPE_PATTERN. Die Implementierung ist sehr ähnlich wie die vorherige. Dieser Code unterscheidet sich in einem Eingabeparameter und in der im Berechnungsteil verwendeten Methode.

//+----------------------------------------------+
//| Indikator Eingabeparameter                   |
//+----------------------------------------------+
input TYPE_PATTERN      PatternType=1;                // Mustertyp
input color             LabelColor=clrCrimson;
input double            LongCoef=1.3;
input double            ShortCoef=0.5;
input double            DojiCoef=0.04;
input double            MaribozuCoef=0.01;
input double            SpinCoef=1;
input double            HummerCoef1=0.1;
input double            HummerCoef2=2;
input int               TrendPeriod=5;
//---
CPattern Pat;
double Signal[];
//---- Deklarieren der ganzzahligen Variablen für den Beginn der Datenberechnung
int min_rates_total;
//+------------------------------------------------------------------+
//| Initialisierungsfunktion des nutzerdefinierten Indikators        |
//+------------------------------------------------------------------+  
void OnInit()
  {
//---- Initialisieren der Variablen zu Beginn der Berechnung
   min_rates_total=TrendPeriod+2;
//---- Definieren der Genauigkeit der dargestellten Indikatorwerte
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);

//---- Setzen des dynamischen Arrays SignUp[] als Indikatorpuffer
   SetIndexBuffer(0,Signal,INDICATOR_DATA);
//---- Starte die Indikatordarstellung ab 1
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,min_rates_total);
//---- Setzen der Indices der Puffer als Zeitreihen   
   ArraySetAsSeries(Signal,true);
//---- Setzen der Indikatorwerte, die nicht auf dem Chart dargestellt werden
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE);
//---- Symbol des Indikators
   PlotIndexSetInteger(0,PLOT_ARROW,108);
//---
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,LabelColor);
//----
   Pat.Long_coef(LongCoef);
   Pat.Short_coef(ShortCoef);
   Pat.Doji_coef(DojiCoef);
   Pat.Maribozu_coef(MaribozuCoef);
   Pat.Spin_coef(SpinCoef);
   Pat.Hummer_coef1(HummerCoef1);
   Pat.Hummer_coef2(HummerCoef2);
   Pat.TrendPeriod(TrendPeriod);
  }
//+------------------------------------------------------------------+
//| Funktion des nutzerdefinierten Indikators                        |
//+------------------------------------------------------------------+
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[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---- Prüfen, ob es genug Bars für die Berechnung gibt
   if(rates_total<min_rates_total)
      return(0);
//---- Deklarieren der lokalen Variablen 
   int limit,bar;
//---- Setzen der Indices der Arrays als Zeitreihen  
   ArraySetAsSeries(low,true);
//---- Berechnen des 'ersten' Index der Bars für die Neuberechnung
   if(prev_calculated>rates_total || prev_calculated<=0)       // Prüfen auf den Erststart der Indikatorberechnung
      limit=rates_total-min_rates_total;                       // Startindex für die Berechnung der aller Bars
   else
      limit=rates_total-prev_calculated;                       // Startindex für die Berechnung der neuen Bars
//---- Hauptschleife der Indikatorberechnung
   for(bar=limit; bar>0; bar--)
     {
      Signal[bar]=0.0;
      if(Pat.PatternType(_Symbol,_Period,PatternType,bar))
         Signal[bar]=low[bar]-200*_Point;
     }
   return(rates_total);
  }
//+------------------------------------------------------------------+

Die Ergebnisse von PatternDetector sind in Abb.4 dargestellt (Suche nach dem Engulfing - Aufwärtsmuster).

Abb.4 Das Funktionsbeispiel des Indikators PatternDetector.

Lassen Sie uns nun einen Expert Advisor erstellen, der die Muster auf dem Chart findet und, je nach dem ausgewählten Mustern, die Positionen eröffnet. Individuelle Mustertypen können für jeden Eröffnungstyp verwendet werden. Ein zusätzlicher Modus ermöglicht die Auswahl zwischen bestehenden Mustern und Mustern, die mit einfachen Kerzentypen erzeugt wurden.

Lassen Sie uns das Verzeichnis der Muster im Ordner Experts erstellen und die Datei PatternExpert.mq5 hinzufügen, die den EA-Code enthält. Binden Sie zunächst die Bibliothek Pattern.mqh für die Arbeit mit den Mustern und die Bibliothek Trade.mqh für die Handelsoperationen ein. Deklarieren Sie Klasseninstanzen und tragen Sie die Enumeration PATTERN_MODE ein, die es ermöglicht, zwischen bestehenden und generierten Mustern zu wechseln.

//+------------------------------------------------------------------+
//|                                                PatternExpert.mq5 |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                           https://www.mql5.com/en/users/alex2356 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://www.mql5.com/en/users/alex2356"
#property version   "1.00"
#include <Pattern/Pattern.mqh>
#include "Trade.mqh" 
CTradeBase Trade;
CPattern Pat;
//+------------------------------------------------------------------+
//| Modus der Mustersuche                                            |
//+------------------------------------------------------------------+
enum PATTERN_MODE
  {
   EXISTING,
   GENERATED
  };

Definieren Sie nun die Eingabeparameter des Expert Advisors. Die EA-Parameter stehen im ersten Block:

//+------------------------------------------------------------------+
//| Expert Advisor Eingabeparameter                                  |
//+------------------------------------------------------------------+
input    string               Inp_EaComment="Pattern Strategy";         // EA Kommentar
input    double               Inp_Lot=0.01;                             // Lot
input    MarginMode           Inp_MMode=LOT;                            // Geldmanagement

//--- EA Parameter
input    string               Inp_Str_label="===EA parameters===";      // Name
input    int                  Inp_MagicNum=1111;                        // Magicnummer
input    int                  Inp_StopLoss=40;                          // Stop-Loss (Punkte)
input    int                  Inp_TakeProfit=30;                        // Take-Profit (Punkte)

Im zweiten Teil stehen die Einstellungen und Handelsparameter. 

//--- Handelsparameter
input ENUM_TIMEFRAMES         Timeframe=PERIOD_CURRENT;                 // Aktueller Zeitrahmen
input PATTERN_MODE            PatternMode=0;                            // Modus der Muster
input TYPE_PATTERN            BuyPatternType=ENGULFING_BULL;            // Mustertyp für Kaufen
input TYPE_PATTERN            SellPatternType=ENGULFING_BEAR;           // Mustertyp für Verkaufen
input uint                    BuyIndex1=1;                              // Kaufindex der einfachen candle1
input uint                    BuyIndex2=0;                              // Kaufindex der einfachen candle2
input uint                    BuyIndex3=0;                              // Kaufindex der einfachen candle3
input uint                    SellIndex1=1;                             // Verkaufsindex der einfachen candle1
input uint                    SellIndex2=0;                             // Verkaufsindex der einfachen candle2
input uint                    SellIndex3=0;                             // Verkaufsindex der einfachen candle3
input double                  LongCoef=1.3;                             // Koeff. langen Kerze
input double                  ShortCoef=0.5;                            // Koeff. kurzen Kerze
input double                  DojiCoef=0.04;                            // Koeff. Doji
input double                  MaribozuCoef=0.01;                        // Koeff. Maribozu
input double                  SpinCoef=1;                               // Koeff. Spin candle coef
input double                  HummerCoef1=0.1;                          // Koeff1. Hummer
input double                  HummerCoef2=2;                            // Koeff2. Hummer
input int                     TrendPeriod=5;                            // Periodenlänge des Trends

Betrachten wir einige Parameter genauer:

  • Current Timeframe — Zeitrahmen, der für Operationen ausgewählt wurde. Ermöglicht die Auswahl des Zeitrahmens während der Optimierung. Der aktuelle Zeitrahmen des Charts ist standardmäßig ausgewählt.
  • Pattern Mode — Modus der Musterauswahl. EXISTING — bestehende Muster; zwei Einstellungen für den Mustertyp sind anwendbar: Kaufen und Verkaufen. GENERATED — erzeugte Muster. In diesem Modus werden die Einstellungen für den Mustertyp Kauf/Verkauf ignoriert und stattdessen BuyIndex1-3 und SellIndex1-3 verwendet.
  • Buy Pattern Type/ Sell Pattern Type — wählen Sie Muster aus, um geeignete Handelsoperationen zu eröffnen. 
  • BuyIndex1-3/SellIndex1-3 — wählen Sie ein Muster aus einfachen Kerzentypen (Abb.1 Block 4), bei deren Auftreten eine Kauf-/Verkaufsposition eröffnet wird. 

Andere Parameter ähneln denen der oben beschriebenen Indikatoren. Zusätzlich zu den Prüfungen, die in den Initialisierungsblöcken the Trend Period value eingestellt sind, der die On-Chart-Erkennung von Mustern beeinflusst.

//+------------------------------------------------------------------+
//| Initialisierungsfunktion des Experten                            |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Prüfen der Verbindung zum Handelsserver
   if(!TerminalInfoInteger(TERMINAL_CONNECTED))
     {
      Print(Inp_EaComment,": No Connection!");
      return(INIT_FAILED);
     }
//--- Prüfen der Handelserlaubnis von Programmen
   if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
     {
      Print(Inp_EaComment,": Trade is not allowed!");
      return(INIT_FAILED);
     }
//---
   Pat.TrendPeriod(TrendPeriod);
//---
   return(INIT_SUCCEEDED);
  }

Der Berechnungsteil ist leicht verständlich. Betrachten wir die Funktion für das Kaufen und Verkaufen auf Grund der Signale.

//+------------------------------------------------------------------+
//| Experten Funktion OnTick                                         |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(!Trade.IsOpenedByMagic(Inp_MagicNum))
     {
      //--- Eröffnen einer Position wegen eines Kaufsignals
      if(BuySignal())
         Trade.BuyPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss,Inp_TakeProfit,Inp_MagicNum,Inp_EaComment);
      //--- Eröffnen einer Position wegen eines Verkaufssignals
      if(SellSignal())
         Trade.SellPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss,Inp_TakeProfit,Inp_MagicNum,Inp_EaComment);
     }
  }

Diese Funktionen sind ähnlich und so betrachten wir eine von ihnen BuySignal(), die nach einem Kaufsignal sucht.

//+------------------------------------------------------------------+
//| Kaufbedingungen                                                  |
//+------------------------------------------------------------------+
bool BuySignal()
  {
   if(PatternMode==0)
     {
      if(BuyPatternType==NONE)
         return(false);
      if(Pat.PatternType(_Symbol,Timeframe,BuyPatternType,1))
         return(true);
     }
   else if(PatternMode==1)
     {
      if(BuyIndex1>0 && BuyIndex2==0 && BuyIndex3==0)
        {
         if(Pat.PatternType(_Symbol,Timeframe,BuyIndex1,1))
            return(true);
        }
      else if(BuyIndex1>0 && BuyIndex2>0 && BuyIndex3==0)
        {
         if(Pat.PatternType(_Symbol,Timeframe,BuyIndex1,BuyIndex2,1))
            return(true);
        }
      else if(BuyIndex1>0 && BuyIndex2>0 && BuyIndex3>0)
        {
         if(Pat.PatternType(_Symbol,Timeframe,BuyIndex1,BuyIndex2,BuyIndex3,1))
            return(true);
        }
     }
   return(false);
  }

Die Funktion verfügt eine Überprüfung des aktuell ausgewählten Modus, bestehende Muster oder erstellte Muster. Die Eingangsparameter werden entsprechend ausgewählt: TYPE_PATTERN oder eine Reihe von Indizes des erstellten Musters.

Lassen Sie uns den resultierenden Expert Advisor in zwei Modi testen und optimieren: mit bestehenden Mustern aus der Enumeration TYPE_PATTERN und mit erstellten Mustern aus einfachen Kerzentypen, wie in Abb.1 Block 4 dargestellt.

Der Expert Advisor wir mit folgenden Parametern getestet:

  • Zeitspanne: Für den Modus Aufwärtstrend 01.01.2018 — 15.03.2018.
  • Währungspaar EURUSD.
  • Ausführung: Ohne Verzögerung. Dies sind keine Hochfrequenzstrategien, damit wird der Effekt einer Verzögerung sehr klein.
  • Test: 1 Minute OHLC. 
  • Einlage: 1000 USD.
  • Test: 1 Minute OHLC. Vortests mit realen Ticks zeigen fast die gleichen Ergebnisse.
  • Server: MetaQuotes-Demo.
  • Kurse: 5 Dezimalstellen.

Modus der erstellten Muster.

Bestimmen wir die zu testende und optimierende Parameter.

Abb.5 Die Parameter der Optimierung im Modus erstellte Muster.

Abb.5 zeigt die Test- und Optimierungsbedingungen. Die besten Parameter, die als Ergebnis der Prüfung erhalten wurden, werden in der zweiten Spalte Wert angezeigt. Die Backtest-Ergebnisse und die Grafik sind in Abbildung 6 unten dargestellt. 

Abb.6 Beste Testergebnisse der Parameter im Modus erstellte Muster.

Modus bestehender Muster.

Die Parameter für das Testen und Optimieren.

Abb.7 Die Parameter zur Optimierung im Modus bestehende Muster. 

Auch hier werden in der zweiten Spalte die Parameter des besten Optimierungsergebnisses angezeigt. Lassen Sie uns nun einen einzigen Test durchführen. Die Ergebnisse sind in Abbildung 8 unten dargestellt.

Abb.8 Beste Testergebnisse für Parameter im Modus Bestehende Muster.


Schlussfolgerungen

Das unten angehängte Archiv enthält alle beschriebenen Dateien in Ordnern. Für einen korrekten Betrieb sollten Sie den Ordner MQL5 im Stammverzeichnis des Terminals speichern. Um diesen Stammordner zu finden, in dem sich der Ordner MQL5 befindet, drücken Sie Ctrl+Shift+D im MetaTrader 5 oder verwenden Sie das Kontextmenü wie in Abbildung 9 gezeigt.

Abb.9 So finden Sie den Ordner MQL5 im Stammverzeichnis von MetaTrader5.

Programme, die im diesem Artikel verwendet werden

#
 Name
Typ
Beschreibung
1
Pattern.mqh Bibliothek  Bibliothek für das Arbeiten mit den Mustern
2 CandleDetector.mq5 Indikator  Indikator für die Suche nach den Kerzen
3 PatternDetector.mq5 Indikator  Indikator für die Suche nach den Mustern
4 PatternExpert.mq5  Expert Advisor   Ein Expert Advisor, der die Muster handelt
5 Trade.mqh Bibliothek  Klasse mit den Handelsfunktionen