Untersuchung von Techniken zur Analyse der Kerzen (Teil II): Automatische Suche nach den Mustern

6 Mai 2019, 17:11
Alexander Fedosov
0
193

Inhaltsverzeichnis

Einführung

Die bestehenden Methoden der Kerzenanalyse wurden im vorherigen Artikel besprochen. Wir haben festgestellt, dass sie nicht universell sind und nicht für alle Bedingungen geeignet sind. Im Gegenteil, bevor Sie sie verwenden, sollten Sie eine zusätzliche Überprüfung für das jeweilige Finanzinstrument, den Zeitrahmen usw. durchführen. D.h. für die Bedingungen, unter denen die Muster verwendet werden.

Der speziell entwickelte Ansatz ermöglicht auch die individuelle Analyse jedes Musters für ein ausgewähltes Finanzinstrument oder eine Reihe von Instrumenten. Es ermöglicht auch das Auffinden möglicher Korrelationen zwischen vordefinierten Parametern, einschließlich des Zeitrahmens oder der Zeitspanne, sowie speziell eingegebener Metriken, wie Häufigkeit des Auftretens, Wahrscheinlichkeit der Bewegung in eine bestimmte Richtung nach der Musterbildung.

Die Analysemethode verwendete nur 14 Muster, die aus einer Vielzahl von bestehenden Kerzenformationen ausgewählt wurden. Es ist unmöglich, alle Muster einzeln zu analysieren, deshalb wurde eine andere Lösung gefunden. Das Hauptmerkmal aller zuvor untersuchten Muster war ihre Grundlage, d.h. woraus sie bestehen. Vier der analysierten Kerzenmuster bestanden aus einer Kerze und zehn von ihnen aus zwei Kerzen. Die analysierten Kerzenmuster bestanden aus verschiedenen Gruppen oder Sequenzen von sechs Kerzentypen.

Das Hauptproblem bei den Mustern ist, dass sie schon vor langer Zeit entstanden sind, während sich Markteigenschaften, Verhalten und Dynamik ständig ändern. Um dem Trend der Marktanalyse gerecht zu werden, sollten einige Änderungen in der Musteranalyse vorgenommen werden. In diesem Artikel betrachten wir ein System zum Suchen und Testen neuer Kerzenmuster, die auf bekannten Kerzentypen basieren. 


Festlegen der Aufgabe

Um den neuen Algorithmus zur Generierung von Kerzenmuster zu entwickeln, müssen wir die wichtigsten Regeln definieren:

  • Neue Muster werden aus einem, zwei oder drei einfachen Kerzentypen bestehen.
  • Die einfachen Kerzentypen sind: lange Kerze, kurze Kerze, Spinning Top, Doji, Marubozu und der Hammer.
  • Die Kerzentypen werden nach der Richtung unterteilt: auf- und aufwärts. Die Ausnahme ist die Doji-Kerze.
  • Einfache Kerzentypen können sich wiederholen. Beispiel: Ein Muster von zwei langen Abwärtskerzen.

Das allgemeine Schema der Erstellung neuer Muster ist in Abbildung 1 dargestellt.


Abb.1 Neue Algorithmen zur Mustererstellung.

So haben wir eine bestimmte Gruppe von Kerzen, aus denen sich neue Muster bilden. Diese neuen Muster werden 1-3 Kerzen mit oder ohne Wiederholungen enthalten. Diese Gruppe wird insgesamt 11 einfache Kerzen enthalten. Die generierten Kerzenmuster werden nach dem gleichen Prinzip analysiert, das im ersten Artikel beschrieben wurde.


Aktualisierung des Schnittstellenprototyps

Für die Arbeit mit den generierten Mustern steht eine separate Registerkarte zur Verfügung. Die Registerkarte enthält ähnliche Elemente, die in der bestehenden Registerkarte Analyze verfügbar sind. Der einzige Unterschied besteht darin, dass die erste Spalte den Namen Set trägt und die Tabellengröße nicht festgelegt wird.

Abb.2 Registerkarte für die Arbeit mit generierten Mustern.

Die dritte Registerkarte Settings wurde grundlegend überarbeitet. Die richtige Konfiguration der Parameter in dieser Registerkarte ist unerlässlich, deshalb werden wir sie genauer betrachten.

Abb.3 Die aktualisierte Registerkarte Settings.

  1. Es wurde eine Nummerierung der einfachen Kerzentypen mit deren Namen hinzugefügt. So können wir die visuelle Darstellung leicht mit der Liste der 'Used candles' (verwendeten Kerzen) abgleichen.
  2. Eine Option zur Auswahl der Sprache der Benutzeroberfläche wurde hinzugefügt. Russisch oder Englisch.
  3. Die Liste der 'Used candles' (verwendeten Kerzen), die an der Musterbildung beteiligt sind. Die Kontrollkästchen ermöglichen die Auswahl der für den Test erforderlichen Typen.
  4. Eine Gruppe von Umschalttasten. Es kann nur eine Position ausgewählt werden. Auf diese Weise vermeiden wir ein Überladen der Liste der generierten Muster auf der Registerkarte AutoSearch (autom. Suche).
  5. Zwei Umschalttasten. 'Repeat' (mit Wiederholungen) bedeutet, dass es nur einen Kerzentyp im Muster geben kann. Ein Beispiel ist ein Muster, das aus drei Marubozu-Abwärtskerzen besteht. Gleichzeitig kann auch das Spinning Top - Marubozu - Marubozu - Marubozu Muster existieren.

Implementierung der Tools

Wir haben die wichtigsten Ergänzungen festgelegt, die in der bestehenden Anwendung implementiert werden müssen. Lassen Sie uns nun zur Umsetzung selbst übergehen. Zuerst müssen wir eine zusätzliche Registerkarte hinzufügen. Die Indexierung der Registerkarten wird sich ändern. Die Registerkarte AutoSearch hat den Index 1, der früher für die Registerkarte Settings verwendet wurde. 2 wird für Settings verwendet. Dies ist bei der Verknüpfung von abgeleiteten Elementen zu berücksichtigen. Daher müssen wir den Index für alle untergeordneten Elemente der Registerkarte Settings von 1 auf 2 ändern.

