English Русский 中文 Español 日本語 Português
Die Handelssignale mehrerer Währungen überwachen (Teil 2): Implementierung des visuellen Teils der Anwendung

Die Handelssignale mehrerer Währungen überwachen (Teil 2): Implementierung des visuellen Teils der Anwendung

MetaTrader 5Handel | 20 Mai 2020, 09:33
1 248 0
Alexander Fedosov
Alexander Fedosov

Inhaltsverzeichnis

Einführung

Im vorherigen Artikel entwickelten wir die allgemeine Struktur des Monitors für Handelssignale mehrerer Symbole. In diesem Teil werden wir nacheinander die mit der anfänglichen Anwendungskonfiguration verbundenen Schritt-für-Schritt-Stufen implementieren und die grundlegende Interaktion der Elemente schaffen, aus denen die Schnittstelle besteht.


Setup-Schritt 1: Symbole

Entsprechend der Anwendungsstruktur impliziert der erste Schritt zur Einrichtung der Anwendung bei der ersten Inbetriebnahme die Schaffung einer Schnittstelle zur Auswahl von Symbolen, die weiter zur Suche nach erzeugten Handelssignalen verwendet werden sollen. Am Ende des vorhergehenden Artikels haben wir einen Anwendungsrahmen geschaffen, auf dessen Grundlage wir weiter arbeiten. Fahren wir mit der Anwendungsentwicklung fort. Zunächst werden wir die Hauptgruppen von Elementen definieren, die für die Implementierung dieses Anwendungsteils erforderlich sind:

  • Das Anwendungsfenster.
  • Schnelle Auswahl der Symbole.
  • Eingabefeld der Gruppe.
  • Schaltflächen zum Speichern und Laden von Symbolgruppen.
  • Die vollständige Liste aller verfügbaren Symbole als Kontrollkästchen mit einer Textbeschriftung für den Symbolnamen.
  • Die Schaltfläche Next (Weiter) für den Wechsel zum zweiten Einrichtungsschritt: Auswahl des Zeitrahmens.

Die zuvor erstellte Dateistruktur sollte wie folgt aussehen:

Abb. 1 Struktur der Anwendungsdatei.

Wir öffnen zunächst die Anwendungsdatei SignalMonitor.mq5 und geben die Eingabeparameter ein. Sie werden die Parameter einstellen können, wenn Sie die Anwendung direkt im MetaTrader 5 Terminal ausführen. Wir deklarieren auch die Instanz der zuvor erstellten Klasse CProgramm und initialisieren einige der Variablen. Bearbeiten wir die Datei wie folgt:

//+------------------------------------------------------------------+
//|                                                SignalMonitor.mq5 |
//|                                Copyright 2019, Alexander Fedosov |
//|                           https://www.mql5.com/en/users/alex2356 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Alexander Fedosov"
#property link      "https://www.mql5.com/en/users/alex2356"
#property version   "1.00"
//--- Include application class
#include "Program.mqh"
//+------------------------------------------------------------------+
//| Expert Advisor input parameters                                  |
//+------------------------------------------------------------------+
input int                  Inp_BaseFont      =  10;                  // Basic font
input color                Caption           =  C'0,130,225';        // Caption color
input color                Background        =  clrWhiteSmoke;       // Background color
//---
CProgram program;
ulong tick_counter;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(void)
{
//---
   tick_counter=GetTickCount();
//--- Initialize class variables
   program.OnInitEvent();
   program.m_base_font_size=Inp_BaseFont;
   program.m_background=Background;
   program.m_caption=Caption;
//--- Set up the trading panel
   if(!program.CreateGUI())
   {
      Print(__FUNCTION__," > Failed to create graphical interface!");
      return(INIT_FAILED);
   }
//--- Initialization completed successfully
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   program.OnDeinitEvent(reason);
}
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer(void)
{
   program.OnTimerEvent();
}
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int    id,
                  const long   &lparam,
                  const double &dparam,
                  const string &sparam)
{
   program.ChartEvent(id,lparam,dparam,sparam);
   //---
   if(id==CHARTEVENT_CUSTOM+ON_END_CREATE_GUI)
   {
      Print("End in ",GetTickCount()-tick_counter," ms");
   }
}
//+------------------------------------------------------------------+

 Wie aus dem Code ersichtlich ist, wurden drei Eingabeparameter hinzugefügt:

  • Schriftgröße.
  • Die Farbe der Kopfzeile für die Anwendungsfenster.
  • Die Hintergrundfarbe für die Anwendungsfenster und -elemente.

Als Nächstes deklarieren wir die Klasseninstanz CProgramm mit dem Namen Programm und die Variable tick_counter (sie wird nur für die Anzeige von Informationen über die Startzeit der Anwendung benötigt). Außerdem initialisieren wir in der Methode OnInit() die Klasseninstanzvariablen, indem wir ihnen die Werte der Eingabeparameter der Anwendung zuweisen. Wir rufen auch die grundlegende Methode CreateGUI() auf, die die Anwendung startet.

Wenn wir jedoch versuchen, die geöffnete Datei jetzt zu kompilieren, erhalten wir Kompilierungsfehler, die besagen, dass die Variablen m_base_font_size, m_background, m_caption und die Methode CreateGUI() in der Klasse CProgram nicht gefunden wurden. Wir öffnen daher die Datei Program.mqh, um die Klasse CProgram zu implementieren. Wir fügen zunächst die oben genannten Variablen und die Methode sowie andere Methoden hinzu, die für die korrekte Inbetriebnahme der Anwendung erforderlich sind. Die Datei CProgram wird so aussehen, nachdem wir die erforderlichen Elemente hinzugefügt haben:

//+------------------------------------------------------------------+
//| Class for creating an application                                |
//+------------------------------------------------------------------+
class CProgram : public CWndEvents
{
public:
//---
   int               m_base_font_size;
//---
   string            m_base_font;
//---
   color             m_background;
   color             m_caption;
public:
   CProgram(void);
   ~CProgram(void);
   //--- Initialization/deinitialization
   void              OnInitEvent(void);
   void              OnDeinitEvent(const int reason);
   //--- Timer
   void              OnTimerEvent(void);
   //--- Chart event handler
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
   //--- Create the graphical interface of the program
   bool              CreateGUI(void);
};

Die Implementierung der Methode, die die Schnittstelle erzeugt, ist noch leer:

//+------------------------------------------------------------------+
//| Creates the graphical interface of the program                   |
//+------------------------------------------------------------------+
bool CProgram::CreateGUI(void)
{
//---

//--- Finish the creation of GUI
   CWndEvents::CompletedGUI();
   return(true);
}
//+------------------------------------------------------------------+

Beachten Sie, dass wir auch die String-Variable m_base_font hinzugefügt haben, die für den Schriftnamen in der Anwendung verantwortlich ist. Sie wird in unserem Klassenkonstruktor initialisiert:

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CProgram::CProgram(void)
{
   m_base_font="Trebuchet MS";
}

Nun wollen wir mit der Erstellung des ersten Fensters der Anwendung fortfahren. Zu diesem Zweck deklarieren Sie in der Klasse die neue Variable m_step_window, die eine Instanz der Klasse CWindow ist. Deklarieren wir auch eine Methode, die das erste Fenster erzeugt, und nennen sie CreateStepWindow(). So sieht der Code in der Klasse aus:

