
Untersuchung von Techniken zur Analyse der Kerzen (Teil III): Eine Bibliothek für die Musterbearbeitung
Inhaltsverzeichnis
- Einführung
- Bibliotheksstruktur
- Bibliotheksentwicklung
- CandleType. Ausgewählter Kerzentyp
- PatternType. Mustertyp
- Found. Die Anzahl der gefundenen Muster des angegebenen Typs
- Coincidence. Wie oft der angegebene Mustertyp gefunden wurde.
- Probability. Die Wahrscheinlichkeit der Bewegung nach dem Auftreten des Musters
- Efficiency. Der Koeffizient des Wirkungsgrads des Musters
- Praktische Verwendung
- CandleDetector. Indikator für die Suche nach den Kerzen
- PatternDetector. Indikator für die Suche nach den Mustern
- PatternExpert. Expert Advisor für den Handel der Muster
- Schlussfolgerungen
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.
- Patterns found. Die Anzahl der gefundenen Muster des angegebenen Typs.
- Occurrence. Der Prozentsatz der Anzahl der gefundenen Muster in der gesamten Zeitspanne.
- Probability Wahrscheinlichkeit der Aufwärts- oder Abwärtsbewegung.
- Efficiency ratios Effizienzverhältnisse während der Auf- und Abwärtsbewegung für dieses Kerzenmuster.
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
TYPE_CANDLESTICK CandleType(const string symbol,const ENUM_TIMEFRAMES timeframe,const int shift);
Parameter
- symbol — Ausgewähltes Symbol der Suche
- timeframe — Gewählter Zeitrahmen
- shift — Index der gewählten Kerze, ab der die Analyse beginnen soll.
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
- symbol — Ausgewähltes Symbol der Suche.
- timeframe — Ausgewählter Zeitrahmen.
- pattern,pattern[] — Existierende Mustertypen aus TYPE_PATTERN.
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 };
- index,index1,index2,index3 — Index der einfachen Kerzentypen (Block 4 in Abb.1).
- shift — Index der gewählten Kerze, ab der die Analyse beginnen soll, beginnend bei 0.
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.
- pattern — Existierende 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
- symbol — Symbol selected for search.
- timeframe — ausgewählter Zeitrahmen.
- pattern — Existierende Mustertypen aus TYPE_PATTERN.
- index,index1,index2,index3 — Index 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
- symbol — Ausgewähltes Symbol der Suche.
- timeframe — ausgewählter Zeitrahmen.
- pattern — Existierende Mustertypen aus TYPE_PATTERN.
- index,index1,index2,index 3— Index der einfachen Kerzentypen (Block 4 in Abb.1).
-
- trend— TYPE_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
- symbol — Ausgewähltes Symbol der Suche.
- timeframe — ausgewählter Zeitrahmen.
- pattern — Existierende Mustertypen aus TYPE_PATTERN.
- index,index1,index2,index3 — Index der einfachen Kerzentypen (Block 4 in Abb.1).
- trend — Trendtyp, 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 |
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/5751





- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.