//+------------------------------------------------------------------+
//| Erstellen einer Gruppe mit Registerkarten                        |
//+------------------------------------------------------------------+
bool CProgram::CreateTabs(const int x_gap,const int y_gap)
  {
#define TABS1_TOTAL 3
//--- Sichern des Pointers im Hauptsteuerelement
   m_tabs1.MainPointer(m_window1);
//--- Eigenschaften
   m_tabs1.IsCenterText(true);
   m_tabs1.PositionMode(TABS_TOP);
   m_tabs1.AutoXResizeMode(true);
   m_tabs1.AutoYResizeMode(true);
   m_tabs1.AutoXResizeRightOffset(3);
   m_tabs1.AutoYResizeBottomOffset(25);

//--- Hinzufügen von Registerkarten mit den angegebenen Eigenschaften
   string tabs_names[TABS1_TOTAL]={"Analysis","Auto search","Settings"};
   for(int i=0; i<TABS1_TOTAL; i++)
      m_tabs1.AddTab(tabs_names[i],150);
//--- Erstellen eines Steuerelements
   if(!m_tabs1.CreateTabs(x_gap,y_gap))
      return(false);
//--- Hinzufügen eines Objekts zum gemeinsamen Array der Objektgruppen
   CWndContainer::AddToElementsArray(0,m_tabs1);
   return(true);
  }

Die abgeleitete Elemente der Registerkarte AutoSearch ähneln denen von Analyze. Der einzige Unterschied ist der Name der ersten Spalte und das Farbschema. Dies ermöglicht eine visuelle Unterscheidung durch die Oberflächenelemente dieser Registerkarten.

//+------------------------------------------------------------------+
//| Erstellen des Formulars eines Steuerelements                     |
//+------------------------------------------------------------------+
bool CProgram::CreateWindow(const string caption_text)
  {
//--- Hinzufügen eines Zeigers auf das Array des Fensters
   CWndContainer::AddWindow(m_window1);
//--- Eigenschaften
   m_window1.XSize(750);
   m_window1.YSize(500);
   m_window1.FontSize(9);
   m_window1.IsMovable(true);
   m_window1.CloseButtonIsUsed(true);
   m_window1.CollapseButtonIsUsed(true);
   m_window1.FullscreenButtonIsUsed(true);
   m_window1.TooltipsButtonIsUsed(true);
//--- Erstellen des Formulars
   if(!m_window1.CreateWindow(m_chart_id,m_subwin,caption_text,5,5))
      return(false);
//--- Registerkarten
   if(!CreateTabs(3,43))
      return(false);
//--- Registerkarte Analyze
//--- Eingabefelder
   if(!CreateSymbolsFilter(m_symb_filter1,10,10,"Symbols",0))
      return(false);
   if(!CreateRequest(m_request1,250,10,"Search",0))
      return(false);
   if(!CreateRange(m_range1,485,10,"Range",0))
      return(false);
//--- Kombinationsfeld
   if(!CreateComboBoxTF(m_timeframes1,350,10,"Timeframe",0))
      return(false);
//--- Erstellen der Symboltabelle
   if(!CreateSymbTable(m_symb_table1,10,50,0))
      return(false);
//--- Erstellen der Ergebnistabelle
   if(!CreateTable1(m_table1,120,50,0))
      return(false);

//--- Registerkarte AutoSearch
//--- Eingabefelder
   if(!CreateSymbolsFilter(m_symb_filter2,10,10,"Symbols",1))
      return(false);
   if(!CreateRequest(m_request2,250,10,"Search",1))
      return(false);
   if(!CreateRange(m_range2,485,10,"Range",1))
      return(false);
//--- Kombinationsfeld
   if(!CreateComboBoxTF(m_timeframes2,350,10,"Timeframe",1))
      return(false);
//--- Erstellen der Symboltabelle
   if(!CreateSymbTable(m_symb_table2,10,50,1))
      return(false);
//--- Erstellen der Ergebnistabelle
   if(!CreateTable2(m_table2,120,50,1))
      return(false);

Wie aus dem obigen Code ersichtlich ist, betrifft der Unterschied nur zwei Methoden CreateTable1() und CreateTable2(). Nun kommen wir zur Registerkarte Settings. Hier betrifft die allererste Änderung die grafischen Ressourcen. Auch das Element der Parametereinstellungen der Kerzen wurde dem Erstellungselement hinzugefügt. Dies geschieht mit der Methode CreateNameCandle().

//+------------------------------------------------------------------+
//| Erstellen eines Elements der Kerzeneinstellung                   |
//+------------------------------------------------------------------+
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp16\\settings_dark.bmp"
#resource "\\Images\\EasyAndFastGUI\\Candles\\long.bmp"
#resource "\\Images\\EasyAndFastGUI\\Candles\\short.bmp"
#resource "\\Images\\EasyAndFastGUI\\Candles\\doji.bmp"
#resource "\\Images\\EasyAndFastGUI\\Candles\\spin.bmp"
#resource "\\Images\\EasyAndFastGUI\\Candles\\maribozu.bmp"
#resource "\\Images\\EasyAndFastGUI\\Candles\\hammer.bmp"
//---
bool CProgram::CreateCandle(CPicture &pic,CButton &button,CTextLabel &candlelabel,const string candlename,const int x_gap,const int y_gap,string path)
  {
//--- Sichern des Pointers im Hauptsteuerelement
   pic.MainPointer(m_tabs1);
//--- Hinzufügen zur Registerkarte
   m_tabs1.AddToElementsArray(2,pic);
//--- Eigenschaften
   pic.XSize(64);
   pic.YSize(64);
   pic.IconFile(path);
//--- Erstellen der Taste
   if(!pic.CreatePicture(x_gap,y_gap))
      return(false);
//--- Hinzufügen eines Zeigers auf das Element der Basis
   CWndContainer::AddToElementsArray(0,pic);
   CreateButtonPic(pic,button,"Images\\EasyAndFastGUI\\Icons\\bmp16\\settings_dark.bmp");
   CreateNameCandle(candlelabel,x_gap,y_gap+pic.YSize(),candlename);
   return(true);
  }

Es geht um die Änderungen an bereits erstellten Steuerelementen. Kommen wir nun zu den Neuen. Eines davon ist die Option zur Auswahl der Oberflächensprache. Die Anwendung unterstützt aktuell zwei Sprachen: Russisch und Englisch. Die Sprachauswahl ist in Abbildung 4 dargestellt.

Abb.4 Auswahl der Sprache der Benutzeroberfläche.

Der Sprachwechsel erfolgt über die Methode ChangeLanguage(). Gemäß der Logik werden die Textkomponenten ersetzt. Der Methodencode ist sehr einfach. Hier ist seine Anwendung in der Ereignisbehandlung:

//--- Auswahl des Elements in einem Kombinationsfeld
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_COMBOBOX_ITEM)
     {
      //--- Ändern des Zeitrahmens
      if(ChangePeriod1(lparam))
         Update(true);
      //--- Ändern der Schnittstellensprache
      if(ChangeLanguage(lparam))
         Update(true);
     }