class CProgram : public CWndEvents
{
public:
//--- Application windows
   CWindow           m_step_window;
...
protected:
   //--- forms
   bool              CreateStepWindow(const string caption_text);

Wir haben bereits früher festgelegt, dass sich die Implementierung des Schnittstellenteils, der für die schrittweise Konfiguration des ersten Starts verantwortlich ist, in der Include-Datei StepWindow.mqh befindet. Öffnen wir sie also und beginnen mit der Implementierung der Methode CreateStepWindow():

#include "Program.mqh"
//+------------------------------------------------------------------+
//| Creates a form for the selection of symbols                      |
//+------------------------------------------------------------------+
bool CProgram::CreateStepWindow(const string text)
{
//--- Add the pointer to the window array
   CWndContainer::AddWindow(m_step_window);
//--- Properties
   m_step_window.XSize(600);
   m_step_window.YSize(200);
//--- Coordinates
   int x=int(ChartGetInteger(m_chart_id,CHART_WIDTH_IN_PIXELS)-m_step_window.XSize())/2;
   int y=10;
   m_step_window.CaptionHeight(22);
   m_step_window.IsMovable(true);
   m_step_window.CaptionColor(m_caption);
   m_step_window.CaptionColorLocked(m_caption);
   m_step_window.CaptionColorHover(m_caption);
   m_step_window.BackColor(m_background);
   m_step_window.FontSize(m_base_font_size);
   m_step_window.Font(m_base_font);
//--- Creating a form
   if(!m_step_window.CreateWindow(m_chart_id,m_subwin,text,x,y))
      return(false);
   //---
   return(true);
}
//+------------------------------------------------------------------+

Vergessen wir nicht, Folgendes in der Methode CreateGUI() hinzuzufügen:

//+------------------------------------------------------------------+
//| Creates the graphical interface of the program                   |
//+------------------------------------------------------------------+
bool CProgram::CreateGUI(void)
{
//--- Step 1-3
   if(!CreateStepWindow("Signal Monitor Step 1: Choose Symbols"))
      return(false);
//--- Finish the creation of GUI
   CWndEvents::CompletedGUI();
   return(true);
}
//+------------------------------------------------------------------+

Wenn die Reihenfolge der Aktionen korrekt ist, sehen Sie das neu erstellte Formular, nachdem Sie die Datei SignalMonitor.mq5 kompiliert und im Terminal gestartet haben:

Abb. 2 Das erste Fenster der Anwendung

Zu den ersten Elementen des erstellten Fensters gehört eine Gruppe von Schaltflächen, die die schnelle Auswahl vordefinierter Symbolsätze aus dem Terminal ermöglichen: forex.all, forex.crosses, forex.major. In der Datei Program.mqh fügen wir ein Array der Klasseninstanzen von CButton mit der drei Dimensionen, sowie die universelle Methode CreateSymbolSet() zur Erstellen von Schaltflächen hinzu:

//+------------------------------------------------------------------+
//| Class for creating an application                                |
//+------------------------------------------------------------------+
class CProgram : public CWndEvents
{
public:
//--- Application windows
   CWindow           m_step_window;
//--- Simple buttons
   CButton           m_currency_set[3];
...
   //--- Buttons
   bool              CreateSymbolSet(CButton &button,string text,const int x_gap,const int y_gap);

Öffnen wir nun die Datei StepWindow.mqh und fügen die obige Methodenimplementierung hinzu.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CProgram::CreateSymbolSet(CButton &button,string text,const int x_gap,const int y_gap)
{
//---
   color baseclr=C'220,225,235';
   color pressed=C'55,160,250';
//--- Save the window pointer
   button.MainPointer(m_step_window);
//--- Set properties before creation
   button.TwoState(true);
   button.XSize(80);
   button.YSize(30);
   button.LabelXGap(19);
   button.LabelYGap(2);
   button.Font(m_base_font);
   button.FontSize(m_base_font_size);
   button.BackColor(baseclr);
   button.BackColorHover(baseclr);
   button.BackColorPressed(pressed);
   button.BorderColor(baseclr);
   button.BorderColorHover(baseclr);
   button.BorderColorPressed(pressed);
   button.LabelColor(clrBlack);
   button.LabelColorPressed(clrWhite);
   button.IsCenterText(true);
//--- Create a control
   if(!button.CreateButton(text,x_gap,y_gap))
      return(false);
//--- Add a pointer to element to the base
   CWndContainer::AddToElementsArray(0,button);
   return(true);
}
//+------------------------------------------------------------------+

Jetzt brauchen wir nur noch drei Schaltflächen mit unterschiedlichen Koordinatenwerten und Textbeschriftungen mit dieser Methode in der Grundmethode CreateStepWindow() des Fensters nach dem Erstellen des Formulars hinzuzufügen:

...
//--- Creating a form
   if(!m_step_window.CreateWindow(m_chart_id,m_subwin,text,x,y))
      return(false);
//---
   if(!CreateSymbolSet(m_currency_set[0],"ALL",10,30))
      return(false);
   if(!CreateSymbolSet(m_currency_set[1],"Major",10+100,30))
      return(false);
   if(!CreateSymbolSet(m_currency_set[2],"Crosses",10+2*(100),30))
      return(false);
...

Nach dem Kompilieren sieht das Ergebnis wie folgt aus:

Abb. 3 Hinzufügen von Schaltflächen zur Schnellauswahl von Symbolgruppen.

Als Nächstes fügen wir ein Eingabefeld für den Namen der ausgewählten Symbolgruppe hinzu, das mit zwei Schaltflächen gespeichert und geladen werden kann: Speichern und Laden. Dafür fügen wir eine Klasseninstanz für die Erstellung des Eingabefeldes CTextEdit und zwei weitere Klasseninstanzen für die Erstellung von Schaltflächen CButton hinzu. Da sich die Schaltflächen zum Speichern und Laden nur in ihren Namen unterscheiden, erzeugen Sie die allgemeine Methode CreateButton1(), und fügen sie dem Eingabefeld CreateEditValue() zur Klasse CProgram: hinzu.

//+------------------------------------------------------------------+
//| Class for creating an application                                |
//+------------------------------------------------------------------+
class CProgram : public CWndEvents
{
public:
//--- Application windows
   CWindow           m_step_window;
//--- Simple buttons
   CButton           m_currency_set[3];
   CButton           m_load_button;
   CButton           m_save_button;
   //--- Input fields
   CTextEdit         m_text_edit;
...
   bool              CreateButton1(CButton &button,string text,const int x_gap,const int y_gap);
   //--- Input field
   bool              CreateEditValue(CTextEdit &text_edit,const int x_gap,const int y_gap);

Gehen wir zurück zur Datei StepWindow.mqh und fügen die Implementierung der erstellten Methoden am Ende der Datei hinzu.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CProgram::CreateEditValue(CTextEdit &text_edit,const int x_gap,const int y_gap)
{
//--- Store the pointer to the main control
   text_edit.MainPointer(m_step_window);
//--- Properties
   text_edit.XSize(110);
   text_edit.YSize(24);
   text_edit.Font(m_base_font);
   text_edit.FontSize(m_base_font_size);
   text_edit.GetTextBoxPointer().XGap(1);
   text_edit.GetTextBoxPointer().XSize(110);
   text_edit.GetTextBoxPointer().DefaultTextColor(clrSilver);
   text_edit.GetTextBoxPointer().DefaultText("Template name");
//--- Create a control
   if(!text_edit.CreateTextEdit("",x_gap,y_gap))
      return(false);
//--- Add an object to the common array of object groups
   CWndContainer::AddToElementsArray(0,text_edit);
   return(true);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CProgram::CreateButton1(CButton &button,string text,const int x_gap,const int y_gap)
{
//---
   color baseclr=C'70,180,70';
   color pressed=C'70,170,70';
//--- Save the window pointer
   button.MainPointer(m_step_window);
//--- Set properties before creation
   button.XSize(80);
   button.YSize(30);
   button.Font(m_base_font);
   button.FontSize(m_base_font_size);
   button.BackColor(baseclr);
   button.BackColorHover(baseclr);
   button.BackColorPressed(pressed);
   button.BorderColor(baseclr);
   button.BorderColorHover(baseclr);
   button.BorderColorPressed(pressed);
   button.LabelColor(clrWhite);
   button.LabelColorPressed(clrWhite);
   button.LabelColorHover(clrWhite);
   button.IsCenterText(true);
//--- Create a control
   if(!button.CreateButton(text,x_gap,y_gap))
      return(false);
//--- Add a pointer to element to the base
   CWndContainer::AddToElementsArray(0,button);
   return(true);
}

 Gehen wir dann zurück zu der Klasse CreateStepWindow(), um zwei Schaltflächen und ein Eingabefeld im Anwendungsfenster hinzuzufügen.

//---
   if(!CreateEditValue(m_text_edit,300,m_step_window.CaptionHeight()+10))
      return(false);
//---
   if(!CreateButton1(m_load_button,"Load(L)",m_step_window.XSize()-2*(80+10),m_step_window.CaptionHeight()+10))
      return(false);
   if(!CreateButton1(m_save_button,"Save(S)",m_step_window.XSize()-(80+10),m_step_window.CaptionHeight()+10))
      return(false);

Wieder kompilieren wir die Datei SignalMonitor.mq5. Hier ist das Ergebnis:

Abb.4 Das hinzugefügte Eingabefeld für Symbolgruppen und die Schaltflächen Save/Load (Sichern/Laden).

Kommen wir nun zur Visualisierung und der Möglichkeit, alle Symbole auszuwählen, die für das ausgewählte Konto im MetaTrader 5-Terminal zur Verfügung stehen. Beachten Sie, dass die Höhe des Anwendungsfensters nicht ausreicht, um alle verfügbaren Symbole anzuzeigen. Eine gute Lösung ist es, die automatische Anpassung der Fensterhöhe in Abhängigkeit von den Daten zu ermöglichen. Das Hinzufügen aller Symbole ist ähnlich: Wir fügen eine Reihe von Klasseninstanzen für die Erstellung von Kontrollkästchen CCheckBox und universelle Methoden für deren Erstellung hinzu (da sie sich nur im Namen unterscheiden werden).

...
   //--- Checkboxes
   CCheckBox         m_checkbox[];
...
   //--- Checkboxes
   bool              CreateCheckBox(CCheckBox &checkbox,const int x_gap,const int y_gap,const string text);

Die Dimension des Arrays m_checkbox[] wird nicht angegeben, da im Voraus nicht bekannt ist, wie viele Symbole auf dem ausgewählten Konto im Terminal vorhanden sind. Lassen Sie uns deshalb zwei Variablen im 'private' Teil der Klasse Programm erstellen und ihnen die Gesamtzahl der verfügbaren Symbole und die Anzahl der aktuell ausgewählten Symbole in Market Watch zuweisen.

private:
//---
   int               m_symbol_total;
   int               m_all_symbols;

Im Klassenkonstruktor weisen wir die erforderlichen Werte zu und setzen die entsprechende Dimension auf das Array m_checkbox[]:

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CProgram::CProgram(void)
{
   m_base_font="Trebuchet MS";
   m_symbol_total=SymbolsTotal(true);
   m_all_symbols=SymbolsTotal(false);
   ArrayResize(m_checkbox,m_all_symbols);
}

Fügen wir diese Methodenimplementierung am Ende der Datei StepWindow.mqh hinzu:

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CProgram::CreateCheckBox(CCheckBox &checkbox,const int x_gap,const int y_gap,const string text)
{
//--- Store the pointer to the main control
   checkbox.MainPointer(m_step_window);
//--- Properties
   checkbox.GreenCheckBox(true);
   checkbox.IsPressed(false);
   checkbox.Font(m_base_font);
   checkbox.FontSize(m_base_font_size);
   checkbox.BackColor(m_background);
   checkbox.LabelColorHover(C'55,160,250');
//--- Create a control
   if(!checkbox.CreateCheckBox(text,x_gap,y_gap))
      return(false);
//--- Add a pointer to element to the base
   CWndContainer::AddToElementsArray(0,checkbox);
   return(true);
}

Fügen wir auch noch Kontrollkästchen in der Methode CreateStepWindow() hinzu. Im untenstehenden Code hat die gesamte Liste der verfügbaren Symbole 7 Spalten. Zusätzlich wird die Fensterhöhe entsprechend der Anzahl der empfangenen Zeilen geändert.

   //--- Checkboxes
   int k=0;
   for(int j=0; j<=MathCeil(m_all_symbols/7); j++)
   {
      for(int i=0; i<7; i++)
      {
         if(k<m_all_symbols)
            if(!CreateCheckBox(m_checkbox[k],10+80*i,m_step_window.CaptionHeight()+70+j*25,SymbolName(k,false)))
               return(false);
         k++;
      }
   }
   m_step_window.ChangeWindowHeight(m_checkbox[m_all_symbols-1].YGap()+30+30);

Kopieren Sie die resultierenden Ergänzungen:

Abb.5 Die Kontrollkästchen für alle verfügbaren Symbolen.

Das letzte Element dieses Anwendungsteils enthält Navigationsschaltflächen zum Umschalten zwischen den Einrichtungsschritten. Sie können leicht hinzugefügt werden: Fügen Sie zwei Instanzen der Klasse CButton mit den Namen m_next_button und m_back_button hinzu, verwenden Sie die Erstellungsmethode aus dem zuvor erstellten CreateButton1(). Fügen wir in der Erstellungsmethode des Fensters CreateStepWindow() Folgendes hinzu:

//---
   if(!CreateButton1(m_back_button,"Back",m_step_window.XSize()-2*(80+10),m_step_window.YSize()-(30+10)))
      return(false);
   if(!CreateButton1(m_next_button,"Next",m_step_window.XSize()-(80+10),m_step_window.YSize()-(30+10)))
      return(false);

Jetzt müssen wir nur noch die Bedienung der Schaltflächen konfigurieren, mit denen vordefinierte Symbolsätze ausgewählt werden können. Öffnen wir die Datei Program.mqh und suchen die Methode OnEvent() und fügen den folgenden Code hinzu:

//+------------------------------------------------------------------+
//| Chart event handler                                              |
//+------------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//--- Pressing the button event
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
   {
      //--- All
      if(lparam==m_currency_set[0].Id() && m_currency_set[0].IsPressed())
      {
         m_currency_set[1].IsPressed(false);
         m_currency_set[2].IsPressed(false);
         m_currency_set[1].Update(true);
         m_currency_set[2].Update(true);
         //---
         for(int i=0; i<m_all_symbols; i++)
         {
            m_checkbox[i].IsPressed(true);
            m_checkbox[i].Update(true);
         }
      }
      //--- Majors
      else if(lparam==m_currency_set[1].Id() && m_currency_set[1].IsPressed())
      {
         m_currency_set[0].IsPressed(false);
         m_currency_set[2].IsPressed(false);
         m_currency_set[0].Update(true);
         m_currency_set[2].Update(true);
         //---
         string pairs[4]= {"EURUSD","GBPUSD","USDCHF","USDJPY"};
         //--- Clear the selection
         for(int i=0; i<m_all_symbols; i++)
         {
            m_checkbox[i].IsPressed(false);
            m_checkbox[i].Update(true);
         }
         //---
         for(int i=0; i<m_all_symbols; i++)
         {
            for(int j=0; j<4; j++)
               if(m_checkbox[i].LabelText()==pairs[j])
               {
                  m_checkbox[i].IsPressed(true);
                  m_checkbox[i].Update(true);
               }
         }
      }
      //--- Crosses
      else if(lparam==m_currency_set[2].Id() && m_currency_set[2].IsPressed())
      {
         m_currency_set[0].IsPressed(false);
         m_currency_set[1].IsPressed(false);
         m_currency_set[0].Update(true);
         m_currency_set[1].Update(true);
         //---
         string pairs[20]=
         {
            "EURUSD","GBPUSD","USDCHF","USDJPY","USDCAD","AUDUSD","AUDNZD","AUDCAD","AUDCHF","AUDJPY",
            "CHFJPY","EURGBP","EURAUD","EURCHF","EURJPY","EURCAD","EURNZD","GBPCHF","GBPJPY","CADCHF"
         };
         //--- Clear the selection
         for(int i=0; i<m_all_symbols; i++)
         {
            m_checkbox[i].IsPressed(false);
            m_checkbox[i].Update(true);
         }
         //---
         for(int i=0; i<m_all_symbols; i++)
         {
            for(int j=0; j<20; j++)
               if(m_checkbox[i].LabelText()==pairs[j])
               {
                  m_checkbox[i].IsPressed(true);
                  m_checkbox[i].Update(true);
               }
         }
      }
      //---
      if((lparam==m_currency_set[0].Id() && !m_currency_set[0].IsPressed())      ||
            (lparam==m_currency_set[1].Id() && !m_currency_set[1].IsPressed())   ||
            (lparam==m_currency_set[2].Id() && !m_currency_set[2].IsPressed())
        )
      {
         //--- Clear the selection
         for(int i=0; i<m_all_symbols; i++)
         {
            m_checkbox[i].IsPressed(false);
            m_checkbox[i].Update(true);
         }
      }
   }
}

Die Idee dieser Umsetzung ist wie folgt:

  • Ein Klick auf ALL wählt alle Symbole aus.
  • Ein Klick auf Major entfernt die vorherige Auswahl und setzt einen Satz von Symbolen, der forex.major in Terminals entspricht.
  • Ein Klick auf Crosses entfernt die vorherige Auswahl und setzt eine Reihe von Symbolen, die crosses.major in Terminals entsprechen.
  • Wenn alle drei Knöpfe nicht gedrückt sind, wird jede Auswahl aufgehoben.

Und so sieht das Ganze aus:

Abb.6 Implementierung der grundlegenden Interaktion der Elemente.

Zwei kleine Ergänzungen sind erforderlich, um die visuelle Implementierung zu vervollständigen. In Abbildung 5 sehen wir, dass das Fenster die zuvor erstellte Schaltfläche Back (Zurück) enthält. Dies ist jedoch Schritt 1, so dass es eine solche Schaltfläche nicht geben sollte. Sie sollte ausgeblendet und nur in den Schritten 2 und 3 angezeigt werden. Fügen wir die folgende Zeile der Methode CreateGUI() hinzu:

bool CProgram::CreateGUI(void)
{
//--- Step 1-3
   if(!CreateStepWindow("Signal Monitor Step 1: Choose Symbols"))
      return(false);
//--- Finish the creation of GUI
   CWndEvents::CompletedGUI();
   m_back_button.Hide();
   return(true);
}

Außerdem müssen wir die Auswahl des Nutzers überwachen. Der Wechsel zu Schritt 2 sollte nicht erlaubt sein, wenn der Nutzer nicht mindestens ein Symbol ausgewählt hat. Das Umschalten zwischen den Schritten wird mit den Schaltflächen Back (Zurück) und Next (Weiter) durchgeführt. Um die Aufgabe zu lösen, fügen wir also drei neue Methoden zum 'private' Abschnitt der Klasse Programm hinzu. Die Methoden verarbeiten die in jedem der drei Schritte ausgewählten Informationen und führen so die anfängliche Einrichtung der Anwendung durch. Wir fügen auch die Variable m_current_step hinzu: Wenn Back/Next angeklickt wird, weiß die Anwendung, in welchem Schritt wir uns gerade befinden.

private:
//---
   int               m_symbol_total;
   int               m_all_symbols;
   int               m_current_step;
   //---
   void              ToStep_1(void);
   void              ToStep_2(void);
   void              ToStep_3(void);

Danach setzen wir im Klassenkonstruktor den Wert des ersten Schrittes für die erzeugte Variable, d.h. 1. Um die Navigation zwischen den drei Konfigurationsschritten einzurichten, fügen wir den untenstehenden Code in das Ereignis eines Schaltflächenklicks in OnEvent() ein:

      //--- Navigation
      if(lparam==m_back_button.Id())
      {
         //--- Return to Step 1
         if(m_current_step==2)
            ToStep_1();
         //--- Return to Step 2
         else if(m_current_step==3)
            ToStep_2();
      }
      //--- Go to Step 2
      if(lparam==m_next_button.Id())
      {
         //--- Go to Step 2
         if(m_current_step==1)
            ToStep_2();
         //--- Go to Step 3
         else if(m_current_step==2)
            ToStep_3();
      }

Wenn wir versuchen, das Projekt so zu kompilieren, gibt der Compiler den Fehler zurück, dass die drei verwendeten Methoden zwar erstellt wurden, sie aber keine Implementierung haben: 

die Funktion 'CProgramm::ToStep_1' muss einen Körper haben Programm.mqh 60 22

Um dies zu beheben, implementieren wir diese Klassen in der Datei Program.mqh. Lassen wir sie jedoch für die Methoden ToStep_1() und ToStep_3() vorerst leer. Sie werden später gefüllt. Nun interessieren wir uns für den Methodenwechsel zum zweiten Schritt ToStep_2(). Fügen wir eine Prüfung hinzu, ob mindestens ein Symbol ausgewählt ist:

//+------------------------------------------------------------------+
//| Go to Step 1                                                     |
//+------------------------------------------------------------------+
void CProgram::ToStep_1(void)
{
//---
}
//+------------------------------------------------------------------+
//| Go to Step 2                                                 |
//+------------------------------------------------------------------+
void CProgram::ToStep_2(void)
{
//--- Check whether at least one symbol is selected
   int cnt=0;
   for(int i=0; i<m_all_symbols; i++)
   {
      if(m_checkbox[i].IsPressed())
         cnt++;
   }
   if(cnt<1)
   {
      MessageBox("No symbols selected!","Warning");
      return;
   }
}
//+------------------------------------------------------------------+
//| Move to Step 3 3                                                 |
//+------------------------------------------------------------------+
void CProgram::ToStep_3(void)
{
//---
}

Wenn der Nutzer versehentlich Next drückt, ohne ein Symbol auszuwählen, wird eine Warnung angezeigt, dass mindestens ein Symbol ausgewählt werden sollte.


Setup-Schritt 2: Zeitrahmen

Im zweiten Schritt der Anwendungseinrichtung sollte der Nutzer Zeitrahmen auswählen, zu denen Handelssignale gesucht werden sollen. Die erforderlichen UI-Elemente haben wir bereits im ersten Artikel erwähnt:

  • Eine Gruppe von Schaltflächen zur schnellen Auswahl von Zeitrahmen.
  • Eine Liste von Zeitrahmen in Form von Ankreuzfeldern.
  • Die Schaltfläche Back, um zu Schritt 1 zurückzukehren.

Lassen Sie uns vorhandene Objekte aus der visuellen Umsetzung von Schritt 1 verwenden und diese für die Auswahl der Zeitrahmen anpassen. Gehen wir zum Hauptteil der Methode ToStep_2(), die wir vor kurzem bearbeitet haben, und fügen ihr zusätzliche Funktionen hinzu. Erinnern wir uns zunächst an die Auswahl der Symbole in Schritt 1 und zeigen sie in Market Watch im MetaTrader 5:

//--- Set selected symbols in Market Watch
   for(int i=0; i<m_all_symbols; i++)
   {
      if(m_checkbox[i].IsPressed())
         SymbolSelect(m_checkbox[i].LabelText(),true);
      else
         SymbolSelect(m_checkbox[i].LabelText(),false);
   }

Dann transformieren wir die Schnittstelle von Schritt 1 in die zweite:

//--- Change header
   m_step_window.LabelText("Signal Monitor Step 2: Choose Timeframes");
   m_step_window.Update(true);
//--- Hide elements of Step 1
   for(int i=0; i<m_all_symbols; i++)
   {
      m_checkbox[i].IsLocked(false);
      m_checkbox[i].IsPressed(false);
      m_checkbox[i].Hide();
   }
   string names[3]= {"All","Junior","Senior"};
//--- Change names of selection buttons
   for(int i=0; i<3; i++)
   {
      m_currency_set[i].LabelText(names[i]);
      m_currency_set[i].IsPressed(false);
      if(m_current_step==3)
         m_currency_set[i].Show();
      m_currency_set[i].Update(true);
   }
//--- Hide block for working with templates
   m_text_edit.Hide();
   m_load_button.Hide();
   m_save_button.Hide();
//--- Show all timeframes
   string timeframe_names[21]=
   {
      "M1","M2","M3","M4","M5","M6","M10","M12","M15","M20","M30",
      "H1","H2","H3","H4","H6","H8","H12","D1","W1","MN"
   };
   for(int i=0; i<21; i++)
   {
      m_checkbox[i].LabelText(timeframe_names[i]);
      m_checkbox[i].Show();
      m_checkbox[i].Update(true);
   }
//--- Show Back button
   m_back_button.Show();
//---
   m_current_step=2;

Die Implementierung ist recht einfach. Am Ende weisen wir der Variablen m_current_step den Wert 2 zu (Schritt 2). Jetzt müssen wir die korrekte Anzeige der ausgewählten Zeitrahmensätze All, Junior, Senior durch die geänderte Schnittstelle bereitstellen. Öffnen wir Programm.mqh und ändern den Code in der Methode OnEvent(). Die Änderung ist im Ereignisabschnitt "button click" erforderlich. Aus der Sicht des Objekts sind die Schnellauswahltasten in Schritt 1 und 2 ähnlich. Deshalb ist es notwendig, den aktuellen Einrichtungsschritt im Ereignis "button click" zu definieren:

 //--- Step 1
      if(m_current_step==1)
      {
       ...
      }
      //--- Step 2
      else if(m_current_step==2)
      {
         //--- All
         if(lparam==m_currency_set[0].Id() && m_currency_set[0].IsPressed())
         {
            m_currency_set[1].IsPressed(false);
            m_currency_set[2].IsPressed(false);
            m_currency_set[1].Update(true);
            m_currency_set[2].Update(true);
            //---
            for(int i=0; i<21; i++)
            {
               m_checkbox[i].IsPressed(true);
               m_checkbox[i].Update(true);
            }
         }
         //--- Junior Timeframes
         else if(lparam==m_currency_set[1].Id() && m_currency_set[1].IsPressed())
         {
            m_currency_set[0].IsPressed(false);
            m_currency_set[2].IsPressed(false);
            m_currency_set[0].Update(true);
            m_currency_set[2].Update(true);
            //---
            string pairs[11]=
            {
               "M1","M2","M3","M4","M5","M6","M10","M12","M15","M20","M30"
            };
            //--- Clear the selection
            for(int i=0; i<21; i++)
            {
               m_checkbox[i].IsPressed(false);
               m_checkbox[i].Update(true);
            }
            //---
            for(int i=0; i<21; i++)
            {
               for(int j=0; j<11; j++)
                  if(m_checkbox[i].LabelText()==pairs[j])
                  {
                     m_checkbox[i].IsPressed(true);
                     m_checkbox[i].Update(true);
                  }
            }
         }
         //--- Senior Timeframes
         else if(lparam==m_currency_set[2].Id() && m_currency_set[2].IsPressed())
         {
            m_currency_set[0].IsPressed(false);
            m_currency_set[1].IsPressed(false);
            m_currency_set[0].Update(true);
            m_currency_set[1].Update(true);
            //---
            string pairs[10]=
            {
               "H1","H2","H3","H4","H6","H8","H12","D1","W1","MN"
            };
            //--- Clear the selection
            for(int i=0; i<m_all_symbols; i++)
            {
               m_checkbox[i].IsPressed(false);
               m_checkbox[i].Update(true);
            }
            //---
            for(int i=0; i<m_all_symbols; i++)
            {
               for(int j=0; j<10; j++)
                  if(m_checkbox[i].LabelText()==pairs[j])
                  {
                     m_checkbox[i].IsPressed(true);
                     m_checkbox[i].Update(true);
                  }
            }
         }

Das letzte UI-Element, das im zweiten Setup-Schritt implementiert wird, ist die Schaltfläche Back, die zu Schritt 1 zurückkehrt. Dies geschieht durch den angelegten, aber noch leeren Schritt ToStep_1(). Kehren wir zur vorherigen Schnittstelle zurück und setzen den vorherigen Wrapper für die Verarbeitung der Klick-Ereignisse der Auswahltaste.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CProgram::ToStep_1(void)
{
//--- Change header
   m_step_window.LabelText("Signal Monitor Step 1: Choose Symbols");
   m_step_window.Update(true);
//--- Hide the Back button
   m_back_button.Hide();
//--- Clear selection
   for(int i=0; i<21; i++)
   {
      m_checkbox[i].IsPressed(false);
      m_checkbox[i].Update(true);
   }
//--- Show elements of Step 1
   for(int i=0; i<m_all_symbols; i++)
   {
      m_checkbox[i].Show();
      m_checkbox[i].LabelText(SymbolName(i,false));
      m_checkbox[i].Update(true);
   }
   string names[3]= {"All","Majors","Crosses"};
//--- Change names of selection buttons
   for(int i=0; i<3; i++)
   {
      m_currency_set[i].IsPressed(false);
      m_currency_set[i].LabelText(names[i]);
      m_currency_set[i].Update(true);
   }
//--- Show block for working with templates
   m_text_edit.Show();
   m_load_button.Show();
   m_save_button.Show();
//--- Set the current setup step
   m_current_step=1;
}

Kompilieren wir nun das Projekt. Wenn alles korrekt hinzugefügt wurde, wird das Ergebnis wie in Abb.7 aussehen.

Abb.7 Implementierung von Schritt 2 der Anwendung.

Setup-Schritt 3: Signale hinzufügen

Der nächste Schritt ist Schritt 3: Das Interface, um Signale hinzufügen. Es ist recht einfach und besteht aus einer Schaltfläche zum Hinzufügen von Signalen und einer Kopfzeile für die Liste der hinzugefügten Signale. Öffnen wir Programm.mqh und deklarieren zwei neue Variablen in СProgram:

   CButton           m_add_signal;
   //---
   CTextLabel        m_signal_header;

Methoden, die Variablen zu implementieren:

   bool              CreateIconButton(CButton &button,string text,const int x_gap,const int y_gap);
   //--- Text label
   bool              CreateLabel(CTextLabel &text_label,const int x_gap,const int y_gap,string label_text);

Fügen wir ihre Implementierung am Ende der Datei StepWindow.mqh hinzu.

//+------------------------------------------------------------------+
//| Creates a button with an image                                   |
//+------------------------------------------------------------------+
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp16\\plus.bmp"
bool CProgram::CreateIconButton(CButton &button,string text,const int x_gap,const int y_gap)
{
//---
   color baseclr=C'70,180,70';
   color pressed=C'70,170,70';
//--- Save the window pointer
   button.MainPointer(m_step_window);
//--- Set properties before creation
   button.XSize(110);
   button.YSize(30);
   button.Font(m_base_font);
   button.FontSize(m_base_font_size);
   button.IconXGap(3);
   button.IconYGap(7);
   button.IconFile("Images\\EasyAndFastGUI\\Icons\\bmp16\\plus.bmp");
   button.BackColor(baseclr);
   button.BackColorHover(baseclr);
   button.BackColorPressed(pressed);
   button.BorderColor(baseclr);
   button.BorderColorHover(baseclr);
   button.BorderColorPressed(pressed);
   button.LabelColor(clrWhite);
   button.LabelColorPressed(clrWhite);
   button.LabelColorHover(clrWhite);
   button.IsCenterText(true);
//--- Create a control
   if(!button.CreateButton(text,x_gap,y_gap))
      return(false);
//--- Add a pointer to element to the base
   CWndContainer::AddToElementsArray(0,button);
   return(true);
}
//+------------------------------------------------------------------+
//| Creates the text label                                           |
//+------------------------------------------------------------------+
bool CProgram::CreateLabel(CTextLabel &text_label,const int x_gap,const int y_gap,string label_text)
{
//--- Save the window pointer
   text_label.MainPointer(m_step_window);
//---
   text_label.Font(m_base_font);
   text_label.FontSize(m_base_font_size);
   text_label.XSize(120);
   text_label.BackColor(m_background);
//--- Create the button
   if(!text_label.CreateTextLabel(label_text,x_gap,y_gap))
      return(false);
//--- Add a pointer to element to the base
   CWndContainer::AddToElementsArray(0,text_label);
   return(true);
}
//+------------------------------------------------------------------+

Fügen wir die folgenden Elemente in das Fenster CreateStepWindow() ein, damit sie beim Start der Anwendung erstellt werden können.

//---
   if(!CreateIconButton(m_add_signal,"Add Signal",10,30))
      return(false);
   if(!CreateLabel(m_signal_header,10,30+30+10,"Signal List"))
      return(false);   

Um nun ihre Anzeige beim Start, d.h. im ersten Schritt, unmittelbar nach der Erzeugung der Schnittstelle durch den Aufruf von CreateGUI() zu deaktivieren, fügen wir zwei Zeilen hinzu, die die Elemente vom Ende der Methode verbergen.

//+------------------------------------------------------------------+
//| Creates the graphical interface of the program                   |
//+------------------------------------------------------------------+
bool CProgram::CreateGUI(void)
{
//--- Step 1-3
   if(!CreateStepWindow("Signal Monitor Step 1: Choose Symbols"))
      return(false);
//--- Finish the creation of GUI
   CWndEvents::CompletedGUI();
   m_back_button.Hide();
   m_add_signal.Hide();
   m_signal_header.Hide();
   return(true);
}

Implementieren wir nun die zuvor hinzugefügte Methode ToStep_3(), die die Visualisierung im vorherigen Schritt löscht und die von uns erstellten Elemente anzeigt:

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CProgram::ToStep_3(void)
{
//--- Check whether at least one timeframe is selected
   int cnt=0;
   for(int i=0; i<21; i++)
   {
      if(m_checkbox[i].IsPressed())
         cnt++;
   }
   if(cnt<1)
   {
      MessageBox("No timeframes selected!","Warning");
      return;
   }
//---
   m_step_window.LabelText("Signal Monitor Step 3: Create Signals");
   m_step_window.Update(true);
   m_next_button.LabelText("Create");
   m_next_button.Update(true);
//--- Hide elements of Step 2
   for(int i=0; i<21; i++)
   {
      if(i<3)
         m_currency_set[i].Hide();
      m_checkbox[i].Hide();
   }
//---
   m_add_signal.Show();
   m_signal_header.Show();
//---
   m_current_step=3;
}

Kompilieren wir das Projekt erneut und gehen durch einen Doppelklick auf die Schaltfläche Next zu Schritt 3. Vergessen wir nicht, in den ersten beiden Schritten Elemente auszuwählen, sonst lässt uns die Anwendung nicht zum dritten Schritt übergehen.

Abb.8 Implementierung von Schritt 3 der Anwendung.

Fenster zur Erstellung und Bearbeitung von Handelssignalen

Die visuelle Komponente, die mit der Arbeit mit Handelssignalen zusammenhängt, befindet sich in der Datei SetWindow.mqh, also öffnen wir sie. Jetzt hat sie nur noch die Include-Datei Program.mqh, die über #include eingebunden ist. Erstellen wir zunächst ein separates Fenster, das für alle anderen Erstellungs- und Einrichtungselemente grundlegend sein wird. Öffnen wir Programm.mqh und deklarieren in der Klasse die Variable m_set_window, die eine Instanz der Klasse CWindow ist. Fügen wir auch die Methode CreateSetWindow() zur Erzeugung des Fensters hinzu:

   CWindow           m_set_window;

   bool              CreateSetWindow(const string caption_text);

Danach gehen wir zurück zu SetWindow.mqh und implementieren die erstellte Methode.

//+------------------------------------------------------------------+
//| Creates a window for creating and editing trading signals        |
//+------------------------------------------------------------------+
bool CProgram::CreateSetWindow(const string text)
{
//--- Add the pointer to the window array
   CWndContainer::AddWindow(m_set_window);
//--- Properties
   m_set_window.XSize(568);
   m_set_window.YSize(555);
//--- Coordinates
   int x=int(ChartGetInteger(m_chart_id,CHART_WIDTH_IN_PIXELS)-m_set_window.XSize())/2;
   int y=30;
//---
   m_set_window.CaptionHeight(22);
   m_set_window.IsMovable(true);
   m_set_window.CaptionColor(m_caption);
   m_set_window.CaptionColorLocked(m_caption);
   m_set_window.CaptionColorHover(m_caption);
   m_set_window.BackColor(m_background);
   m_set_window.FontSize(m_base_font_size);
   m_set_window.Font(m_base_font);
   m_set_window.WindowType(W_DIALOG);
//--- Creating a form
   if(!m_set_window.CreateWindow(m_chart_id,m_subwin,text,x,y))
      return(false);
   return(true);
}
//+------------------------------------------------------------------+

Binden wir nun das neu erstellte Fenster mit bereits verfügbaren Elementen. Zuerst fügen wir den Methodenaufruf im Menü für das Erstellen des Interfaces CreateGUI() hinzu. Das Fenster sollte sich bei einem Klick auf die Schaltfläche "Add Signal" in Schritt 3 öffnen.

//+------------------------------------------------------------------+
//| Creates the graphical interface of the program                   |
//+------------------------------------------------------------------+
bool CProgram::CreateGUI(void)
{
//--- Step 1-3
   if(!CreateStepWindow("Signal Monitor Step 1: Choose Symbols"))
      return(false);
//--- Creation and editing window
   if(!CreateSetWindow("Signal Monitor Edit Signal"))
      return(false);
//--- Finish the creation of GUI
   CWndEvents::CompletedGUI();
   m_back_button.Hide();
   m_add_signal.Hide();
   m_signal_header.Hide();
   return(true);
}

Beim Klick-Ereignis in OnEvent():

      //--- Click on the "Add Signal" button
      if(lparam==m_add_signal.Id())
      {
         m_set_window.OpenWindow();
      }

Kompilieren wir das Projekt und überprüfen das Ergebnis: Bei einem Klick auf "Add Signal" in Schritt 3 wird ein zusätzliches Erstellungs- und Bearbeitungsfenster geöffnet.

Abb. 9 Implementierung des Fensters zur Erstellung und Bearbeitung von Handelssignalen.

Das erste Fensterelement ist die Auswahl des Indikatortyps, der bei der Erzeugung eines Handelssignals verwendet werden soll. Das Verfahren zum Hinzufügen von Elementen ist das gleiche: Wir erstellen eine Klasseninstanz und eine Methode zur Implementierung der Instanz.

   //--- Drop-down menu
   CComboBox         m_indicator_type;
   //--- Creates a drop-down method
   bool              CreateIndicatorType(const int x_gap,const int y_gap);

Die Methodenimplementierung befindet sich in derselben Datei, in der auch das zuvor erstellte Fenster erstellt wird. 

//+------------------------------------------------------------------+
//| Creates a drop-down menu with indicator types                    |
//+------------------------------------------------------------------+
bool CProgram::CreateIndicatorType(const int x_gap,const int y_gap)
{
//--- Pass the object to the panel
   m_indicator_type.MainPointer(m_set_window);
//--- Array of the item values in the list view
   string pattern_names[7]=
   {
      "ATR","CCI","DeMarker","Force Ind","WPR","RSI","Momentum"
   };
//--- Set properties before creation
   m_indicator_type.XSize(200);
   m_indicator_type.YSize(26);
   m_indicator_type.LabelYGap(4);
   m_indicator_type.ItemsTotal(7);
   m_indicator_type.Font(m_base_font);
   m_indicator_type.FontSize(m_base_font_size);
   m_indicator_type.BackColor(m_background);
   m_indicator_type.GetButtonPointer().Font(m_base_font);
   m_indicator_type.GetButtonPointer().FontSize(m_base_font_size);
   m_indicator_type.GetButtonPointer().BackColor(clrWhite);
   m_indicator_type.GetButtonPointer().XGap(100);
   m_indicator_type.GetButtonPointer().XSize(100);
   m_indicator_type.GetListViewPointer().Font(m_base_font);
   m_indicator_type.GetListViewPointer().FontSize(m_base_font_size);
   m_indicator_type.GetListViewPointer().ItemYSize(26);
//--- Store the item values in the combo box list view
   for(int i=0; i<7; i++)
      m_indicator_type.SetValue(i,pattern_names[i]);
//--- Get the list pointer
   CListView *lv=m_indicator_type.GetListViewPointer();
//--- Set the list view properties
   lv.LightsHover(true);
   m_indicator_type.SelectItem(5);
//--- Create a control
   if(!m_indicator_type.CreateComboBox("Indicator Type",x_gap,y_gap))
      return(false);
//--- Add an object to the common array of object groups
   CWndContainer::AddToElementsArray(1,m_indicator_type);
   return(true);
}

Der einzige Zusatz hier ist, dass wir am Ende der Methode CreateSetWindow() eine Methode zum Anlegen der Auswahlmöglichkeit für den Indikatortyp CreateIndicatorType() aufrufen.

...
//--- Creating a form
   if(!m_set_window.CreateWindow(m_chart_id,m_subwin,text,x,y))
      return(false);
//--- Indicator type
   if(!CreateIndicatorType(10,22+10))
      return(false);

Das Ergebnis ist das UI-Element, das die Auswahl aus 7 Standardindikatoren des Oszillatortyps ermöglicht.

Abb. 10 Element zur Auswahl des Indikatortyps.

Betrachten wir als Nächstes Gruppen von Elementen, die in zwei Abschnitten gruppiert sind: Indikatoreinstellungen und Signaleinstellungen. Alle ausgewählten Indikatoren aus dem Standardsatz haben gemeinsame Einstellungen, wie z.B. Periode und Angewandter Preis. Daher wird für den ersten Abschnitt Folgendes benötigt: eine Textkennzeichnung, ein Periodeneingabefeld und ein Dropdown-Menü zur Auswahl des für die Indikatorberechnung verwendeten Preises. Fügen wir die erforderliche Variable und ihre Erstellungsmethoden der Klasse Programm hinzu.

//--- Text label
   CTextLabel        m_set_header[5];
//--- Input fields
   CTextEdit         m_period_edit;
//--- Drop-down menu
   CComboBox         m_applied_price;
...
   bool              CreateSetLabel(CTextLabel &text_label,const int x_gap,const int y_gap,string label_text);
   bool              CreatePeriodEdit(const int x_gap,const int y_gap);
   bool              CreateAppliedPrice(const int x_gap,const int y_gap);

Implementieren wir die hinzugefügten Methoden und rufen sie am Ende des Methodenrumpfes CreateSetWindow() auf. Fügen wir nun einen Mechanismus hinzu, durch den die erstellten Elemente den Satz der verfügbaren Einstellungen in Abhängigkeit vom gewählten Indikatortyp ändern. Fügen wir dazu in OnEvent() einen Abschnitt mit einem Ereignis des Anklickens des Dropdown-Menüpunkts hinzu und stellen den individuellen Satz von Einstellungen für jeden der Indikatoren ein:

//--- Item selection in the combobox list
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_COMBOBOX_ITEM)
   {
      int index=m_indicator_type.GetListViewPointer().SelectedItemIndex();
      switch(index)
      {
      case  0:
         m_period_edit.LabelText("ATR Period");
         m_applied_price.Hide();
         break;
      case  1:
         m_period_edit.LabelText("CCI Period");
         m_applied_price.Show();
         break;
      case  2:
         m_period_edit.LabelText("DeMarker Period");
         m_applied_price.Hide();
         break;
      case  3:
         m_period_edit.LabelText("Force Index Period");
         m_applied_price.Show();
         break;
      case  4:
         m_period_edit.LabelText("WPR Period");
         m_applied_price.Hide();
         break;
      case  5:
         m_period_edit.LabelText("RSI Period");
         m_applied_price.Show();
         break;
      case  6:
         m_period_edit.LabelText("Momentum Period");
         m_applied_price.Hide();
         break;
      default:
         m_period_edit.LabelText("RSI Period");
         m_applied_price.Hide();
         break;
      }
      m_period_edit.Update(true);
   }

Kompilieren wir das Projekt und sehen uns das Ergebnis an:

Abb. 11 Implementierung der Indikatoreneinstellungen.

Als Nächstes gehen wir zum zweiten Abschnitt der Signalbearbeitung über. Er besteht aus der Kopfzeile und acht Einstellungen:

  • Signalregel.
  • Textwert des Labels im Signalblock.
  • Farbe des Textlabels.
  • Hintergrundverwendung und -farbe.
  • Kantenverwendung und -farbe.
  • Verwendung, Farbe und Wert eines Tooltips über dem Signalblock.
  • Die Verwendung von Grafik-Labels und deren Darstellung im Signalblock.
  • Auswahl der verfügbaren Zeitrahmen für die Suche nach einem bestimmten Signal.

Um eine Kopfzeile für diesen Abschnitt hinzuzufügen, fügen wir den folgenden Code am Ende des Körpers CreateSetWindow() ein (wir haben zuvor eine Methode zur Visualisierung der Kopfzeile erstellt, die mit verschiedenen Argumentwerten wieder verwendet werden kann):

//--- Signal settings
   if(!CreateSetLabel(m_set_header[1],10,22+10+4*(25+10),"2.Signal Settings"))
      return(false);

Die Signalregel besteht aus zwei Elementen: einem Dropdown-Menü und einem Eingabefeld für einen numerischen Wert. Fügen wir die Klasseninstanzen und Implementierungsmethoden der Klasse CProgramm hinzu:

CTextEdit         m_rule_value;
CComboBox         m_rule_type;
...
bool              CreateRuleValue(const int x_gap,const int y_gap);
bool              CreateRule(const int x_gap,const int y_gap);

Fügen wir ihre Implementierung zu SetWindow.mqh hinzu und rufen sie in der Methode CreateSetWindow() auf.

