
Merrill-Muster
Inhalt
Einführung
Der erste Versuch, ein System von Preismustern zu schaffen, wurde 1971 von Robert Levy unternommen. Er verwendete ein Muster aus fünf Punkten und prüfte dann, ob sie von Bedeutung waren. Er erzielte keine nennenswerten Ergebnisse, aber Arthur Merrill setzte seine Arbeit 10 Jahre später fort.
Er teilte die Muster in zwei Kategorien ein, die den Buchstaben M und W ähneln. Jede Kategorie enthält 16 Muster und eigene Unterkategorien. Merrill hat 6 Unterkategorien hervorgehoben:
- Aufwärtstrend
- Abwärtstrend
- Dreieck
- Expansion
- Kopf und Schultern
- Umgekehrte Kopf und Schultern
Wir werden die aktuelle Relevanz der Merrill-Muster anhand der Anwendung zum Testen definieren. Außerdem wäre es interessant, dieses Modell auf verschiedene Arten von Daten anzuwenden — wie die Schluss-, Hoch- und Tiefstpreise sowie Oszillatorwerte.
Definition und Anwendung
Um zu klären, wie und für welche Daten wir Merrill-Muster anwenden werden, müssen wir verstehen, was sie tatsächlich sind. Die beiden Hauptkategorien sind die Muster, die den Buchstaben M und W ähneln. Sie werden M und W Muster genannt. Jede der Kategorien enthält 16 Muster.
Abb. 1 stellt 16 M Muster dar. Wie wir sehen können, liegt der Unterschied in der gegenseitigen Anordnung der fünf Punkte, die das Muster ausmachen.
Abb. 1. Visuelle Darstellung von М Mustern
Abb. 2 zeigt 16 W-Muster. Wir werden nach diesen beiden Gruppen anhand von Preisdiagrammen und Indikatoren suchen, sowie mögliche Regeln untersuchen, bewerten und suchen.
Abb. 2. Visuelle Darstellung von W Mustern
Die Idee hinter jedem Muster läuft darauf hinaus, dass wir bei Auftreten einer bestimmten Formation erwarten können, dass sich der Preis in eine bestimmte Richtung bewegt und wir dann davon profitieren.
Um möglichst deutlich zu machen, in welchem Bereich und wie Merrill-Muster untersucht werden sollen, hier einige Beispiele. Abb. 3 zeigt ein übliches lineares USDCAD H1 Preischart. Diese Art der Darstellung wird nicht so häufig verwendet, da Kerzen und Bars beliebter geworden sind.
Abb. 3. Lineares USDCAD H1-Chart basierend auf den Schlusskursen
Hier sehen wir bereits einige der oben beschriebenen Muster. Dies soll der erste Studienschwerpunkt sein — die Anwendung auf das lineare Chart auf Basis der Schlusskurse. Außerdem werden wir lineare Charts überprüfen, die auf Eröffnungs-, Hoch- und Tiefstpreisen basieren.
Der zweite Studienbereich soll aus Oszillatoren bestehen, wie z.B.:
- Average True Range (ATR) — Volatilität des Marktes.
- Commodity Channel Index (CCI) misst die Differenz des Symbolpreises zum Durchschnitt.
- DeMarker (DeM).
- Force Index (FRC).
- Williams’ Percent Range (WPR) — dynamischer Indikator, der überkaufte/überverkaufte Zustände zeigt.
- Relative Strength Index (RSI).
- Momentum — Preisänderung einer vorgegebenen Zeitspanne.
Die Methode, die ich im Artikel Untersuchung von Techniken zur Analyse der Kerzen (Teil I): Überprüfen vorhandener Muster ist als Methode zur Bewertung von Mustern zu verwenden, die sie sowohl auf den Preis als auch auf die oben genannten Oszillatoren anwendbar ist. Die Idee dahinter ist einfach:
- Identifizieren des analysierten Musters auf einem bestimmten Probenabschnitt.
- Analyse der Preisbewegung nach der Identifizierung.
- Erfassung der Daten und Berechnung der Mustereffizienz.
Entwicklung des Testwerkzeugs
Bevor wir mit der Entwicklung beginnen, müssen wir definieren, welche Einstellungen sie enthalten soll. Das Tool soll aus dem Panel mit den Registerkarten Analysis und Settings. Es sind auch die Parameter aus dem Fenster EA-Einstellungen zu verwenden. Insgesamt sollen wir drei Abschnitte mit Werkzeugen für die Arbeit mit Mustern haben. Lassen Sie uns nun die Einstellungen in den einzelnen Abschnitten beschreiben.
Die Registerkarte Analysis enthält:
- Zwei Schaltflächensätze zur Auswahl der Arten von getesteten Mustern. Es gibt auch die Schaltflächen All M und All W zur schnellen Aus-/Abwahl von М- und W-Mustern.
- Eine Reihe von Schaltflächen zur Auswahl der getesteten Zeitrahmen und die Schaltfläche ALL zum Aus-/Abwählen der gesamten Schaltflächengruppe.
- Das Eingabefeld "Trendschwelle (Punkte)". Dies ist ein Gewinn in Punkten, die der Preis innerhalb von maximal drei Kerzen erreichen sollte, nachdem ein analysiertes Merrill-Muster identifiziert wurde.
- Die Schaltfläche öffnet das Dialogfenster zur Auswahl von Start- und Enddatum sowie der Testzeit.
- Das Eingabefeld mit dem Kontrollkästchen und der Schaltfläche ist ein Filter zum Auffinden der notwendigen Handelssymbole. Es hat eine Voreinstellung — Major. Es zeigt die wichtigsten Währungspaare an. Das Kontrollkästchen deaktiviert den Filter und zeigt alle verfügbaren Handelssymbole an.
- Handelssymbole, die in der Tabelle mit dem Filter ausgewählt wurden. Nach Auswahl aus der Liste wird die Musteranalyse durchgeführt.
- Die Ergebnistabelle besteht aus sieben Spalten:
- Figure name. In der Spalte wird ein Name eines analysierten Merrill-Musters angezeigt, z.B. M10 oder W12.
- Found. Anzahl der gefundenen Muster des angegebenen Typs des Probeabschnitts.
- Timeframe. Der Zeitrahmen auf dem das angegebene Muster gesucht wird.
- P, Uptrend. Die Wahrscheinlichkeit, dass der Preis um den Wert "Trend threshold (points)" nach dem Muster steigt.
- P, Dntrend. Die Wahrscheinlichkeit, dass der Preis um den Wert "Trend threshold (points)" nach dem Muster fällt.
- K, UpTrend/K, DnTrend. Dies ist ein Verhältnis, das in meinem Artikel Untersuchung von Techniken zur Analyse der Kerzen (Teil I): Überprüfen vorhandener Muster. Es wird bewertet, wie schnell der Preis einen bestimmten Gewinn erreicht, nachdem ein analysiertes Muster in Aufwärts- oder Abwärtsrichtung eines Trends erscheint.
Abb. 4 zeigt eine visuelle Umsetzung aller oben beschriebenen Symbole und Parameter.
Abb. 4. Registerkarte Analyse
Betrachten wir nun die Registerkarte Settings:
- Used indicator. Wählen Sie einen Indikator aus, auf den die Suche und Analyse von Merrill-Mustern angewendet werden soll.
- Bei der Berechnung der oben beschriebenen Verhältnisse von K, UpTrend/DnTrend werden Gewichtungskoeffizienten verwendet.
- Sprache der Nutzeroberfläche. Die Dropdown-Liste zur Auswahl der Oberflächensprache: Englisch oder Russisch.
Die Darstellung der Registerkarte mit den Einstellungen ist in Abb. 5 unten dargestellt:
Abb. 5. Registerkarte Settings
Im letzten Abschnitt wird das Fenster "EA settings" (Hotkey F7) und die Einstellungen der verwendeten Indikatoren, die unter "Verwendete Indikatoren" aufgeführt sind, angewendet. Abb. 6 zeigt das Fenster des letzten Abschnitts der Einstellungen.
Abb. 6. Einstellungsfenster der verwendeten Indikatoren
Wir sollten die folgenden Nuancen bei der Definition der Einstellungen im Fenster berücksichtigen:
- Die erste ("Applied price") wendet die Variable ENUM_APPLIED_PRICE Aufzählungstyp mit sieben Werten an: Eröffnungs- und Schlusskurs, Höchst- und Tiefstkurs sowie mittlere, typische und gewichtete Durchschnittspreise. Bei der Durchführung einer Analyse auf der Grundlage eines Chartpreises sollten die ersten vier Werte verwendet werden, da die letzten drei Werte für die Berechnung von Indikatoren bestimmt sind.
- Wenn Sie Indikatoren zur Analyse von Mustern verwenden möchten, wirkt sich die Einstellung "Applied price" auf die Indikatoren aus, die die Variable vom Typ ENUM_APPLIED_PRICE in ihren Berechnungen verwenden, und zwar: ATR, CCI und RSI.
Betrachten wir nun die Implementierung der Schnittstelle der App sowie die Methoden zur Suche und Analyse der Merrill-Muster.
Zur Entwicklung der GUI verwenden wir die Methode CreateGUI(), bestehend aus den Methoden CreateWindow(), die das Hauptfenster der Schnittstelle erstellen, und dem Dialogfenster CreateWindowSetting1() zur Auswahl eines Zeitraumes für die Untersuchung.
//+------------------------------------------------------------------+ //| Create the program GUI | //+------------------------------------------------------------------+ bool CProgram::CreateGUI(void) { //--- Create the panel if(!CreateWindow("Merrill Patterns")) return(false); //--- Create the dialog window if(!CreateWindowSetting1("Setting dates")) return(false); //--- Komplettes Erstellen der GUI CWndEvents::CompletedGUI(); return(true); }
Nun lassen Sie uns sehen, woraus jede Methode besteht. Wir werden unsere Aufmerksamkeit zunächst auf das Hauptfenster der Schnittstelle richten. Es besteht aus der Implementierung der Registerkarte Analyse, die aus den in Abb. 4 beschriebenen Elementen besteht.
//+------------------------------------------------------------------+ //| Analyze tab | //+------------------------------------------------------------------+ //--- Create the pattern set buttons if(!CreatePatternSet(m_patterns,10,10)) return(false); //--- Timeframe header if(!CreateTFLabel(m_text_labels[1],10,105,0)) return(false); //--- Create the timeframe set buttons if(!CreateTimeframeSet(m_timeframes,10,125,0)) return(false); //--- Field for searching the symbol filter if(!CreateSymbolsFilter(m_symb_filter1,m_request1,10,180,0)) return(false); //--- Create the button for selecting a date range if(!CreateDateRange(m_request3,280,180,0)) return(false); //--- Create the field for entering the profit threshold value if(!CreateThresholdValue(m_threshold1,400,180,100,0)) return(false); //--- Create the symbol table if(!CreateSymbTable(m_symb_table1,10,225,0)) return(false); //--- Create the result table if(!CreateTable1(m_table1,120,225,0)) return(false);
Und von der Registerkarte Einstellungen, die in Abb. 5 beschrieben ist.
//+------------------------------------------------------------------+ //| Settings tab | //+------------------------------------------------------------------+ //--- if(!CreateButtonsGroup1(10,50)) return(false); //--- Textbezeichner if(!CreateTextLabel(m_text_labels[0],10,100)) return(false); if(!CreateTextLabel(m_text_labels[3],10,10)) return(false); //--- Eingabefelder if(!CreateCoef(m_coef1,10,140,"K1",1)) return(false); if(!CreateCoef(m_coef2,100,140,"K2",0.5)) return(false); if(!CreateCoef(m_coef3,200,140,"K3",0.25)) return(false); if(!CreateLanguageSetting(m_lang_setting,10,180,1)) return(false); //--- Statusleiste if(!CreateStatusBar(1,26)) return(false); //--- return(true); }
Eine detailliertere Implementierung jeder der angewandten Methoden, die Interface-Elemente hinzufügen, finden Sie in den beigefügten Quellcodes.
Das Verfahren, das das Dialogfenster zum Setzen einer temporären Stichprobe implementiert, sieht wie folgt aus:
//+---------------------------------------------------------------------------------+ //| Create the dialog window for selecting the range of dates in the Analysis tab | //+---------------------------------------------------------------------------------+ bool CProgram::CreateWindowSetting1(const string caption_text) { //--- Fensterpointer zum Array des Fensters hinzufügen CWndContainer::AddWindow(m_window[2]); //--- Koordinaten int x=m_request3.X(); int y=m_request3.Y()+m_request3.YSize(); //--- Eigenschaften m_window[2].XSize(372); m_window[2].YSize(230); m_window[2].WindowType(W_DIALOG); //--- Erstellen der Formulars if(!m_window[2].CreateWindow(m_chart_id,m_subwin,caption_text,x,y)) return(false); //--- if(!CreateCalendar(m_calendar1,m_window[2],10,25,D'01.01.2019',1)) return(false); if(!CreateCalendar(m_calendar2,m_window[2],201,25,m_calendar2.Today(),1)) return(false); //--- if(!CreateTimeEdit(m_time_edit1,m_window[2],10,200,"Time",1)) return(false); if(!CreateTimeEdit(m_time_edit2,m_window[2],200,200,"Time",1)) return(false); //--- return(true); }
Lassen Sie uns nun unsere Aufmerksamkeit auf die Methoden der Suche, des Studiums und der Bewertung der Muster richten. Um dies zu erreichen, müssen wir die gesamte Sequenz der Algorithmus-Aktionen verfolgen. Werfen wir zunächst einen Blick in die Datei MerrillPatterns.mq5, wo dieser Algorithmus beginnt.
//--- Include the application class #include "Program.mqh" CProgram program; //+------------------------------------------------------------------+ //| EA Eingabeparameter | //+------------------------------------------------------------------+ input ENUM_APPLIED_PRICE Inp_Price1 = PRICE_CLOSE; // Applied price input int Inp_ATR_Peroid = 5; // ATR Period input int Inp_CCI_Peroid = 5; // CCI Period input int Inp_DeM_Peroid = 5; // DeMarker Period input int Inp_ForcePeriod = 13; // ForceIndex Period input ENUM_MA_METHOD Inp_ForceMAMethod = MODE_SMA; // ForceIndex MA method input ENUM_APPLIED_PRICE Inp_ForceAppliedPrice = PRICE_CLOSE; // ForceIndex Applied price input ENUM_APPLIED_VOLUME Inp_ForceAppliedVolume = VOLUME_TICK; // ForceIndex Volumes input int Inp_WPR_Period = 5; // WPR Period input int Inp_RSI_Period = 5; // RSI Period //+------------------------------------------------------------------+ //| Initialisierungsfunktion des Experten | //+------------------------------------------------------------------+ int OnInit(void) { //--- program.OnInitEvent(); //--- Set the trading panel if(!program.CreateGUI()) { ::Print(__FUNCTION__," > Failed to create GUI!"); return(INIT_FAILED); } //--- program.InitializePrice(Inp_Price1); program.InitializeATR(Inp_ATR_Peroid); program.InitializeCCI(Inp_CCI_Peroid); program.InitializeDeM(Inp_DeM_Peroid); program.InitializeForce(Inp_ForcePeriod,Inp_ForceMAMethod,Inp_ForceAppliedPrice,Inp_ForceAppliedVolume); program.InitializeWPR(Inp_WPR_Period); program.InitializeRSI(Inp_RSI_Period); return(INIT_SUCCEEDED); }
Abgesehen von den Anzeigeneingaben erfolgt die Suche nach einer grafischen Shell im Abschnitt OnInit(), gefolgt von der Initialisierung des Datensatzes im Fenster der Eigenschaften. Alle Methoden übergeben die externen Einstellungen an die internen Variablen.
//--- void InitializePrice(ENUM_APPLIED_PRICE price) { m_applied_price=price; } void InitializeATR(int period) { m_atr_period=period; } void InitializeCCI(int period) { m_cci_period=period; } void InitializeDeM(int period) { m_dem_period=period; } void InitializeWPR(int period) { m_wpr_period=period; } void InitializeRSI(int period) { m_rsi_period=period; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CProgram::InitializeForce(int period,ENUM_MA_METHOD ma_method,ENUM_APPLIED_PRICE price,ENUM_APPLIED_VOLUME volume) { m_force_period=period; m_force_ma_method=ma_method; m_force_applied_price=price; m_force_applied_volume=volume; } //+-----------------------------------------------------------------
Danach ist die Anwendung einsatzbereit, während die restlichen Einstellungen an die erstellte GUI übergeben werden. Ich habe bereits erwähnt, dass der Start der Berechnung durch die Auswahl eines Währungssymbols aus der Symboltabelle (Pos. 6 in Abb. 4) erfolgt. Sie wird auch nach dem Einstellen des "Trend threshold" (Pos. 3 in Abb. 4) durchgeführt. Beide Ereignisse starten die Methode ChangeSymbol1(), um das Sammeln der erfassten Daten zu starten und sie für die Analyse vorzubereiten.
//+------------------------------------------------------------------+ //| Select a symbol in the Analysis tab | //+------------------------------------------------------------------+ bool CProgram::ChangeSymbol1(const long id) { //--- Prüfen der Elemente-ID if(id!=m_symb_table1.Id()) return(false); //--- Exit if the string is not highlighted if(m_symb_table1.SelectedItem()==WRONG_VALUE) { //--- Show full description of a symbol in the status bar m_status_bar.SetValue(0,"Symbol for analysis not selected"); m_status_bar.GetItemPointer(0).Update(true); return(false); } //--- Get a selected symbol string symbol=m_symb_table1.GetValue(0,m_symb_table1.SelectedItem()); //--- Anzeige der gesamten Symbolbeschreibung in der Statusleiste string val=(m_lang_index==0)?"Выбранный символ: ":"Selected symbol: "; m_status_bar.SetValue(0,val+::SymbolInfoString(symbol,SYMBOL_DESCRIPTION)); m_status_bar.GetItemPointer(0).Update(true); //--- GetResult(symbol); return(true); }
Der Kern ihrer Arbeit besteht darin, ein ausgewähltes Handelssymbol aus der Symboltabelle zu definieren und seinen Wert an die Statusleiste und die Methode GetResult() zu übergeben. Betrachten wir die Methode im Detail, da alle Hauptarbeiten in ihr stattfinden.
//+------------------------------------------------------------------+ //| Handle pattern search results | //+------------------------------------------------------------------+ bool CProgram::GetResult(const string symbol) { //--- Structure for evaluating pattern efficiency RATING_SET m_coef[]; //--- Figure types PATTERN_TYPE pattern_types[]; //--- ArrayResize(pattern_types,33); for(int i=0;i<33;i++) { if(i==16) pattern_types[i]=-1; if(i<16) pattern_types[i]=PATTERN_TYPE(i); if(i>16) pattern_types[i]=PATTERN_TYPE(i-1); } //--- Define selected timeframes GetTimeframes(m_timeframes,m_cur_timeframes); int total=ArraySize(m_cur_timeframes); //--- Check for at least one selected timeframe if(total<1) { if(m_lang_index==0) MessageBox("Вы не выбрали рабочий таймфрейм!","Ошибка",MB_OK); else if(m_lang_index==1) MessageBox("You have not selected working timeframe!","Error",MB_OK); return(false); } int count=0; m_total_row=0; //--- Remove all strings m_table1.DeleteAllRows(); //--- Get date range datetime start=StringToTime(TimeToString(m_calendar1.SelectedDate(),TIME_DATE)+" "+(string)m_time_edit1.GetHours()+":"+(string)m_time_edit1.GetMinutes()+":00"); datetime end=StringToTime(TimeToString(m_calendar2.SelectedDate(),TIME_DATE)+" "+(string)m_time_edit2.GetHours()+":"+(string)m_time_edit2.GetMinutes()+":00"); //--- Check selected dates if(start>end || end>TimeCurrent()) { if(m_lang_index==0) MessageBox("Неправильно выбран диапазон дат!","Ошибка",MB_OK); else if(m_lang_index==1) MessageBox("Incorrect date range selected!","Error",MB_OK); return(false); } //--- for(int k=0;k<33;k++) { if(k==16) continue; //--- Get selected patterns for analysis if(m_patterns[k].IsPressed()) { ArrayResize(m_m_total,total); ArrayResize(m_coef,total); ZeroMemory(m_m_total); ZeroMemory(m_coef); count++; //--- Calculate by timeframes for(int j=0;j<total;j++) { double arr[]; //--- Get data for analysis int copied=GetData(m_buttons_group1.SelectedButtonIndex(),symbol,m_cur_timeframes[j],start,end,arr); //--- if(copied<9) MessageBox("Insufficient data for analysis","Error",MB_OK); for(int i=0;i<copied;i++) { if(i>copied-9) continue; //--- Pattern search condition double A=arr[i]; double B=arr[i+1]; double C=arr[i+2]; double D=arr[i+3]; double E=arr[i+4]; if(GetPatternType(A,B,C,D,E)==pattern_types[k]) { m_m_total[j]++; GetCategory(symbol,i+5,m_coef[j],m_cur_timeframes[j],m_threshold_value1); } } //--- Add the result to the table AddRow(m_table1,m_patterns[k].LabelText(),m_coef[j],m_m_total[j],m_cur_timeframes[j]); } } } //--- if(count>0) { //--- m_table1.DeleteRow(m_total_row); //--- Aktualisieren der Tabelle m_table1.Update(true); m_table1.GetScrollVPointer().Update(true); } else { if(m_lang_index==0) MessageBox("Вы не выбрали паттерн!","Ошибка",MB_OK); else if(m_lang_index==1) MessageBox("You have not chosen a pattern!","Error",MB_OK); } return(true); }
Zuerst muss ich die Typen der eingegebenen Variablen gleich zu Beginn der Methode erklären. Die erste ist die Struktur RATING_SET.
struct RATING_SET { int a_uptrend; int b_uptrend; int c_uptrend; int a_dntrend; int b_dntrend; int c_dntrend; };
Sie enthält 6 Variablen vom Typ int und ist notwendig, um Daten darüber hinzuzufügen, wie oft sich der Preis nach der Identifizierung eines Musters in eine bestimmte Richtung bewegt und wie schnell der Preis es erreicht. Angenommen, wir haben einen Aufwärtstrend und die Trendschwelle liegt bei 100 Punkten auf 5 Stellen, während der Preis diesen Wert innerhalb einer einzigen Kerze abdeckt. In diesem Fall erhält die Variable a_uptrend den Wert eins. Wenn der Preis innerhalb von 2 Kerzen 100 Punkte erreicht, wird der Wert an die Variable b_uptrend übergeben. Wir werden das Struktur-Array m_coef[] in unserer Methode verwenden.
Der zweite Variablentyp ist PATTERN_TYPE. Dies ist eine Enumeration, die alle Arten von Merrill-Mustern abdeckt.
//+------------------------------------------------------------------+ //| Figure type | //+------------------------------------------------------------------+ enum PATTERN_TYPE { M1,M2,M3,M4,M5,M6,M7,M8, M9,M10,M11,M12,M13,M14,M15,M16, W1,W2,W3,W4,W5,W6,W7,W8, W9,W10,W11,W12,W13,W14,W15,W16 };
Das Enumeration-Array pattern_types[] wird in der Methode verwendet. Danach folgt die Prüfung — welche Zeiträume wurden für die Arbeit in der Anwendung ausgewählt. Diese Daten werden von der Methode GetTimeframes() verarbeitet.
//+------------------------------------------------------------------+ //| Get the array of selected timeframes | //+------------------------------------------------------------------+ void CProgram::GetTimeframes(CButton &buttons[],ENUM_TIMEFRAMES &timeframe[]) { string tf[22]= { "M1","M2","M3","M4","M5","M6","M10","M12","M15","M20","M30", "H1","H2","H3","H4","H6","H8","H12","D1","W1","MN" }; int j=0; ArrayResize(timeframe,22); for(int i=0;i<22;i++) { if(buttons[i].IsPressed()) { timeframe[j]=StringToTimeframe(tf[i]); j++; } } ArrayResize(timeframe,j); }
Die Methode schreibt dies in das vorläufig gesetzte Zeitrahmen-Array m_cur_timeframes[]. Weiter, holen Sie sich den Zeitraum für die Arbeit.
In der ersten Schleife beginnen wir mit der Überprüfung durch Drücken der ausgewählten Taste, die für die Mustertypen verantwortlich ist, und der Definition einer Reihe von untersuchten Mustern. In der nächsten Schleife wird jedes der Muster auf der Grundlage der zuvor ausgewählten Zeitrahmen untersucht. In diesem Stadium stellt sich die Frage, auf welche Daten die vorläufig eingestellten Muster- und Zeitrahmeneinstellungen angewendet werden sollen. Die Methode GetData() ist dafür verantwortlich, da sie die Einstellungen definiert, die Sie im Eigenschaftsfenster des EAs vorgenommen haben, sowie den verwendeten Indikator (Pos.1 in Abb. 5) in der Registerkarte der Anwendungseinstellungen.
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int CProgram::GetData(int index,string symb,ENUM_TIMEFRAMES tf,datetime start,datetime end,double &arr[]) { //--- int Handle=INVALID_HANDLE,copied; //--- Close price if(index==0) { MqlRates rt[]; ZeroMemory(rt); copied=CopyRates(symb,tf,start,end,rt); ArrayResize(arr,copied); for(int i=0;i<copied;i++) { arr[i]=rt[i].close; if(m_applied_price==PRICE_OPEN) arr[i]=rt[i].open; else if(m_applied_price==PRICE_CLOSE) arr[i]=rt[i].close; else if(m_applied_price==PRICE_HIGH) arr[i]=rt[i].high; else if(m_applied_price==PRICE_LOW) arr[i]=rt[i].low; } return(copied); } //--- ATR if(index==1) Handle=iATR(symb,tf,m_atr_period,m_applied_price); //--- CCI if(index==2) Handle=iCCI(symb,tf,m_cci_period,m_applied_price); //--- DeMarker if(index==3) Handle=iDeMarker(symb,tf,m_dem_period); //--- Force Index if(index==4) Handle=iForce(symb,tf,m_force_period,m_force_ma_method,m_force_applied_volume); //--- WPR if(index==5) Handle=iWPR(symb,tf,m_wpr_period); //--- RSI if(index==6) Handle=iRSI(symb,tf,m_rsi_period,m_applied_price); //--- if(Handle==INVALID_HANDLE) { Print("Failed to get indicator handle"); return(-1); } copied=CopyBuffer(Handle,0,start,end,arr); return(copied); }
Nachdem der Algorithmus Daten zur Analyse empfangen hat, fährt er mit der Methode GetPatternType() fort, mit der er nach allen zuvor eingestellten Mustern in ausgewählten Zeiträumen sucht.
//+------------------------------------------------------------------+ //| Define the patterns | //+------------------------------------------------------------------+ PATTERN_TYPE CProgram::GetPatternType(double A,double B,double C,double D,double E) { //--- M1 if(B>A && A>D && D>C && C>E) return(M1); //--- M2 if(B>A && A>D && D>E && E>C) return(M2); //--- M3 if(B>D && D>A && A>C && C>E) return(M3); //--- M4 if(B>D && D>A && A>E && E>C) return(M4); //--- M5 if(D>B && B>A && A>C && C>E) return(M5); //--- M6 if(D>B && B>A && A>E && E>C) return(M6); //--- M7 if(B>D && D>C && C>A && A>E) return(M7); //--- M8 if(B>D && D>E && E>A && A>C) return(M8); //--- M9 if(D>B && B>C && C>A && A>E) return(M9); //--- M10 if(D>B && B>E && E>A && A>C) return(M10); //--- M11 if(D>E && E>B && B>A && A>C) return(M11); //--- M12 if(B>D && D>C && C>E && E>A) return(M12); //--- M13 if(B>D && D>E && E>C && C>A) return(M13); //--- M14 if(D>B && B>C && C>E && E>A) return(M14); //--- M15 if(D>B && B>E && E>C && C>A) return(M15); //--- M16 if(D>E && E>B && B>C && C>A) return(M16); //--- W1 if(A>C && C>B && B>E && E>D) return(W1); //--- W2 if(A>C && C>E && E>B && B>D) return(W2); //--- W3 if(A>E && E>C && C>B && B>D) return(W3); //--- W4 if(A>C && C>E && E>D && D>B) return(W4); //--- W5 if(A>E && E>C && C>D && D>B) return(W5); //--- W6 if(C>A && A>B && B>E && E>D) return(W6); //--- W7 if(C>A && A>E && E>B && B>D) return(W7); //--- W8 if(E>A && A>C && C>B && B>D) return(W8); //--- W9 if(C>A && A>E && E>D && D>B) return(W9); //--- W10 if(E>A && A>C && C>D && D>B) return(W10); //--- W11 if(C>E && E>A && A>B && B>D) return(W11); //--- W12 if(E>C && C>A && A>B && B>D) return(W12); //--- W13 if(C>E && E>A && A>D && D>B) return(W13); //--- W14 if(E>C && C>A && A>D && D>B) return(W14); //--- W15 if(C>E && E>D && D>A && A>B) return(W15); //--- W16 if(E>C && C>D && D>A && A>B) return(W16); return(-1); }
Beim Erkennen des Musters wird es mit der Methode GetCategory() ausgewertet. Hier wird das zuvor definierte Strukturarray vom Typ RATING_SET verwendet.
//+------------------------------------------------------------------+ //| Define the profit categories | //+------------------------------------------------------------------+ bool CProgram::GetCategory(const string symbol,const int shift,RATING_SET &rate,ENUM_TIMEFRAMES timeframe,int threshold) { MqlRates rt[]; datetime start=StringToTime(TimeToString(m_calendar1.SelectedDate(),TIME_DATE)+" "+(string)m_time_edit1.GetHours()+":"+(string)m_time_edit1.GetMinutes()+":00"); start+=PeriodSeconds(timeframe)*shift; int copied=CopyRates(symbol,timeframe,start,4,rt); //--- Get the data of previous candles if(copied<4) return(false); double high1,high2,high3,low1,low2,low3,close0,point; close0=rt[0].close; high1=rt[1].high; high2=rt[2].high; high3=rt[3].high; low1=rt[1].low; low2=rt[2].low; low3=rt[3].low; if(!SymbolInfoDouble(symbol,SYMBOL_POINT,point)) return(false); //--- Check for Uptrend if((int)((high1-close0)/point)>=threshold) { rate.a_uptrend++; } else if((int)((high2-close0)/point)>=threshold) { rate.b_uptrend++; } else if((int)((high3-close0)/point)>=threshold) { rate.c_uptrend++; } //--- Check for Downtrend if((int)((close0-low1)/point)>=threshold) { rate.a_dntrend++; } else if((int)((close0-low2)/point)>=threshold) { rate.b_dntrend++; } else if((int)((close0-low3)/point)>=threshold) { rate.c_dntrend++; } return(true); }
Die bearbeiteten Auswertungsdaten werden an die Methode AddRow() übergeben, die Wahrscheinlichkeitswerte und Wirkungsgrade berechnet und in die Ergebnistabelle einfügt.
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CProgram::AddRow(CTable &table,string pattern_name,RATING_SET &rate,int found,ENUM_TIMEFRAMES timeframe) { int row=m_total_row; double p1,p2,k1,k2; int sum1=0,sum2=0; sum1=rate.a_uptrend+rate.b_uptrend+rate.c_uptrend; sum2=rate.a_dntrend+rate.b_dntrend+rate.c_dntrend; //--- p1=(found>0)?(double)sum1/found*100:0; p2=(found>0)?(double)sum2/found*100:0; k1=(found>0)?(m_k1*rate.a_uptrend+m_k2*rate.b_uptrend+m_k3*rate.c_uptrend)/found:0; k2=(found>0)?(m_k1*rate.a_dntrend+m_k2*rate.b_dntrend+m_k3*rate.c_dntrend)/found:0; //--- table.AddRow(row); table.SetValue(0,row,pattern_name); table.SetValue(1,row,(string)found); table.SetValue(2,row,TimeframeToString(timeframe)); table.SetValue(3,row,DoubleToString(p1,2),2); table.SetValue(4,row,DoubleToString(p2,2),2); table.SetValue(5,row,DoubleToString(k1,2),2); table.SetValue(6,row,DoubleToString(k2,2),2); ZeroMemory(rate); m_total_row++; }
Um mögliche Fragen im Zusammenhang mit der Verwendung der Anwendung zu vermeiden, zeigt das folgende Video Beispiele für Berechnungen mit unterschiedlichen Einstellungen.
Empfehlungen für die Prüfung von Merrill-Mustern:
- Damit die Anwendung korrekt funktioniert, benötigen wir historische Daten zum Testen an einem bestimmten Handelssymbol zum Herunterladen.
- Es wird nicht empfohlen, alle Muster und alle Zeitrahmen gleichzeitig herunterzuladen, da die Handhabung der Ergebnisse sehr lange dauern kann.
- Die häufigsten Szenarien, die Schwierigkeiten verursachen können, werden von Tipps begleitet. Solche Szenarien beinhalten das Nichtvorgeben eines Zeitrahmens oder eines Musters sowie ein ungültiges Datum.
- Seien Sie vorsichtig beim Einstellen der Eigenschaften des EAs (Abb. 6). Wenn die Einstellungen nicht eindeutig sind, lesen Sie den Artikel erneut.
- Der Artikel hat das Thema einer Methode zur Berechnung der Mustereffizienz zweimal behandelt. Der Link zum Artikel über das Thema wurde bereitgestellt. Beachten Sie, dass Sie ein klares Verständnis dafür benötigen, wie sich die Gewichtungskoeffizienten auf der Registerkarte Einstellungen auf die Musterbewertung auswirken.
Schlussfolgerung
Das unten angehängte Archiv enthält alle beschriebenen Dateien in den jeweiligen Ordnern. Für einen korrekten Betrieb legen Sie den Ordner MQL5 in das Stammverzeichnis des Terminals. Um das Stammverzeichnis des Terminals zu öffnen, in dem sich der Ordner MQL5 befindet, drücken Sie die Tastenkombination Ctrl+Shift+D im MetaTrader 5 Terminal oder verwenden Sie das Kontextmenü wie in Abb. 7 unten gezeigt.
Abb. 7. Öffnen des Ordners MQL5 im Stammordner von MetaTrader 5
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/7022





- 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.