Wie aus dem Code ersichtlich ist, bestimmt die Methode zu Sprachänderung bei der Auswahl eines Elements in einem Kombinationsfeld, welches der Elemente im Dropdown-Menü ausgewählt ist, und stellt den entsprechenden Sprachindex ein:

//+------------------------------------------------------------------+
//| Ändern der Schnittstellensprache                                 |
//+------------------------------------------------------------------+
bool CProgram::ChangeLanguage(const long id)
  {
//--- Prüfen der Elemente-ID
   if(id!=m_lang_setting.Id())
      return(false);
   m_lang_index=m_lang_setting.GetListViewPointer().SelectedItemIndex();
//---
   if(m_lang_index==0)
     ....

Der nächste Abschnitt ist für die Auswahl einfacher Kerzentypen zuständig, aus denen die Muster für den Test generiert werden. Es gibt 11 Typen. Das Steuerelement ist als Liste von Namen der verwendeten Kerzentypen und Kontrollkästchen implementiert, die die Auswahl widerspiegeln. Für die Implementierung wurde die Methode CreateListView() verwendet:

//+------------------------------------------------------------------+
//| Erstellen der Liste                                              |
//+------------------------------------------------------------------+
bool CProgram::CreateListView(const int x_gap,const int y_gap)
  {
//--- Größe der Listenansicht
#define CANDLE_TOTAL 11
//--- Sichern des Pointers im Hauptsteuerelement
   m_listview1.MainPointer(m_tabs1);
//--- Hinzufügen zur Registerkarte
   m_tabs1.AddToElementsArray(2,m_listview1);
//--- Eigenschaften
   m_listview1.XSize(175);
   m_listview1.YSize(250);
   m_listview1.ItemYSize(19);
   m_listview1.LabelXGap(25);
   m_listview1.LightsHover(true);
   m_listview1.CheckBoxMode(true);
   m_listview1.ListSize(CANDLE_TOTAL);
   m_listview1.AutoYResizeMode(true);
   m_listview1.AutoYResizeBottomOffset(10);
   m_listview1.FontSize(10);
//--- Befüllen der Listenansicht mit den Daten
   string cand_name[CANDLE_TOTAL]=
     {
      "Long — bullish",
      "Long — bearish",
      "Short — bullish",
      "Short — bearish",
      "Spinning Top — bullish",
      "Spinning Top — bearish",
      "Doji",
      "Marubozu — bullish",
      "Marubozu — bearish",
      "Hammer — bullish",
      "Hammer — bearish"
     };
   for(int r=0; r<CANDLE_TOTAL; r++)
     {
      m_listview1.SetValue(r,(string)(r+1)+". "+cand_name[r]);
     }
//--- Erstellen der Listenansicht
   if(!m_listview1.CreateListView(x_gap,y_gap))
      return(false);
//--- Hinzufügen eines Zeigers auf das Element der Basis
   CWndContainer::AddToElementsArray(0,m_listview1);
   return(true);
  }

Die nächsten beiden Steuerelemente stehen in direktem Zusammenhang mit der Liste der einfachen Kerzentypen. Das erste ist ein Schalter, der Wiederholungen aktiviert oder deaktiviert. Wie bereits im Abschnitt zur Aufgabendefinition erwähnt, bezieht sich die Wiederholung auf das Muster, das aus nur einem Kerzentyp besteht, unabhängig von seiner Größe. 

Abb.5 Auswahl des analysierten Kerzentyps und des Wiederholungsmodus.

Die Methode, die für die Erstellung des Repeat-Schalters verantwortlich ist, heißt CreateDualButton():

//+------------------------------------------------------------------+
//| Erstellen des Umschalters Repeat                                 |
//+------------------------------------------------------------------+
bool CProgram::CreateDualButton(CButton &lbutton,CButton &rbutton,const int x_gap,const int y_gap,const string ltext,const string rtext)
  {
   CreateButton(lbutton,x_gap,y_gap,ltext);
   CreateButton(rbutton,x_gap+99,y_gap,rtext);
   return(true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CProgram::CreateButton(CButton &button,const int x_gap,const int y_gap,const string text)
  {
//--- Sichern des Zeigers auf das Hauptsteuerelement
   button.MainPointer(m_tabs1);
//--- Hinzufügen zur Registerkarte
   m_tabs1.AddToElementsArray(2,button);
//--- Eigenschaften
   button.XSize(100);
   button.YSize(30);
   button.Font("Trebuchet");
   button.FontSize(10);
   button.IsCenterText(true);
   button.BorderColor(C'0,100,255');
   button.BackColor(clrAliceBlue);
   button.BackColorLocked(C'50,180,75');
   button.BorderColorLocked(C'50,180,75');
   button.LabelColorLocked(clrWhite);
//--- Erstellen eines Steuerelements
   if(!button.CreateButton(text,x_gap,y_gap))
      return(false);
//--- Hinzufügen eines Zeigers auf das Element der Basis
   CWndContainer::AddToElementsArray(0,button);
   return(true);
  }

Die Einstellung des Steuerelements wird über das Ereignis eines Klicks mit der linken Maustaste verfolgt:

   if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
     {
      ....
      //--- Falls eine Taste gedrückt wurde
      if(lparam==m_button7.Id())
        {
         m_button7.IsLocked(true);
         m_button8.IsLocked(false);
        }
      else if(lparam==m_button8.Id())
        {
         m_button7.IsLocked(false);
         m_button8.IsLocked(true);
        }

Nachdem wir den visuellen Teil der Anwendung analysiert haben, kommen wir nun zum Berechnungsteil. Zunächst müssen wir die minimalen Einstellungen, die Reihenfolge der Aktionen und die Verarbeitungsmethoden für diese Aktionen festlegen:

Schritt 1. Einstellen der Eingabedaten.

Bevor wir mit der Anwendung beginnen, müssen wir einfache Kerzentypen auswählen, aus denen Muster für die Analyse generiert werden. Wählen Sie dann, ob der Wiederholungsmodus aktiviert ist. Der Wiederholungsmodus impliziert die Verwendung von nur einem Kerzentyp bei der Erstellung eines Musters beliebiger Größe. Wählen wir dann die Anzahl der Kerzen in einem Muster aus. Dies kann Muster von einem, zwei oder drei Kerzen beinhalten. Beachten Sie, dass für die Erzeugung von zwei oder drei Kerzenmustern mindestens zwei einfache Kerzen ausgewählt werden müssen. Wenn Sie versuchen, Muster mit weniger Kerzen zu erzeugen, gibt die Anwendung einen Fehler zurück, wie in Abbildung 6 dargestellt.

Abb.6 Fehler: Es wird nur ein Kerzentyp für die Zwei-Kerzen-Muster ausgewählt.

Schritt 2. Arbeiten mit der Registerkarte AutoSearch.

Nachdem Sie die richtigen Eingabeparameter eingegeben haben, wechseln Sie zu AutoSearch und wählen Sie ein Symbol zum Testen aus. Lassen Sie uns die Möglichkeiten der in dieser Registerkarte vorgestellten Instrumente im Detail betrachten.

  • Auswählen und Suchen der zu analysierenden Währungssymbole. Im Eingabefeld können Sie einen Teil eines Symbols oder bestimmte gewünschte Symbole durch Kommas getrennt eingeben und auf die Schaltfläche Suchen klicken. Sie können auch den vordefinierten Ausdruck Major verwenden, der die wichtigsten Währungspaare anzeigt. Um alle im Fenster Marktübersicht verfügbaren Symbole anzuzeigen, deaktivieren Sie das Kontrollkästchen in der oberen linken Ecke. Dadurch wird die Filterung im Suchfenster deaktiviert.
  • Wählen Sie dann den gewünschten Zeitrahmen aus der Dropdown-Liste und der Zeitspanne in Form der Kerzenanzahl des ausgewählten Zeitrahmens.
  • Nach Auswahl des gewünschten Symbols oder der Liste klicken Sie auf das aktuelle Symbol, um die Analyse zu starten. Danach erzeugt die Anwendung die in Schritt 1 konfigurierten Muster, führt entsprechende Berechnungen durch und zeigt die Daten in einer Tabelle an. Nachdem Sie Daten in einer Tabelle empfangen haben, können Sie den Zeitrahmen ändern und die Daten werden in Echtzeit neu berechnet.

Lassen Sie uns die resultierende Datentabelle im Detail betrachten. Dies wird dazu beitragen, das Berechnungs- und Funktionsprinzip der Algorithmen zu verstehen, die wir im Folgenden untersuchen werden.


Abb.7 Beispiel für die Datenberechnung für das Paar EURUSD.  

Wie aus Abbildung 7 ersichtlich, ist in der Symboltabelle eine Zeile mit dem analysierten Währungspaar ausgewählt. Der Zeitrahmen M15 und der Zeitspanne von 8000 15-Minuten Kerzen werden oben im rechten Teil angezeigt. Die Ergebnistabelle enthält sechs Spalten. Hier werden wir nur die erste Spalte betrachten, während die restlichen im ersten Artikel beschrieben wurden, im Abschnitt Entwicklung einer Prototyp-Schnittstelle.

Die erste Spalte ist Set. In den unteren Zeilen werden die Werte im Format[1,1,2] angezeigt. Drei Zahlen in eckigen Klammern bedeuten, dass ein Muster von drei Kerzenleuchtern verwendet wird. Das Muster besteht aus einfachen Kerzenleuchtern 1 und 2 in genau der in eckigen Klammern angegebenen Reihenfolge. Die Anzahl der verwendeten Kerzen finden Sie in der Registerkarte Settings im Abschnitt Used candles.

Abb.8 Die Liste und Anzahl der Kerzen, die bei der Mustererzeugung verwendet werden.  

Jetzt wissen wir, wie man die Anwendung konfiguriert und startet, so dass wir mit der Berücksichtigung der internen Betriebslogik fortfahren können. Nach dem Einstellen der Eingabedaten klicken wir auf das Währungsinstrument in der Symboltabelle. Die Handhabung des Klicks auf das Tabellenelement ruft die Methode ChangeSymbol2() auf:

//--- Ereignis des Drucks auf das Element einer Liste oder Tabelle
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_LIST_ITEM)
     {
      //--- Ändern des Symbols
      if(ChangeSymbol1(lparam))
         Update(true);
      if(ChangeSymbol2(lparam))
         m_table2.Update(true);
     }

Bei dieser Methode gibt es neben dem Setzen der Informationswerte in der Statusleiste noch zwei weitere Methoden.

//+------------------------------------------------------------------+
//| Ändern des Symbols                                               |
//+------------------------------------------------------------------+
bool CProgram::ChangeSymbol2(const long id)
  {
//--- Prüfen der Elemente-ID
   if(id!=m_symb_table2.Id())
      return(false);
//--- Verlassen, wenn die Zeile nicht hervorgehoben ist
   if(m_symb_table2.SelectedItem()==WRONG_VALUE)
     {
      //--- Anzeige der gesamten Symbolbeschreibung in der Statusleiste
      m_status_bar.SetValue(0,"No symbol selected for analysis");
      m_status_bar.GetItemPointer(0).Update(true);
      return(false);
     }
//--- Abrufen des Symbols
   string symbol=m_symb_table2.GetValue(0,m_symb_table2.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);
   if(!BuildingAutoSearchTable())
      return(false);
   GetPatternType(symbol,m_total_combination);
   return(true);
  }

Die erste Methode ist BuildingAutoSearchTable(). Sie erstellt Muster aus der Liste der einfachen Kerzen, die auf der Registerkarte Settings im Abschnitt Used candles ausgewählt wurden (Abb.8) und zeigt sie in der ersten Spalte der Ergebnistabelle an.

//+------------------------------------------------------------------+
//| Neuerstellen der Tabelle der automatischen Mustersuche           |
//+------------------------------------------------------------------+
bool CProgram::BuildingAutoSearchTable(void)
  {
//---
   if(!GetCandleCombitaion())
     {
      if(m_lang_index==0)
         MessageBox("Число выбранных свечей меньше размера исследуемого паттерна!","Ошибка");
      else if(m_lang_index==1)
         MessageBox("The number of selected candles is less than the size of the studied pattern!","Error");
      return(false);
     }
//--- Löschen aller Zeilen
   m_table2.DeleteAllRows();
//--- Festlegen der Zeilenzahl durch die Anzahle der Symbole
   for(int i=0; i<ArraySize(m_total_combination); i++)
     {
      m_table2.AddRow(i);
      m_table2.SetValue(0,i,m_total_combination[i]);
     }
   m_table2.DeleteRow(ArraySize(m_total_combination));
//--- Aktualisieren der Tabelle
   m_table2.Update(true);
   m_table2.GetScrollVPointer().Update(true);
   m_table2.GetScrollHPointer().Update(true);
   return(true);
  }
//+------------------------------------------------------------------+
//| Mustererstellung mit einfachen Kerzen                            |
//+------------------------------------------------------------------+
bool CProgram::GetCandleCombitaion(void)
  {
   string candlenumber[];
   int selected_candles=0,n;
   ArrayResize(candlenumber,m_total_candles);
//---
   for(int i=0;i<m_total_candles;i++)
     {
      if(m_listview1.GetState(i))
        {
         candlenumber[selected_candles]=(string)(i+1);
         selected_candles++;
        }
     }

   if((m_pattern_size==2 && selected_candles<2) || (m_pattern_size==3 && selected_candles<2) || selected_candles<1)
      return(false);
//--- Berechnen der Kombinationsanzahl
   if(m_pattern_size>1)
      n=(m_button7.IsLocked())?(int)MathPow(selected_candles,m_pattern_size):(int)MathPow(selected_candles,m_pattern_size)-selected_candles;
   else
      n=selected_candles;
   ArrayResize(m_total_combination,n);

   n=0;
//--- A Gruppe von einzelnen Kerzen
   if(m_pattern_size==1)
     {
      for(int i=0;i<selected_candles;i++)
         m_total_combination[i]="["+candlenumber[i]+"]";
     }
//--- A Gruppe von zwei Kerzen
   else if(m_pattern_size==2)
     {
      //--- Modus Repeat aktiviert
      if(m_button7.IsLocked())
        {
         for(int i=0;i<selected_candles;i++)
           {
            for(int j=0;j<selected_candles;j++)
              {
               m_total_combination[n]="["+candlenumber[i]+","+candlenumber[j]+"]";
               n++;
              }
           }
        }
      //--- Modus Repeat deaktiviert
      else if(m_button8.IsLocked())
        {
         for(int i=0;i<selected_candles;i++)
           {
            for(int j=0;j<selected_candles;j++)
              {
               if(j!=i)
                 {
                  m_total_combination[n]="["+candlenumber[i]+","+candlenumber[j]+"]";
                  n++;
                 }
              }
           }
        }
     }
//--- A Gruppe von drei Kerzen
   else if(m_pattern_size==3)
     {
      //--- Modus Repeat aktiviert
      if(m_button7.IsLocked())
        {
         for(int i=0;i<selected_candles;i++)
           {
            for(int j=0;j<selected_candles;j++)
              {
               for(int k=0;k<selected_candles;k++)
                 {
                  m_total_combination[n]="["+candlenumber[i]+","+candlenumber[j]+","+candlenumber[k]+"]";
                  n++;
                 }
              }
           }
        }
      //--- Modus Repeat deaktiviert
      else if(m_button8.IsLocked())
        {
         for(int i=0;i<selected_candles;i++)
           {
            for(int j=0;j<selected_candles;j++)
               for(int k=0;k<selected_candles;k++)
                 {
                  if(i==j && i==k)
                     continue;
                  m_total_combination[n]="["+candlenumber[i]+","+candlenumber[j]+","+candlenumber[k]+"]";
                  n++;
                 }
           }
        }
     }
   return(true);
  }

Das Erstellen von Mustern basierend auf einem Kerzengruppe erfolgt mit der Methode GetCandleCombination(). Zweck des Verfahrens ist es, alle möglichen Kombinationen von einfachen Kerzen basierend auf den Sequenznummern der ausgewählten Kerzen, mit oder ohne Wiederholungen und unter Berücksichtigung der in der Anzahl der Kerzen im Suchbereich der Muster gewählten Größe anzuzeigen. 

Alle Kombinationen werden in das Zeichenketten-Array m_total_combitaion[] geschrieben, und die Daten werden in der Methode BuildingAutoSearchTable() in die Ergebnistabelle eingefügt.

Die zweite Methode, die nach BuildingAutoSearchTable() aufgerufen wird, ist für die Berechnung und Anzeige anderer Datenbanken auf der resultierenden Liste der erzeugten Muster verantwortlich. Betrachten wir die Methode GetPatternType() genauer - sie wurde im ersten Artikel zur Berechnung vordefinierter Muster verwendet, wurde aber vereinfacht. Ziel dieser Aufgabe ist es, voreingestellte Muster in einem Chart zu erkennen und zu analysieren. Da mit dieser Methode sowohl nach bereits vorhandenen als auch nach generierten Mustern gesucht wird, wurde mit der überladenen Methode implementiert:

   //--- Muster erkennen
   bool              GetPatternType(const string symbol);
   bool              GetPatternType(const string symbol,string &total_combination[]);

In der zweiten Variante verwenden wir das vorher erstellten Zeichenketten-Array mit den generierten Mustern. Der Zweck der Methode ist es, eines unserer generierten Muster auf dem Diagramm zu identifizieren, es zu bewerten und seine Effizienz zu berechnen. Die Beschreibung der Idee und der Algorithmen finden Sie im Abschnitt Definition des Problems des ersten Artikels. Deshalb werden wir uns jetzt nicht damit beschäftigen.

Die gefundene Mustereffizienz wurde früher mit einem Array bewertet, zu dem wir die Kategorieschätzungen A, B und C für den Aufwärtstrend und den Abwärtstrend hinzugefügt haben. In diesem Artikel konvertieren wir das Array in eine Struktur. Dies ermöglichte eine Verkürzung des resultierenden Codes. Die Struktur ist wie folgt:

struct RATING_SET
  {
   int               a_uptrend;
   int               b_uptrend;
   int               c_uptrend;
   int               a_dntrend;
   int               b_dntrend;
   int               c_dntrend;
  };

 Für unsere Aufgabe benötigen wir diesen Satz von Schätzungen für jedes der erzeugten Muster. Daher wird das Array RATING_SET der Strukturen am Anfang der Methode deklariert. Die Array-Größe entspricht der Anzahl der erzeugten Muster oder der Größe des Zeichenketten-Arrays m_total_combitaion[].

   RATING_SET ratings[];

//---
   total_patterns=ArraySize(total_combination);
...
   ArrayResize(ratings,total_patterns);

Dieses Array speichert alle generierten Muster, die jedoch als Zeichenkette dargestellt werden, die in der ersten Spalte des Tabellenergebnisses angezeigt wird. Der nächste Schritt besteht also darin, aus jedem Zeichenkettenindex die verwendeten einfachen Kerzenmuster zu extrahieren und sie in den Kerzentyp aus der CANDLE_STRUCTURE zu konvertieren.

struct CANDLE_STRUCTURE
  {
   double            open,high,low,close;       // OHLC
   TYPE_TREND        trend;                     //Trend
   bool              bull;                      // Aufwärtskerze
   double            bodysize;                  // Abwärtskerze
   TYPE_CANDLESTICK  type;                      // Kerzentyp
  };

Zu diesem Zweck werden wir einige Konvertierungen durchführen. Zusätzlich werden wir eine zusätzliche Methode in Betracht ziehen, die hilft, den Kerzenindex in seinen Typ zu konvertieren.

//---
   for(int i=0;i<total_patterns;i++)
     {
      StringReplace(total_combination[i],"[","");
      StringReplace(total_combination[i],"]","");
      if(m_pattern_size>1)
        {
         ushort sep=StringGetCharacter(",",0);
         StringSplit(total_combination[i],sep,elements);
        }
      ZeroMemory(ratings[i]);
      m_pattern_total[i]=0;
      if(m_pattern_size==1)
         IndexToPatternType(cand1[i],(int)total_combination[i]);
      else if(m_pattern_size==2)
        {
         IndexToPatternType(cand1[i],(int)elements[0]);
         IndexToPatternType(cand2[i],(int)elements[1]);
        }
      else if(m_pattern_size==3)
        {
         IndexToPatternType(cand1[i],(int)elements[0]);
         IndexToPatternType(cand2[i],(int)elements[1]);
         IndexToPatternType(cand3[i],(int)elements[2]);
        }
     }

In einer Schleife gehen wir durch alle Zeichenketten der erzeugten Muster, entfernen die eckigen Klammern, verwenden StringSplit() basierend auf das Trennzeichen "," und fügen Informationen zu dem Array elements[] hinzu. Beachten Sie, dass dieses Verfahren auf Muster anzuwenden ist, die aus mehr als einer Kerze bestehen, da es für eine Kerze keine Kommas gibt und wir nur die eckigen Klammern entfernen müssten. Betrachten wir nun die Methode IndexToPatternType(), in die wir CANDLE_STRUCTURE eingeben, um Daten aus dem Array der erzeugten Muster auszufüllen und zu verarbeiten.

void CProgram::IndexToPatternType(CANDLE_STRUCTURE &res,const int index)
  {
//--- Long - bullish
   if(index==1)
     {
      res.bull=true;
      res.type=CAND_LONG;
     }
//--- Long - bearish
   else if(index==2)
     {
      res.bull=false;
      res.type=CAND_LONG;
     }
//--- Short - bullish
   else if(index==3)
     {
      res.bull=true;
      res.type=CAND_SHORT;
     }
//--- Short - bearish
   else if(index==4)
     {
      res.bull=false;
      res.type=CAND_SHORT;
     }
//--- Spinning Top - bullish
   else if(index==5)
     {
      res.bull=true;
      res.type=CAND_SPIN_TOP;
     }
//--- Spinning Top - bearish
   else if(index==6)
     {
      res.bull=false;
      res.type=CAND_SPIN_TOP;
     }
//--- Doji
   else if(index==7)
     {
      res.bull=true;
      res.type=CAND_DOJI;
     }
//--- Marubozu - bullish
   else if(index==8)
     {
      res.bull=true;
      res.type=CAND_MARIBOZU;
     }
//--- Marubozu - bearish
   else if(index==9)
     {
      res.bull=false;
      res.type=CAND_MARIBOZU;
     }
//--- Hammer - bullish
   else if(index==10)
     {
      res.bull=true;
      res.type=CAND_HAMMER;
     }
//--- Hammer - bearish
   else if(index==11)
     {
      res.bull=false;
      res.type=CAND_HAMMER;
     }
  }

Je nach Mustergröße werden ein, zwei oder drei CANDLE_STRUCTURE gefüllt: cand1, cand2, cand3. Siehe den untenstehenden Code:

if(m_pattern_size==1)
         IndexToPatternType(cand1[i],(int)total_combination[i]);
      else if(m_pattern_size==2)
        {
         IndexToPatternType(cand1[i],(int)elements[0]);
         IndexToPatternType(cand2[i],(int)elements[1]);
        }
      else if(m_pattern_size==3)
        {
         IndexToPatternType(cand1[i],(int)elements[0]);
         IndexToPatternType(cand2[i],(int)elements[1]);
         IndexToPatternType(cand3[i],(int)elements[2]);
        }

Dies ermöglicht die sofortige Analyse der benötigten Anzahl von Kerzen, unabhängig von der Mustergröße, die auf dem Diagramm gefunden wurde. 

Für Muster mit nur einer Kerze wird jeweils nur eine Kerze für die Analyse und Berechnung verwendet, während die gesamte Gruppe für 2- und 3-Kerzenmuster verwendet wird. Bei einem Abtastbereich von 2000 Kerzen besteht die Gruppe beispielsweise bei 1-Kerzenmustern aus einem 2000er Kerzen. Mit zwei Kerzen besteht eine Gruppe aus 2000er und 1999er und so weiter. 

Als Nächstes betrachten wir das folgende Fragment der Methode GetPatternType(), die für das Auffinden jedes der erzeugten Muster auf dem Chart verantwortlich ist.

//---
   for(int i=m_range_total2;i>5;i--)
     {
      if(m_pattern_size==1)
        {
         //--- Abrufen des abrufen Kerzentyps
         GetCandleType(symbol,cur_cand,m_timeframe2,i);                                         // Aktuelle Kerze
         //---
         for(int j=0;j<total_patterns;j++)
           {
            if(cur_cand.type==cand1[j].type && cur_cand.bull==cand1[j].bull)
              {
               m_pattern_total[j]++;
               GetCategory(symbol,i-3,ratings[j],m_timeframe2);
              }
           }
        }
      else if(m_pattern_size==2)
        {
         //--- Abrufen des abrufen Kerzentyps
         GetCandleType(symbol,prev_cand,m_timeframe2,i);                                        // Vorherige Kerze
         GetCandleType(symbol,cur_cand,m_timeframe2,i-1);                                       // Aktuelle Kerze
         //---
         for(int j=0;j<total_patterns;j++)
           {
            if(cur_cand.type==cand1[j].type && cur_cand.bull==cand1[j].bull && 
               prev_cand.type==cand2[j].type && prev_cand.bull==cand2[j].bull)
              {
               m_pattern_total[j]++;
               GetCategory(symbol,i-4,ratings[j],m_timeframe2);
              }
           }
        }
      else if(m_pattern_size==3)
        {
         //--- Abrufen des abrufen Kerzentyps
         GetCandleType(symbol,prev_cand2,m_timeframe2,i);                                       // Vorherige Kerze
         GetCandleType(symbol,prev_cand,m_timeframe2,i-1);                                      // Vorherige Kerze
         GetCandleType(symbol,cur_cand,m_timeframe2,i-2);                                       // Aktuelle Kerze
         //---
         for(int j=0;j<total_patterns;j++)
           {
            if(cur_cand.type==cand1[j].type && cur_cand.bull==cand1[j].bull && 
               prev_cand.type==cand2[j].type && prev_cand.bull==cand2[j].bull && 
               prev_cand2.type==cand3[j].type && prev_cand2.bull==cand3[j].bull)
              {
               m_pattern_total[j]++;
               GetCategory(symbol,i-5,ratings[j],m_timeframe2);
              }
           }
        }
     }

Wie wir im obigen Code sehen können, ist die Schleife ganz am Anfang und stoppt bei der sechsten Kerze. Warum? Im ersten Artikel erwähnten wir, dass wir, um die Mustereffizienz zu analysieren, bestimmen müssen, wohin der Preis nach der Musterbildung geht und herausfinden müssen, was das Muster voraussagt, was die Vorhersagehäufigkeit und wie die Wahrscheinlichkeit ist. Für diese Bewertung haben wir die Analyse der Preisbewegung innerhalb von drei Kerzenleuchtern nach dem Muster implementiert. Die aktuelle Null-Kerze nimmt nicht an der Analyse teil, da sie noch nicht vollständig ist. 

Abb.9 Berechnung der Mustereffizienzbewertung. 

Ein Muster aus drei Kerzen ist in Abbildung 9 dargestellt. Um seine Effizienz zu bewerten, brauchen wir drei weitere Kerzen außer der Nullkerze. Um diese Bedingungen für das aktuelle Muster zu erfüllen, kann die erste Kerze innerhalb des Musters daher einen Index von mindestens 6 haben. 

Nach der Suche nach Mustern, der Zählung ihrer Anzahl und der Auswertung nach Kategorien A, B, C müssen wir die empfangenen Daten verarbeiten und die Ergebnisse in eine Tabelle aufnehmen. Diese Berechnungen werden in der Methode CoefCalculation() durchgeführt.

//---
   for(int i=0;i<total_patterns;i++)
      CoefCalculation(m_table2,i,ratings[i],m_pattern_total[i]);

 Die Methodenargumente sind:

  • m_table2 — ein Link zu der Tabelle, zu der die Berechnungsergebnisse der einzelnen generierten Muster hinzugefügt werden.
  • i — Tabellenzeile.
  • ratings[i] — ein Array der Struktur RATING_SET, das einen Satz von kategoriebasierten Bewertungen für jedes Muster enthält.
  • m_pattern_total[i] — ein Array, das die Anzahl der gefundenen Muster jedes Typs enthält.

Lassen Sie uns die Methode genauer betrachten.

//+------------------------------------------------------------------+
//| Berechnung der Effizienz der Bewertungskoeffizienten             |
//+------------------------------------------------------------------+
bool CProgram::CoefCalculation(CTable &table,const int row,RATING_SET &rate,int found)
  {
   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)?NormalizeDouble((double)sum1/found*100,2):0;
   p2=(found>0)?NormalizeDouble((double)sum2/found*100,2):0;
   k1=(found>0)?NormalizeDouble((m_k1*rate.a_uptrend+m_k2*rate.b_uptrend+m_k3*rate.c_uptrend)/found,3):0;
   k2=(found>0)?NormalizeDouble((m_k1*rate.a_dntrend+m_k2*rate.b_dntrend+m_k3*rate.c_dntrend)/found,3):0;

   table.SetValue(1,row,(string)found);
   table.SetValue(2,row,(string)((double)found/m_range_total2*100),2);
   table.SetValue(3,row,(string)p1,2);
   table.SetValue(4,row,(string)p2,2);
   table.SetValue(5,row,(string)k1,2);
   table.SetValue(6,row,(string)k2,2);
//--- Aktualisieren der Tabelle
   table.Update(true);
   table.GetScrollVPointer().Update(true);
   table.GetScrollHPointer().Update(true);
   return(true);
  }

Wie aus der Methodenimplementierung ersichtlich ist, können wir durch die Verwendung der Struktur deutlich sehen, wie die Musteranalysekoeffizienten berechnet werden.

Demonstration der Verwendung

Als Beispiel werden wir einige der erzeugten Muster mit verschiedenen Parametern testen.

Schritt 1. Auswahl einfacher Kerzenmodelle.

Zuerst müssen wir alle möglichen einfachen Kerzenmodelle im Abschnitt "Used candles" auswählen, "Repeat" aktivieren und "The number of candles in the pattern" auf eins einstellen. Der Schwellenwert für den Trendwert in Punkten wird auf 200 gesetzt. Hier ist das Setup:

Abb.10 Der erste Setup-Schritt zur Analyse der generierten Muster.

Navigieren Sie nun zur Registerkarte AutoSearch, geben Sie Major in das Suchfeld ein und klicken Sie auf Search. Stellen Sie dann den Zeitrahmen auf Н1 und wählen Sie das Währungspaar GBPUSD aus. Hier sind die Testergebnisse.

Abb.11 Ergebnisse der Tests generierten Ein-Kerzen-Muster.

Wählen Sie die sechs häufigsten Kerzentypen aus. Diese sind 1,2,5,6,3,4 in absteigender Reihenfolge.

Schritt 2. Testen von Mustern mit zwei Kerzen.

Nun bilden wir Muster mit zwei Kerzen, die auf einfachen Typen basieren. Wir navigieren zur Registerkarte Settings und deaktivieren die Kontrollkästchen von 7 bis 11. Diesmal stellen wir den Modus "No Repeat" ein und stellen die "Number of Candles in the pattern" auf 2. Die obige Konfiguration ist in Abb.12 dargestellt.

Abb.12 Testkonfiguration für generierte Zwei-Kerzen-Muster.  

Gehen wir zurück zu AutoSearch und klicken auf GBPUSD. Dadurch entstehen verschiedene Kombinationen von ausgewählten Kerzen und deren Bewertung. Aber wenn der "Threshold trend value" niedrig ist, insbesondere bei höheren Zeitrahmen, sind die Ergebnisse der Preisbewegung oft fast gleich. Durch Erhöhen des Schwellenwerts können Sie strengere Bedingungen für die Mustersuche festlegen. Im Folgenden finden Sie beispielsweise die Ergebnisse für den Schwellenwert von 400:

Abb.13 Testergebnis mit einem erhöhten Trendschwellenwert.

Unter den erzielten Ergebnissen habe ich versucht, eine große Preisbewegung in eine Richtung und eine mehrfach geringere Bewegung in die andere zu finden. Wie aus Abbildung 13 ersichtlich ist, wurde die Situation zweimal aufgegriffen: [1,4] und [2,6]. Dies sind die Muster Long(bullish)—Short(bearish) and Long(bearish)—Spinning Top(bearish). Die zweite Mustervariante ist besser geeignet, da die Häufigkeit ihres Auftretens fast um ein Vielfaches höher ist.

Lassen Sie uns nun Muster mit drei Kerzen testen. Bei all den möglichen einfachen Modelloptionen erhalten wir zu viele Mustervarianten, daher werden wir nur 4 Typen verwenden, die in früheren Tests oft anzutreffen waren — 1,2,5,6. Eine ordnungsgemäß konfigurierte Registerkarte Settings sieht wie folgt aus:

Abb.14 Testkonfiguration für generierte Muster mit drei Kerzen.

Der Schwellenwert für den Trendwert ist immer noch gleich 400. Wir öffnen dann die Registerkarte AutoSearch und klicken erneut auf GBPUSD. Dabei wird das gleiche Prinzip für die Auswahl gut funktionierender Muster angewendet: eine viel größere Preisbewegung in eine Richtung als in die andere. Dies zeigt sich am Wirkungsgrad. Zum Beispiel begegnete ich zweimal hintereinander sehr interessanten Ergebnissen mit sehr guten Koeffizienten und Wahrscheinlichkeitsparametern.

Abb.15 Testergebnisse erzeugten drei Kerzenmuster.

Das sind die Muster [2,5,2] und das nächste [2,5,5,5]: Long(bearish)—Spinning Top(bullish)—Long(bearish) and Long(bearish)—Spinning Top(bullish)—Spinning Top(bullish). Das erste Kerzenmuster zeigte eine hohe Wahrscheinlichkeit für einen Aufwärtstrend und einen großen Wirkungsgrad. Die zweite hat eine gute Wahrscheinlichkeit für eine Richtung, aber einen etwas niedrigeren Wirkungsgrad. 

Eine große Anzahl von Parameterkombinationen kann weitere interessante Ergebnisse liefern. Beim Testen wird nicht empfohlen, alle elf Kerzentypen auf einmal zu verwenden, da die Datenverarbeitung viel Zeit in Anspruch nehmen kann. Die maximal möglichen Kombinationen von Mustern für die Analyse sind gleich 1463, ohne Berücksichtigung der Zeitspanne, des Zeitrahmens, des Trendschwellenwerts und individueller Einstellungen einfacher Kerzentypen. Eine so umfangreiche Analyse erfordert viel Zeit.

Schlussfolgerungen

Das unten angehängte Archiv enthält alle beschriebenen Dateien in Ordnern. Für den ordnungsgemäßen Betrieb müssen Sie lediglich den Ordner MQL5 in den Terminalverzeichnis speichern.

Programme, die im diesem Artikel verwendet werden

#
 Name
Typ
Beschreibung
1
PatternAnalyzer.mq5 Grafische Benutzeroberfläche
 Werkzeugleiste für die Analyse der Kerzenmuster
2 MainWindow.mqh Bibliothek  GUI Bibliothek
3 Program.mqh Bibliothek  Bibliothek der Methoden für das Interface und der Berechnung der Elemente

Übersetzt aus dem Russischen von MetaQuotes Software Corp.
Originalartikel: https://www.mql5.com/ru/articles/5630

Beigefügte Dateien |
MQL5.zip (431.36 KB)
Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil I). Konzept, Datenverwaltung und erste Ergebnisse Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil I). Konzept, Datenverwaltung und erste Ergebnisse