   //--- Condition settings
   if(!CreateRuleValue(130,22+10+5*(25+10)))
      return(false);
   if(!CreateRule(10,22+10+5*(25+10)))
      return(false);

Fügen wir jede der Einstellungen auf die gleiche Weise hinzu. So sieht die vollständige Implementierung der Methode CreateSetWindow () aus:

//+------------------------------------------------------------------+
//| Creates a window for creating and editing trading signals        |
//+------------------------------------------------------------------+
bool CProgram::CreateSetWindow(const string text)
{
//--- Add the pointer to the window array
   CWndContainer::AddWindow(m_set_window);
//--- Properties
   m_set_window.XSize(568);
   m_set_window.YSize(575);
//--- Coordinates
   int x=int(ChartGetInteger(m_chart_id,CHART_WIDTH_IN_PIXELS)-m_set_window.XSize())/2;
   int y=30;
//---
   m_set_window.CaptionHeight(22);
   m_set_window.IsMovable(true);
   m_set_window.CaptionColor(m_caption);
   m_set_window.CaptionColorLocked(m_caption);
   m_set_window.CaptionColorHover(m_caption);
   m_set_window.BackColor(m_background);
   m_set_window.FontSize(m_base_font_size);
   m_set_window.Font(m_base_font);
   m_set_window.WindowType(W_DIALOG);
//--- Creating a form
   if(!m_set_window.CreateWindow(m_chart_id,m_subwin,text,x,y))
      return(false);
//--- Indicator type
   if(!CreateIndicatorType(10,22+10))
      return(false);
//--- Settings of the selected indicator
   if(!CreateSetLabel(m_set_header[0],10,22+10+26+10,"1.Indicator Settings"))
      return(false);
   if(!CreatePeriodEdit(10,22+10+2*(25+10)))
      return(false);
   if(!CreateAppliedPrice(10,22+10+3*(25+10)))
      return(false);
//--- Signal settings
   if(!CreateSetLabel(m_set_header[1],10,22+10+4*(25+10),"2.Signal Settings"))
      return(false);
//--- Condition settings
   if(!CreateRuleValue(130,22+10+5*(25+10)))
      return(false);
   if(!CreateRule(10,22+10+5*(25+10)))
      return(false);
//--- Label display settings
   if(!CreateSetLabel(m_set_header[2],10,22+10+6*(25+10),"Label"))
      return(false);
   if(!CreateButton2(m_label_button[0],"Value",100,22+7+6*(25+10)))
      return(false);
   if(!CreateButton2(m_label_button[1],"Text",100+80,22+7+6*(25+10)))
      return(false);
//--- Label color display settings
   if(!CreateColorButton(m_color_button[0],10,22+10+7*(25+10),"Label Color"))
      return(false);
   if(!CreateTextBox(180+80+10,22+7+6*(25+10)))
      return(false);
//---
   if(!CreateColorButton(m_color_button[1],25,22+10+8*(25+10),""))
      return(false);
   if(!CreateSetCheckBox(m_set_param[0],10,22+10+8*(25+10),"Use Background"))
      return(false);
   if(!CreateColorButton(m_color_button[2],25,22+10+9*(25+10),""))
      return(false);
   if(!CreateSetCheckBox(m_set_param[1],10,22+10+9*(25+10),"Use Border"))
      return(false);
   if(!CreateColorButton(m_color_button[3],25,22+10+10*(25+10),""))
      return(false);
   if(!CreateSetCheckBox(m_set_param[2],10,22+10+10*(25+10),"Use Tooltip"))
      return(false);
   if(!CreateTooltipText(240,22+10+10*(25+10)))
      return(false);
   if(!CreateSetCheckBox(m_set_param[3],10,22+10+11*(25+10),"Use Image"))
      return(false);
   if(!CreateImageSlider(125,22+10+11*(25+10)))
      return(false);
//--- Timeframe selection
   if(!CreateSetLabel(m_set_header[4],10,22+10+12*(25+10),"Timeframes"))
      return(false);
//---
   y=22+10+13*(25+10);
   int k=0;
   for(int i=0; i<21; i++)
   {
      if(i==11)
      {
         y=22+20+14*(25+10);
         k=0;
      }
      if(!CreateTfButton(m_tf_button[i],40*k+10,y))
         return(false);
      k++;
   }
   return(true);
}

Die vollständige Liste der Ergänzungen und ihrer Umsetzung ist in den Anhängen unten zu finden. Nachdem alle erforderlichen Teile hinzugefügt wurden, sieht das Erstellungs- und Bearbeitungsfenster wie folgt aus:

Abb. 12 Implementierung von UI-Elementen des Signalbearbeitungsfensters.

Wie Sie in der Abbildung sehen können, sind die Schaltflächen zur Auswahl des Zeitrahmens leer. Wir müssen auch die grundlegenden Interaktionen der Elemente konfigurieren:

  • Die Schaltflächen für den Zeitrahmen sollten nur die in Schritt 2 ausgewählte Zahl anzeigen.
  • Wenn die Schaltfläche für den Wert ausgewählt ist, sollte die Schaltfläche für Text Text nicht gedrückt sein und das Eingabefeld für die Textbeschriftung sollte ausgeblendet sein.
  • Ein Klick auf die Farbauswahl-Schaltfläche sollte ein Fenster mit der Farbpalette öffnen.
  • Wenn sie nicht angekreuzt ist, sollten die Palettenauswahl, das Tooltip-Eingabefeld und die Auswahl der grafischen Beschriftung inaktiv werden.

Um die Ausgabe von ausgewählten Zeitrahmen zu implementieren, lassen Sie uns die Methode RebulidTimeframes() im 'private' Bereich der Basisklasse erstellen und diese Methode implementieren:

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CProgram::RebuildTimeframes(void)
{
//--- Count the number of selected timeframes
   int cnt=0;
   for(int i=0; i<21; i++)
   {
      if(m_checkbox[i].IsPressed())
         cnt++;
   }
   ArrayResize(m_timeframes,cnt);
   cnt=0;
//--- Remember the selected timeframe to the array
   for(int i=0; i<21; i++)
   {
      if(m_checkbox[i].IsPressed())
      {
         m_timeframes[cnt]=m_checkbox[i].LabelText();
         cnt++;
      }
   }
//---
   for(int i=0; i<cnt; i++)
      m_tf_button[i].IsLocked(false);
//---
   for(int i=0; i<cnt; i++)
   {
      m_tf_button[i].LabelText(m_timeframes[i]);
      m_tf_button[i].Update(true);
   }
   //---
   for(int i=cnt; i<21; i++)
      m_tf_button[i].IsLocked(true);
}

Fügen wir nun Folgendes zum Code hinzu, der das Bearbeitungsfenster aufruft, wenn jemand auf Add Signal (Signal hinzufügen) klickt.

      //--- Click on the "Add Signal" button
      if(lparam==m_add_signal.Id())
      {
         m_set_window.OpenWindow();
         if(m_set_window.IsAvailable())
            RebuildTimeframes();
      }

Kommen wir zum nächsten Moment, der mit der Einrichtung der Interaktion der Schaltflächen Wert und Text zu tun hat. Fügen wir folgenden Code OnEvent() hinzu:

//---
      if(lparam==m_label_button[0].Id())
      {
         if(m_label_button[0].IsPressed())
         {
            m_label_button[1].IsPressed(false);
            m_label_button[1].Update(true);
         }
         m_text_box.Hide();
      }
      if(lparam==m_label_button[1].Id())
      {
         if(m_label_button[1].IsPressed())
         {
            m_label_button[0].IsPressed(false);
            m_label_button[0].Update(true);
         }
         m_text_box.Show();
      }

Folgende Bedingung ist hier erfüllt: Wenn eine der Tasten gedrückt ist, sollte die andere nicht gedrückt sein. Wenn die Taste Text nicht gedrückt ist, soll das Bearbeitungsfeld ausgeblendet werden. Klicks auf die Schaltflächen für die Farbpaletten sind hier ebenfalls implementiert. Wir haben vier Schaltflächen, ein Array mit vier Elementen wurde deklariert, daher kann der Zugriff auf diese in einer Schleife geschrieben werden.

      //---
      for(int i=0; i<4; i++)
      {
         if(lparam==m_color_button[i].Id())
         {
            m_color_picker.ColorButtonPointer(m_color_button[i]);
            return;
         }
      }

Und die letzte Interaktion besteht darin, Elemente zu blockieren, wenn die Kontrollkästchen nicht gedrückt sind. Fügen wir die Kontrolle der Klicks der Checkboxen OnEvent() hinzu und implementieren die Interaktionen.

//--- Click on the checkbox
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_CHECKBOX)
   {
      //---
      for(int i=0; i<3; i++)
      {
         if(lparam==m_set_param[i].Id())
         {
            m_color_button[i+1].IsLocked(!m_set_param[i].IsPressed());
            if(m_set_param[2].IsPressed())
               m_tooltip_text.Show();
            else
               m_tooltip_text.Hide();
         }
      }
      //---
      if(lparam==m_set_param[3].Id())
         m_pictures_slider.IsLocked(!m_set_param[3].IsPressed());
   }

Kompilieren wir das Projekt erneut und sehen uns das Ergebnis an.

Abb. 13 Implementierungen der Interaktion von UI-Elementen des Signalbearbeitungsfensters.


Monitor der Handelssignale

Der letzte Schritt innerhalb dieser Entwicklungsphase ist die Schaffung eines Fensters für die Überwachung zukünftiger Handelssignale. Dabei sollten wir auch jene Grundeinstellungen berücksichtigen, die in der aktuellen Version bereits implementiert sind. Vor dem Erstellen sollten wir einige Aufgaben festlegen, damit der Leser versteht, zu welchem Zweck die Elemente erstellt werden:

  • Erstellen wir die Zeilen mit Textbeschriftungen der im ersten Schritt ausgewählten Signale.
  • Erstellen wir Überschriftsspalten mit Textbeschriftungen von Zeitrahmen, die im zweiten Schritt ausgewählt wurden.
  • Ändern wir die Größe des Fensters in Übereinstimmung mit den Zeilen und Spalten der erstellten Elemente. Eine Art automatische Größenanpassung.

Um die Erstellung der Text-Labels von Zeitrahmen und Symbolen zu ermöglichen, erstellen wir zwei Arrays mit den Klasseninstanzen CTextLabel und fügen zwei Implementierungsmethoden in der Klasse CProgramm hinzu.

   CTextLabel        m_timeframe_label[];
   CTextLabel        m_symbol_label[];
   bool              CreateTimeframeLabel(CTextLabel &text_label,const int x_gap,const int y_gap,string label_text);
   bool              CreateSymbolLabel(CTextLabel &text_label,const int x_gap,const int y_gap,string label_text);

Implementieren wir nun die erstellten Methoden in der Datei MainWindow.mqh:

//+------------------------------------------------------------------+
//| Creates the text label                                           |
//+------------------------------------------------------------------+
bool CProgram::CreateTimeframeLabel(CTextLabel &text_label,const int x_gap,const int y_gap,string label_text)
{
//--- Save the window pointer
   text_label.MainPointer(m_step_window);
//---
   text_label.Font(m_base_font);
   text_label.FontSize(m_base_font_size);
   text_label.XSize(40);
   text_label.BackColor(m_background);
//--- Create the button
   if(!text_label.CreateTextLabel(label_text,x_gap,y_gap))
      return(false);
//--- Add a pointer to element to the base
   CWndContainer::AddToElementsArray(0,text_label);
   return(true);
}
//+------------------------------------------------------------------+
//| Creates the text label                                           |
//+------------------------------------------------------------------+
bool CProgram::CreateSymbolLabel(CTextLabel &text_label,const int x_gap,const int y_gap,string label_text)
{
//--- Save the window pointer
   text_label.MainPointer(m_step_window);
//---
   text_label.Font(m_base_font);
   text_label.FontSize(m_base_font_size);
   text_label.XSize(100);
   text_label.BackColor(m_background);
//--- Create the button
   if(!text_label.CreateTextLabel(label_text,x_gap,y_gap))
      return(false);
//--- Add a pointer to element to the base
   CWndContainer::AddToElementsArray(0,text_label);
   return(true);
}

Bevor wir mit der Visualisierung der Fensteroberfläche fortfahren, müssen wir zwei wichtige Variablen im 'private' Bereich sowie zwei Methoden erstellen:

   int               m_total_signals;
   string            m_symbols[];
   void              ToMonitor(void);
   void              AutoResize(const int x_size,const int y_size);

Die Variable m_total_signals wird benötigt, um zu überprüfen, ob mindestens ein Handelssignal erzeugt wurde. Diese Prüfung wird vor der Erstellung des Monitorfensters durchgeführt. Das Array m_symbols[] enthält eine Auswahl von Symbolen aus dem ersten Einrichtungsschritt. Die Methode ToMonitor() implementiert die Erstellung der Monitorschnittstelle, während AutoResize() die Fenstergröße entsprechend den erstellten Elementen anpasst. Hier ist die Implementierung der deklarierten Methoden:

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CProgram::ToMonitor(void)
{
//--- Check if there is at least one signal
   if(m_total_signals<1)
   {
      MessageBox("No signals created!","Warning");
      return;
   }
//--- Hide Step 3
   m_add_signal.Hide();
   m_signal_header.Hide();
   m_back_button.Hide();
   m_next_button.Hide();
//--- Change window header
   m_step_window.LabelText("Signal Monitor");
   m_step_window.Update(true);
//--- Symbols
   int sy=ArraySize(m_symbols);
   ArrayResize(m_symbol_label,sy);
   for(int i=0; i<sy; i++)
   {
      if(!CreateSymbolLabel(m_symbol_label[i],5,m_step_window.CaptionHeight()+25+i*25,m_symbols[i]))
         return;
      m_symbol_label[i].Update(true);
   }
//--- Timeframes
   int tf=ArraySize(m_timeframes);
   ArrayResize(m_timeframe_label,tf);
//---
   for(int i=0; i<tf; i++)
   {
      if(!CreateTimeframeLabel(m_timeframe_label[i],110+50*i,m_step_window.CaptionHeight()+3,m_timeframes[i]))
         return;
      m_timeframe_label[i].Update(true);
   }
//--- Resize window
   AutoResize(m_timeframe_label[tf-1].XGap()+m_timeframe_label[tf-1].XSize()+5,m_symbol_label[sy-1].YGap()+m_symbol_label[sy-1].YSize()+5);
}

Wie aus dem obigen Code ersichtlich ist, werden im Abschnitt Symbole Daten aus m_symbols verwendet. Diese Daten werden jedoch nicht gesammelt oder aufbereitet. Lassen Sie uns das beheben. Gehen wir zur Methode ToStep_2() und nachdem wir überprüft haben, ob mindestens ein Symbol ausgewählt wurde, merken wir uns die im ersten Schritt ausgewählten Symbole in unserem Array:

//--- Count the number of selected symbols
   ArrayResize(m_symbols,cnt);
   cnt=0;
//--- Remember the selected timeframe to the array
   for(int i=0; i<m_all_symbols; i++)
   {
      if(m_checkbox[i].IsPressed())
      {
         m_symbols[cnt]=m_checkbox[i].LabelText();
         cnt++;
      }
   }

Erstellen Sie nun die Methode zur automatischen Größenanpassung. 

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CProgram::AutoResize(const int x_size,const int y_size)
{
   m_step_window.ChangeWindowWidth(x_size);
   m_step_window.ChangeWindowHeight(y_size);
}

Bevor wir das Projekt überprüfen, setzen wir die Variable m_total_signals im Konstruktor von CProgramm auf Null. Ein weiterer wichtiger Punkt ist das Hinzufügen zur Methode OnEvent(), im Klick-Ereignis der Schaltfläche. 

      //--- Navigation
      if(lparam==m_back_button.Id())
      {
         //--- Go back
         if(m_current_step==2)
            ToStep_1();
         //--- Return to Step 2
         else if(m_current_step==3)
            ToStep_2();
      }
      //--- Go forward
      if(lparam==m_next_button.Id())
      {
         //--- Go to Step 2
         if(m_current_step==1)
            ToStep_2();
         //--- Go to Step 3
         else if(m_current_step==2)
            ToStep_3();
         //--- Go to Monitor
         else if(m_current_step==3)
            ToMonitor();
      }

Fügen wir hier den Aufruf der erstellten Methode ToMonitor() bei einem Klick auf die Schaltfläche hinzu, die zum nächsten Schritt springt. Diese Schaltfläche wird in Schritt 3 "Create" genannt. Kompilieren wir nun das Projekt und starten die Anwendung:

  • Wählen wir im ersten Schritt die Crosses aus.
  • Im zweiten Schritt wählen Sie Senior.
  • Klicken wir im dritten Schritt auf Add Signal. 
  • Schließen Sie danach das Fenster zur Signalerzeugung und klicken Sie auf Create.

Abb. 14 Grundlegende Monitoreinstellung

Im nächsten Artikel werden wir uns mit der Implementierung eines Algorithmus befassen, der die konfigurierten Handelssignale unter den Arbeitsbedingungen sucht, die während der anfänglichen Einführung geschaffen wurden.

Schlussfolgerung

Das angehängte Archiv enthält alle besprochenen Dateien, die sich in den entsprechenden Ordnern befinden. Für den ordnungsgemäßen Betrieb müssen Sie lediglich den Ordner MQL5 in den Terminalverzeichnis speichern. Um das Stammverzeichnis des Terminals zu öffnen, in dem sich der Ordner MQL5 befindet, drücken wir die Tastenkombination Strg+Umschalt+D im Terminal MetaTrader 5 oder verwenden das Kontextmenü wie in Abb. 15 unten dargestellt.


Abb. 15. Öffnen des Ordners MQL5 im Stammordner von MetaTrader 5

Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/7528

Beigefügte Dateien |
MQL5.zip (1626.37 KB)
Zeitreihen in der Bibliothek DoEasy (Teil 35): das Bar-Objekt und die Liste der Zeitreihen eines Symbols Zeitreihen in der Bibliothek DoEasy (Teil 35): das Bar-Objekt und die Liste der Zeitreihen eines Symbols
Dieser Artikel startet eine neue Serie über das Erstellen der Bibliothek DoEasy zur einfachen und schnellen Programmentwicklung. Im aktuellen Artikel werden wir die Bibliotheksfunktionen für den Zugriff auf und die Arbeit mit den Zeitreihen der Symbole implementieren. Wir werden das Bar-Objekt erstellen, das die Haupt- und erweiterten Zeitreihendaten speichert, und Bar-Objekte in der Zeitreihenliste platzieren, um eine bequeme Suche und Sortierung der Objekte zu ermöglichen.
Verwendung von Netzwerkfunktionen oder MySQL ohne DLL: Teil II - Programm zur Überwachung von Änderungen der Signaleigenschaften Verwendung von Netzwerkfunktionen oder MySQL ohne DLL: Teil II - Programm zur Überwachung von Änderungen der Signaleigenschaften
Im vorherigen Teil haben wir die Implementierung des MySQL-Konnektors besprochen. In diesem Artikel wenden wir uns seiner Anwendung durch die Implementierung eines Dienstes zum Sammeln von Signaleigenschaften und des Programms zum Anzeigen ihrer Änderungen im Laufe der Zeit. Das implementierte Beispiel ist praktisch sinnvoll, wenn Nutzer Änderungen an Eigenschaften beobachten müssen, die auf der Webseite des Signals nicht angezeigt werden.
Prognose von Zeitreihen (Teil 1): Methode der Empirischen Modus Dekomposition (Empirical Mode Decomposition, EMD) Prognose von Zeitreihen (Teil 1): Methode der Empirischen Modus Dekomposition (Empirical Mode Decomposition, EMD)
Dieser Artikel befasst sich mit der Theorie und der praktischen Anwendung des Algorithmus zur Vorhersage von Zeitreihen, basierend auf der empirischen Moduszerlegung. Er schlägt die MQL-Implementierung dieser Methode vor und stellt Testindikatoren und Expert Advisors vor.
Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil XXXIII): Schwebende Handelsanfragen - Entfernen und Ändern von Orders und Positionen unter bestimmten Bedingungen Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil XXXIII): Schwebende Handelsanfragen - Entfernen und Ändern von Orders und Positionen unter bestimmten Bedingungen
In diesem Artikel werden wir die Beschreibung des Konzepts des Handels mit schwebenden Anfragen vervollständigen und die Funktionen zum Entfernen von Pending-Orders sowie zur Änderung von Orders und Positionen unter bestimmten Bedingungen schaffen. Auf diese Weise werden wir über die gesamte Funktionalität verfügen, die es uns ermöglicht, einfache benutzerdefinierte Strategien bzw. EA-Verhaltenslogiken zu entwickeln, die unter benutzerdefinierten Bedingungen aktiviert werden.