Bei der Analyse einer Vielzahl von Handelsstrategien, der Entwicklung von Anwendungen für MetaTrader 5 und MetaTrader 4 Terminals und verschiedenen MetaTrader Websites kam ich zu dem Schluss, dass diese ganze Vielfalt hauptsächlich auf den gleichen elementaren Funktionen, Aktionen und Werten basiert, die regelmäßig in verschiedenen Programmen wiederkehren. Daraus entstand die plattformübergreifende Bibliothek DoEasy für die einfache und schnelle Entwicklung von Anwendungen für МetaТrader 4 und 5.

MQL-Parsing mit Hilfe von MQL MQL-Parsing mit Hilfe von MQL

Der Artikel beschreibt einen Präprozessor, einen Scanner und einen Parser, die beim Parsen der MQL-basierten Quellcodes verwendet werden sollten. Die MQL-Implementierung ist beigefügt.

Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil II). Erhebung (Collection) historischer Aufträge und Deals Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil II). Erhebung (Collection) historischer Aufträge und Deals

Im ersten Teil begannen wir mit dem Erstellen einer großen plattformübergreifenden Bibliothek, die die Entwicklung von Programmen für MetaTrader 5 und MetaTrader 4 Plattformen vereinfacht. Wir haben das abstrakte Objekt COrder angelegt, das als Basisobjekt für die Speicherung von Daten zu historischen Aufträgen und Deals sowie zu Marktorders und Positionen dient. Jetzt werden wir alle notwendigen Objekte entwickeln, um die Daten der Kontenhistorie in "Collections" (Sammlungen bzw. Listen) zu speichern.

Extrahieren von strukturierten Daten aus HTML-Seiten mit Hilfe von CSS-Selektoren Extrahieren von strukturierten Daten aus HTML-Seiten mit Hilfe von CSS-Selektoren

Der Artikel beschreibt eine universelle Methode zur Analyse und Konvertierung von Daten aus HTML-Dokumenten auf Basis von CSS-Selektoren. Handelsberichte, Testerberichte, Ihren bevorzugten Wirtschaftskalender, öffentliche Signale, Kontoüberwachung und zusätzliche Online-Kursquellen werden direkt mit MQL verfügbar gemacht.