Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil XVI): Ereignisse der Kollektionssymbole

6 November 2019, 11:25
Artyom Trishkin
0
229

Inhalt

Beim Erstellen des Kontoobjekts und der Kollektion der Konten im Teil 12 sowie bei der Verfolgung der aktuellen Kontoereignisse im Teil 13 der Bibliotheksbeschreibung haben wir die Notwendigkeit festgestellt, eine neue Art von Objekten zu erstellen, die ihre Ereignisse an das Objekt Engine senden.


Die Prinzipien der Verfolgung von Kontoereignissen unterscheiden sich von denen, die bei der Verfolgung von Handelsgeschäften angewendet werden wir haben begonnen, im Artikel 4 und später zu berücksichtigen. Handelsereignisse werden definiert und an die Kollektion von Handelsereignissen für einen vollständigen Zugriff auf eines der zuvor aufgetretenen Ereignisse gesendet, während Kontoereignisse einfach in Echtzeit funktionieren — "hier und jetzt": Das Ereignis wird definiert und von EventChartCustom() mit einem Programm an das Chart gesendet, bevor es an das Basisobjekt der Bibliothek gesendet wird. Danach können Sie aus dem Basisobjekt der Bibliothek auf die Liste der gleichzeitig aufgetretenen Ereignisse zugreifen und diese in Ihrem Programm behandeln. Auf diese Weise werden Ereignisse am Kontoobjekt angeordnet.

Ereignisse in des Objekts der Kollektionssymbole sind gleich anzuordnen. Der Unterschied besteht nur in der Menge — wir verfolgen Kontoereignisse nur für das Konto, mit dem wir im Moment verbunden sind, aber wir müssen Symbolereignisse für jedes Symbol der Kollektion verfolgen — sei es nur das aktuelle Symbol oder zwei, drei oder alle auf dem Server verfügbaren Symbole.

Hier kommen wir zu dem Schluss, dass fast jedes Objekt mit einer bestimmten Anzahl von Eigenschaften ausgestattet ist, die sich von einem Objekt zum anderen wiederholen, und wir setzen jede dieser Eigenschaften immer wieder in jedem neuen Objekt während seiner Entwicklung.

Dies führt zu einer eindeutigen Entscheidung — wir sollten ein Basisobjekt anlegen, von dem alle Bibliotheksobjekte geerbt werden sollen. Derzeit werden sie aus dem CObject Basisobjekt der Standardbibliothek vererbt. Wir werden noch ein weiteres Objekt erstellen, das von CObject abgeleitet ist, und alle Objekte unserer Bibliothek davon erben. Somit können alle Eigenschaften, die für jedes der Objekte gemeinsam sind, einmal im Basisobjekt eingestellt werden. Alle nachfolgenden Objekte werden automatisch mit diesen Eigenschaften ausgestattet.

Interessanterweise können wir nun ein Ereignisobjekt erstellen und in das Basisobjekt schreiben, während alle Bibliotheksobjekte ihre Ereignisse an das Programm senden können. Genau das ist es, was wir im Bibliothekskonzept brauchen — die Objekte sollen das Programm selbst über ihren Status informieren können, während die Bibliothek oder das Programm die entsprechenden Nachrichten aus den Objekten verarbeiten und entscheiden (Programm) oder Objektereignisse behandeln (Bibliothek) soll. Dies erhöht die Interaktivität der Bibliothek und vereinfacht die Entwicklung von Programmen durch den Endbenutzer erheblich, da die Bibliothek alle Aktionen zur Behandlung von Objektereignissen übernimmt.

Die Objekt-Ereignisstruktur besteht darin, Daten zu wiederholen, die für das Senden von Ereignis-ID, long-, double- und string-Parameter durch die Funktion EventChartCustom() erforderlich sind. Dies vereinfacht das Senden von Ereignissen an das Programm, da alle an das Programm zu sendenden Ereignisdaten sofort in der Klasse des Objekts gefüllt werden, in dem das Ereignis bei der Ereignisregistrierung aufgetreten ist. Wir müssen es nur beschaffen und zur weiteren Bearbeitung an das Programm weiterleiten.

Beginnen wir mit der Entwicklung. Zuerst werden wir das Ereignisobjekt erstellen, gefolgt vom Basisobjekt. Danach werden wir die Verfolgung der Ereignisse von Kollektionssymbolen implementieren und Anpassungen vornehmen, wobei wir das Konzept der Klasse der Kontoereignisse im Auge behalten. Die Handelsereignisse bleiben intakt, da ihre Struktur völlig anders ist und dem Konzept widerspricht. Außerdem sind sie bereits vollständig und senden ihre Daten an das Programm.

Basisobjektklasse für alle Bibliotheksobjekte

Erstellen Sie im Bibliotheksordner \MQL5\Include\DoEasy\Objects\ die neue Klasse CBaseObj in der Datei BaseObj.mqh. Die Basisklasse der Standardbibliothek CObject ist als Basisobjekt der Klasse zu verwenden. Die Klasse ist ziemlich klein, also werde ich hier ihre vollständige Liste anzeigen. Dann werden wir es nach seinen Mitgliedern und Methoden analysieren.

Um zu vermeiden, dass eine neue Datei für die Ereignisklasse Objekt erstellt wird, schreiben Sie diese Klasse vor die Basisklasse in dieselbe Datei:
//+------------------------------------------------------------------+
//|                                                      BaseObj.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/de/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/de/users/artmedia70"
#property version   "1.00"
#property strict    // Notwendig für mql4
//+------------------------------------------------------------------+
//| Include-Dateien                                                  |
//+------------------------------------------------------------------+
#include <Arrays\ArrayObj.mqh>
#include "..\Services\DELib.mqh"
//+------------------------------------------------------------------+
//| Base object event class for all library objects                  |
//+------------------------------------------------------------------+
class CEventBaseObj : public CObject
  {
private:
   long              m_time;
   long              m_chart_id;
   ushort            m_event_id;
   long              m_lparam;
   double            m_dparam;
   string            m_sparam;
public:
   void              Time(const long time)               { this.m_time=time;           }
   long              Time(void)                    const { return this.m_time;         }
   void              ChartID(const long chart_id)        { this.m_chart_id=chart_id;   }
   long              ChartID(void)                 const { return this.m_chart_id;     }
   void              ID(const ushort id)                 { this.m_event_id=id;         }
   ushort            ID(void)                      const { return this.m_event_id;     }
   void              LParam(const long lparam)           { this.m_lparam=lparam;       }
   long              LParam(void)                  const { return this.m_lparam;       }
   void              DParam(const double dparam)         { this.m_dparam=dparam;       }
   double            DParam(void)                  const { return this.m_dparam;       }
   void              SParam(const string sparam)         { this.m_sparam=sparam;       }
   string            SParam(void)                  const { return this.m_sparam;       }
public:
//--- Konstructor
                     CEventBaseObj(const ushort event_id,const long lparam,const double dparam,const string sparam) : m_chart_id(::ChartID()) 
                       { 
                        this.m_event_id=event_id;
                        this.m_lparam=lparam;
                        this.m_dparam=dparam;
                        this.m_sparam=sparam;
                       }
//--- Comparison method to search for identical event objects
   virtual int       Compare(const CObject *node,const int mode=0) const 
                       {   
                        const CEventBaseObj *compared=node;
                        return
                          (
                           this.ID()>compared.ID()          ?  1  :
                           this.ID()<compared.ID()          ? -1  :
                           this.LParam()>compared.LParam()  ?  1  :
                           this.LParam()<compared.LParam()  ? -1  :
                           this.DParam()>compared.DParam()  ?  1  :
                           this.DParam()<compared.DParam()  ? -1  :
                           this.SParam()>compared.SParam()  ?  1  :
                           this.SParam()<compared.SParam()  ? -1  :  0
                          );
                       } 
  };
//+------------------------------------------------------------------+
//| Base object class for all library objects                        |
//+------------------------------------------------------------------+
class CBaseObj : public CObject
  {
private:

protected:
   CArrayObj         m_list_events;                            // Object event list
   MqlTick           m_tick;                                   // Tick structure for receiving quote data
   double            m_hash_sum;                               // Object data hash sum
   double            m_hash_sum_prev;                          // Object data hash sum during the previous check
   int               m_digits_currency;                        // Number of decimal places in an account currency
   int               m_global_error;                           // Global error code
   long              m_chart_id;                               // Control program chart ID
   bool              m_is_event;                               // Object event flag
   int               m_event_code;                             // Object event code
   string            m_name;                                   // Object name
   string            m_folder_name;                            // Name of the folder storing CBaseObj descendant objects 

//--- Return time in milliseconds from MqlTick
   long              TickTime(void)                            const { return #ifdef __MQL5__ this.m_tick.time_msc #else this.m_tick.time*1000 #endif ;}
//--- return the flag of the event code presence in the event object
   bool              IsPresentEventFlag(const int change_code) const { return (this.m_event_code & change_code)==change_code; }
//--- Return the number of decimal places of the account currency
   int               DigitsCurrency(void)                      const { return this.m_digits_currency; }
//--- Returns the number of decimal places in the 'double' value
   int               GetDigits(const double value)             const;
//--- Initialize the variables of (1) tracked, (2) controlled object data (implementation in the descendants)
   virtual void      InitChangesParams(void);
   virtual void      InitControlsParams(void);
//--- (1) Check the object change, return the change code, (2) set the event type and fill in the list of events (implementation in the descendants)
   virtual int       SetEventCode(void);
   virtual void      SetTypeEvent(void);
public:
//--- Add the event object to the list
   bool              EventAdd(const ushort event_id,const long lparam,const double dparam,const string sparam);
//--- Return the occurred event flag to the object data
   bool              IsEvent(void)                             const { return this.m_is_event;              }
//--- Return (1) the list of events, (2) the object event code and (3) the global error code
   CArrayObj        *GetListEvents(void)                             { return &this.m_list_events;          }
   int               GetEventCode(void)                        const { return this.m_event_code;            }
   int               GetError(void)                            const { return this.m_global_error;          }
//--- Return the event object by its number in the list
   CEventBaseObj    *GetEvent(const int shift=WRONG_VALUE,const bool check_out=true);
//--- Return the number of object events
   int               GetEventsTotal(void)                      const { return this.m_list_events.Total();   }
//--- (1) Set and (2) return the chart ID of the control program
   void              SetChartID(const long id)                       { this.m_chart_id=id;                  }
   long              GetChartID(void)                          const { return this.m_chart_id;              }
//--- (1) Set the sub-folder name, (2) return the folder name for storing descendant object files
   void              SetSubFolderName(const string name)             { this.m_folder_name=DIRECTORY+name;   }
   string            GetFolderName(void)                       const { return this.m_folder_name;           }
//--- Return the object name
   string            GetName(void)                             const { return this.m_name;                  }
//--- Update the object data (implementation in the descendants)
   virtual void      Refresh(void);
   
//--- Konstructor
                     CBaseObj();
  };
//+------------------------------------------------------------------+
//| Konstruktor                                                      |
//+------------------------------------------------------------------+
CBaseObj::CBaseObj() : m_global_error(ERR_SUCCESS),
                       m_hash_sum(0),m_hash_sum_prev(0),
                       m_is_event(false),m_event_code(0),
                       m_chart_id(::ChartID()),
                       m_folder_name(DIRECTORY),
                       m_name("")
  {
   ::ZeroMemory(this.m_tick);
   this.m_digits_currency=(#ifdef __MQL5__ (int)::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #else 2 #endif);
   this.m_list_events.Clear();
   this.m_list_events.Sort();
  }
//+------------------------------------------------------------------+
//| Add the event object to the list                                 |
//+------------------------------------------------------------------+
bool CBaseObj::EventAdd(const ushort event_id,const long lparam,const double dparam,const string sparam)
  {
   CEventBaseObj *event=new CEventBaseObj(event_id,lparam,dparam,sparam);
   if(event==NULL)
      return false;
   this.m_list_events.Sort();
   if(this.m_list_events.Search(event)>WRONG_VALUE)
     {
      delete event;
      return false;
     }
   return this.m_list_events.Add(event);
  }
//+------------------------------------------------------------------+
//| Return the object event by its index in the list                 |
//+------------------------------------------------------------------+
CEventBaseObj *CBaseObj::GetEvent(const int shift=WRONG_VALUE,const bool check_out=true)
  {
   int total=this.m_list_events.Total();
   if(total==0 || (!check_out && shift>total-1))
      return NULL;   
   int index=(shift<=0 ? total-1 : shift>total-1 ? 0 : total-shift-1);
   CEventBaseObj *event=this.m_list_events.At(index);
   return(event!=NULL ? event : NULL);
  }
//+------------------------------------------------------------------+
//| Return the number of decimal places in the 'double' value        |
//+------------------------------------------------------------------+
int CBaseObj::GetDigits(const double value) const
  {
   string val_str=(string)value;
   int len=::StringLen(val_str);
   int n=len-::StringFind(val_str,".",0)-1;
   if(::StringSubstr(val_str,len-1,1)=="0")
      n--;
   return n;
  }
//+------------------------------------------------------------------+


Lassen Sie uns einen Blick auf das Basisobjekt der Ereignisklasse werfen.

Im 'private' Teil des Basisobjekts der Ereignisklasse werden Klassenvariablen zur Speicherung aller Ereigniseigenschaften deklariert:

private:
   long              m_time;
   long              m_chart_id;
   ushort            m_event_id;
   long              m_lparam;
   double            m_dparam;
   string            m_sparam;

Ereigniszeit, ID des Charts, an den das Ereignis gesendet wird, Ereignis-ID, Ereigniswerte long, double und string, die an das Kontrollprogramm übergeben werden sollen.
Die Werte für die meisten dieser Variablen werden an den Klassenkonstruktor übergeben:

//--- Konstructor
                     CEventBaseObj(const ushort event_id,const long lparam,const double dparam,const string sparam) : m_chart_id(::ChartID()) 
                       { 
                        this.m_event_id=event_id;
                        this.m_lparam=lparam;
                        this.m_dparam=dparam;
                        this.m_sparam=sparam;
                       }


wo ihnen die zugeordneten Werte zugewiesen werden.
Auch in der Klasseninitialisierungsliste erhält die Variable der Chart-ID die aktuelle Chart-ID.

Das Verfahren zum Vergleichen zweier Objektereignisklassen:

//--- Comparison method to search for identical event objects
   virtual int       Compare(const CObject *node,const int mode=0) const 
                       {   
                        const CEventBaseObj *compared=node;
                        return
                          (
                           this.ID()>compared.ID()          ?  1  :
                           this.ID()<compared.ID()          ? -1  :
                           this.LParam()>compared.LParam()  ?  1  :
                           this.LParam()<compared.LParam()  ? -1  :
                           this.DParam()>compared.DParam()  ?  1  :
                           this.DParam()<compared.DParam()  ? -1  :
                           this.SParam()>compared.SParam()  ?  1  :
                           this.SParam()<compared.SParam()  ? -1  :  0  
                          );
                       } 


vergleicht alle Felder zweier Klassen (die aktuelle und diejenige , die über den Zeiger an die Methode übergeben wird) Element für Element. Wenn alle Felder gleich sind, gibt die Methode 0 zurück, was notwendig ist, um eine Suche nach dem gleichen Objekt in der dynamischen Liste der Standardbibliothekszeiger durchzuführen, da diese Objekte in der Liste von CArrayObj gespeichert sind, während ihre Methode Search() für die Suche nach ähnlichen Objekten in der Liste bestimmt ist:

//+------------------------------------------------------------------+
//| Search of position of element in a sorted array                  |
//+------------------------------------------------------------------+
int CArrayObj::Search(const CObject *element) const
  {
   int pos;
//--- check
   if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
      return(-1);
//--- search
   pos=QuickSearch(element);
   if(m_data[pos].Compare(element,m_sort_mode)==0)
      return(pos);
//--- not found
   return(-1);
  }
//+------------------------------------------------------------------+


verlangt die im Objekt vorhandene virtuelle Methode Compare(). Die Methode gibt 0 zurück, falls alle Eigenschaften der beiden Objekte übereinstimmen.

Deklarieren Sie im 'public' Abschnitt der Klasse die Methoden zum Setzen und Zurückgeben aller Objekteigenschaften:

public:
   void              Time(const long time)               { this.m_time=time;           }
   long              Time(void)                    const { return this.m_time;         }
   void              ChartID(const long chart_id)        { this.m_chart_id=chart_id;   }
   long              ChartID(void)                 const { return this.m_chart_id;     }
   void              ID(const ushort id)                 { this.m_event_id=id;         }
   ushort            ID(void)                      const { return this.m_event_id;     }
   void              LParam(const long lparam)           { this.m_lparam=lparam;       }
   long              LParam(void)                  const { return this.m_lparam;       }
   void              DParam(const double dparam)         { this.m_dparam=dparam;       }
   double            DParam(void)                  const { return this.m_dparam;       }
   void              SParam(const string sparam)         { this.m_sparam=sparam;       }
   string            SParam(void)                  const { return this.m_sparam;       }


Hier ist alles klar, und keine Kommentare sind erforderlich. Dies ist eine komplette Objekt-Ereignisklasse.

Betrachten wir die Basisobjektklasse für alle Bibliotheksobjekte.

Die Variablen der Klassenmitglieder, die wir bereits beim Umgang mit den vorherigen Objekten gefunden haben, werden im Abschnitt Geschützte Klasse deklariert:

protected:
   CArrayObj         m_list_events;                            // Object event list
   MqlTick           m_tick;                                   // Tick structure for receiving quote data
   double            m_hash_sum;                               // Object data hash sum
   double            m_hash_sum_prev;                          // Object data hash sum during the previous check
   int               m_digits_currency;                        // Number of decimal places in an account currency
   int               m_global_error;                           // Global error code
   long              m_chart_id;                               // Control program chart ID
   bool              m_is_event;                               // Object event flag
   int               m_event_code;                             // Object event code
   string            m_name;                                   // Object name
   string            m_folder_name;                            // Name of the folder storing CBaseObj descendant objects 


  • Die Liste der Objektereignisse m_list_events soll Objekte der oben betrachteten Ereignisklasse speichern. Das Objekt kann mehrere Ereignisse auf einmal haben, daher müssen wir alle definieren und in die Liste aufnehmen. Dies ermöglicht es uns, die Liste aller Ereignisse aus dem Hauptobjekt der Bibliothek CEngine zu extrahieren und zu bearbeiten.
  • Die Struktur der Ticks m_tick dient der Ermittlung von Preisen und einer Ereigniszeit.
  • Die Hash-Summe m_hash_sum ist notwendig, um Änderungen in den Objekteigenschaften zu definieren.
    Eine Änderung der Objekteigenschaften wird durch den Vergleich der aktuellen und vorherigen ( m_hash_sum_prev) Hash-Summen definiert.
  • Die Anzahl der Dezimalstellen für die Kontowährung m_digit_currency ist notwendig, um die Daten einiger Ereignisse im Zusammenhang mit der Änderung von Geldwerten korrekt anzuzeigen.
  • Die Nummer des Fehlers, der bei einer fehlerhaften Rückgabe einer beliebigen Funktion erhalten wurde, wird in den m_global_error global error code geschrieben. Dieser Code wird zur weiteren Verarbeitung an das aufrufende Programm übergeben.
  • Die Karten-ID des Steuerungsprogramms m_chart_id dient zur Angabe des Charts, an das ein Objektereignis gesendet werden soll.
  • Das Flag der Objekt-Ereignisse m_is_event ist notwendig, um dem Programm mitzuteilen, dass das Ereignis im überwachten Objekt aufgetreten ist, damit es rechtzeitig auf das Ereignis reagiert.
  • Der m_event_code Objektereigniscode speichert die Flags aller gleichzeitig aufgetretenen Ereignisse. Das Vorhandensein dieser Flags ermöglicht es uns, die Liste der gleichzeitig aufgetretenen Objektereignisse zu definieren.
  • Der Objektname m_name ist notwendig, um dem Programm einige Texteigenschaften des Objekts mitzuteilen, von dem die Ereignisse empfangen werden sollen. Bei einem Konto ist dies beispielsweise die Kontonummer+Client-Name+Servername, bei einem Symbol ist es der Symbolname.
  • Der Name des Ordners zum Speichern von Objektdateien m_folder_name ist notwendig, um das Objekt in der Datei zu speichern: Hier wird der Name des Unterordners mit den Objektdateien des gleichen Typs gespeichert.
    Das Basisverzeichnis für den Unterordner ist das Verzeichnis der gemeinsamen Dateien aller Client-Terminals+Bibliothek Ordnername: "DoEasy\\". Wir haben bereits die Speicherung von Dateien bei der Erstellung der Kontenkollektion im Teil 12 der Bibliotheksbeschreibung diskutiert.

Wir haben alle diese Eigenschaften bereits in den Bibliotheksobjekten angelegt und in den verschiedenen Teilen der Bibliotheksbeschreibung, die den besprochenen Objekten entsprechen, diskutiert. Nun haben wir sie in einer einzigen Klasse platziert — dem Basisobjekt aller Bibliotheksobjekte CBaseObj und entfernen die Definitionen dieser Klassenmitglieder aus den nachfolgenden Objektklassen (siehe die angehängten Dateien).

Lassen Sie uns einen Blick auf die Methoden werfen, die sich im 'private' Abschnitt der Klasse befinden:

//--- Return time in milliseconds from MqlTick
   long              TickTime(void)                            const { return #ifdef __MQL5__ this.m_tick.time_msc #else this.m_tick.time*1000 #endif ;}
//--- return the flag of the event code presence in the event object
   bool              IsPresentEventFlag(const int change_code) const { return (this.m_event_code & change_code)==change_code; }
//--- Return the number of decimal places of the account currency
   int               DigitsCurrency(void)                      const { return this.m_digits_currency; }
//--- Returns the number of decimal places in the 'double' value
   int               GetDigits(const double value)             const;
//--- Initialize the variables of (1) tracked, (2) controlled object data (implementation in the descendants)
   virtual void      InitChangesParams(void);
   virtual void      InitControlsParams(void);
//--- (1) Check the object change, return the change code, (2) set the event type and fill in the list of events (implementation in the descendants)
   virtual int       SetEventCode(void);
   virtual void      SetTypeEvent(void);


  • Die Methode TickTime() gibt die Ereigniszeit in Millisekunden zurück. Bei MQL4 wird die Zeit in Sekunden * 1000 zurückgegeben, da eine Struktur für Millisekunden nicht vorhanden sind.
  • Die Methode IsPresentEventFlag() gibt das Vorhandensein eines bestimmten Ereigniscodes in der Variablen m_event_code zurück.
  • Die Methode DigitsCurrency() liefert die Anzahl der Dezimalstellen im Wert der Kontowährung aus der Variablen m_digits_currency.
  • Die Methode GetDigits() berechnet und gibt die Anzahl der Dezimalstellen des an sie übergebenen Doppelwerts zurück.
  • Die virtuelle Methode InitChangesParams() initialisiert die Parameter aller editierbaren Objekteigenschaften.
  • Die virtuelle Methode InitControlsParams() initialisiert die Parameter der verfolgten Objekteigenschaften.
  • Die virtuelle Methode SetEventCode() überprüft die Änderungen in den Objekteigenschaften und gibt den Code der aufgetretenen Änderungen zurück.
  • Die virtuelle Methode SetTypeEvent() setzt den Typ eines aufgetretenen Ereignisses basierend auf dem Ereigniscode und platziert alle Ereignisse in der Objekt-Ereignisliste.

Alle diese Methoden wurden bereits in den vorangegangenen Artikeln entwickelt. Es hat also keinen Sinn, sie hier zu beschreiben. Ich möchte nur klarstellen, dass alle virtuellen Methoden hier nichts bewirken und in den abgeleiteten Klassen des Basisobjekts implementiert werden sollten.

Die folgenden Methoden sind im 'public' Abschnitt der Klasse deklariert:

public:
//--- Add the event object to the list
   bool              EventAdd(const ushort event_id,const long lparam,const double dparam,const string sparam);
//--- Return the occurred event flag to the object data
   bool              IsEvent(void)                             const { return this.m_is_event;              }
//--- Return (1) the list of events, (2) the object event code and (3) the global error code
   CArrayObj        *GetListEvents(void)                             { return &this.m_list_events;          }
   int               GetEventCode(void)                        const { return this.m_event_code;            }
   int               GetError(void)                            const { return this.m_global_error;          }
//--- Return the event object by its number in the list
   CEventBaseObj    *GetEvent(const int shift=WRONG_VALUE,const bool check_out=true);
//--- Return the number of object events
   int               GetEventsTotal(void)                      const { return this.m_list_events.Total();   }
//--- (1) Set and (2) return the chart ID of the control program
   void              SetChartID(const long id)                       { this.m_chart_id=id;                  }
   long              GetChartID(void)                          const { return this.m_chart_id;              }
//--- (1) Set the sub-folder name, (2) return the folder name for storing descendant object files
   void              SetSubFolderName(const string name)             { this.m_folder_name=DIRECTORY+name;   }
   string            GetFolderName(void)                       const { return this.m_folder_name;           }
//--- Return the object name
   string            GetName(void)                             const { return this.m_name;                  }
//--- Update the object data (implementation in the descendants)
   virtual void      Refresh(void);


In der Initialisierungsliste des Klassenkonstruktors, werden den Variablen der Klassenmitglieder die Initialwerte zugewiesen:

//+------------------------------------------------------------------+
//| Konstruktor                                                      |
//+------------------------------------------------------------------+
CBaseObj::CBaseObj() : m_global_error(ERR_SUCCESS),      
                       m_hash_sum(0),m_hash_sum_prev(0), 
                       m_is_event(false),m_event_code(0),
                       m_chart_id(::ChartID()),          
                       m_folder_name(DIRECTORY),         
                       m_name("")                        
  {
   ::ZeroMemory(this.m_tick);
   this.m_digits_currency=(#ifdef __MQL5__ (int)::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #else 2 #endif);
   this.m_list_events.Clear();
   this.m_list_events.Sort();
  }
//+------------------------------------------------------------------+


Die Tickstruktur wird dann auf Null gesetzt, die Anzahl der Dezimalstellen für die Kontowährung wird zugeordnet, die Ereignisliste wird gelöscht und das Sortierlistenkennzeichen wird für die Objekt-Ereignisliste gesetzt.

Die Methode zum Hinzufügen eines Ereignisses zur Liste:

//+------------------------------------------------------------------+
//| Add the event object to the list                                 |
//+------------------------------------------------------------------+
bool CBaseObj::EventAdd(const ushort event_id,const long lparam,const double dparam,const string sparam)
  {
   CEventBaseObj *event=new CEventBaseObj(event_id,lparam,dparam,sparam);
   if(event==NULL)
      return false;
   this.m_list_events.Sort();
   if(this.m_list_events.Search(event)>WRONG_VALUE)
     {
      delete event;
      return false;
     }
   return this.m_list_events.Add(event);
  }
//+------------------------------------------------------------------+


Ereignis-ID sowie Long-, Double- und String-Werte der Event-Eigenschaften werden an die Methode übergeben. Ein neues Ereignis mit diesen Parametern wird dann erzeugt. Wenn das gleiche Ereignis bereits in der Liste vorhanden ist, gibt das Ereignisobjekt und die Methode false zurück, andernfalls gibt die Methode das Ergebnis des Hinzufügens eines Ereignisobjekts zur Liste zurück.

Die Methode, die ein Ereignisobjekt über seinen Index in der Liste zurückgibt:

//+------------------------------------------------------------------+
//| Return the object event by its index in the list                 |
//+------------------------------------------------------------------+
CEventBaseObj *CBaseObj::GetEvent(const int shift=WRONG_VALUE,const bool check_out=true)
  {
   int total=this.m_list_events.Total();
   if(total==0 || (!check_out && shift>total-1))
      return NULL;   
   int index=(shift<=0 ? total-1 : shift>total-1 ? 0 : total-shift-1);
   CEventBaseObj *event=this.m_list_events.At(index);
   return(event!=NULL ? event : NULL);
  }
//+------------------------------------------------------------------+


Wir haben die Methode bereits vorher berücksichtigt. Hier haben wir nur das Flag hinzugefügt, das die Notwendigkeit definiert, den Index zu überprüfen und zu korrigieren, wenn sein Wert über die Liste hinaus laufen sollte. Standardmäßig wird der Index -1 an die Methode übergeben und die Prüfung auf Verlassen der Liste durchgeführt. In diesem Fall gibt die Methode das jüngste Ereignisobjekt aus der Liste zurück. Um ein Objekt über seinen Index zu erhalten, müssen wir den erforderlichen Index an die Methode übergeben und das Flag außerhalb der Liste auf false setzen. In diesem Fall wird ein Objekt (oder ein Index innerhalb der Liste) zurückgegeben. Wenn der Index außerhalb der Liste liegt, wird NULL zurückgegeben.

Die Methode, die die Anzahl der Dezimalstellen der reellen Zahl zurückgibt, wurde ebenfalls vorher berücksichtigt:

//+------------------------------------------------------------------+
//| Return the number of decimal places in the 'double' value        |
//+------------------------------------------------------------------+
int CBaseObj::GetDigits(const double value) const
  {
   string val_str=(string)value;
   int len=::StringLen(val_str);
   int n=len-::StringFind(val_str,".",0)-1;
   if(::StringSubstr(val_str,len-1,1)=="0")
      n--;
   return n;
  }
//+------------------------------------------------------------------+


Das neue Basisobjekt ist fertig.

Nun müssen wir nur noch die Basisklasse CObject durch CBaseObj in jedem der Bibliothek-Basisobjekte ersetzen. Diese Objekte sind:

Klassenobjekt Objekt:

//+------------------------------------------------------------------+
//| Account class                                                    |
//+------------------------------------------------------------------+
class CAccount : public CBaseObj
  {


Klassenobjekt CSymbol:

//+------------------------------------------------------------------+
//| Abstract symbol class                                            |
//+------------------------------------------------------------------+
class CSymbol : public CBaseObj
  {


Die Kollektionsklassen sind ebenfalls mit den allgemeinen Objekteigenschaften ausgestattet:

Kollektion der Handelsereignisse:

//+------------------------------------------------------------------+
//| Collection of account trading events                             |
//+------------------------------------------------------------------+
class CEventsCollection : public CBaseObj
  {


Kollektion der Konten:

//+------------------------------------------------------------------+
//| Account collection                                               |
//+------------------------------------------------------------------+
class CAccountsCollection : public CBaseObj
  {


Symbolkollektion:

//+------------------------------------------------------------------+
//| Symbol collection                                                |
//+------------------------------------------------------------------+
class CSymbolsCollection : public CBaseObj
  {


Nun haben alle CBaseObj-basierten Objekte einen ähnlichen Satz von Eigenschaften, und wir müssen sie nicht für jedes neu erstellte Objekt neu setzen. Außerdem sind wir nun in der Lage, beliebige Eigenschaften für alle Objekte hinzuzufügen, die auf der Grundlage dieses Basisobjekts erstellt wurden. Interessanterweise hat jedes der Objekte nun das Werkzeug, um mit Ereignissen zu arbeiten. Jedes der Objektereignisse hat den gleichen Parametersatz wie die Funktion zum Senden von Ereignissen an das Programmchart EventChartCustom(). So haben wir die Weiterentwicklung neuer Objekte und die Verbesserung der vorgefertigten stark vereinfacht.


Jetzt sind wir bereit, Ereignisse der Kollektionssymbole zu erstellen.

Ereignisse der Kollektionssymbole

Wie üblich beginnt alles mit der Definition von Konstanten und Enumerationen. Öffnen Sie die Datei Defines.mqh und fügen Sie Daten hinzu, die für die Verfolgung von Symbolereignissen erforderlich sind.

Da Symbole im Fenster der Marktübersicht vorhanden sein sollten, um mit ihnen zu arbeiten, während ihre Anzahl im Fenster begrenzt ist,
Hinzufügen der Zeichenkette mit der Makrosubstitution, die die maximal mögliche Anzahl von Symbolen angibt, die sich gleichzeitig im Fenster der Marktübersicht befinden, zu den Symbolparametern:.

//--- Symbol parameters
#define CLR_DEFAULT                    (0xFF000000)               // Default color
#define SYMBOLS_COMMON_TOTAL           (1000)                     // Total number of working symbols


Verschieben wir die Enumeration der Arbeitsmodi mit Symbolen aus dem Datenteil für die Arbeit mit Symbolen

//+------------------------------------------------------------------+
//| Data for working with symbols                                    |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Modes of working with symbols                                    |
//+------------------------------------------------------------------+
enum ENUM_SYMBOLS_MODE
  {
   SYMBOLS_MODE_CURRENT,                                    // Work with the current symbol only
   SYMBOLS_MODE_DEFINES,                                    // Work with the specified symbol list
   SYMBOLS_MODE_MARKET_WATCH,                               // Work with the Market Watch window symbols
   SYMBOLS_MODE_ALL                                         // Work with the full symbol list
  };
//+------------------------------------------------------------------+

in die Datei Datas.mqh:

//+------------------------------------------------------------------+
//|                                                        Datas.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/de/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/de/users/artmedia70"
//+------------------------------------------------------------------+
//| Enumerations                                                     |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Modes of working with symbols                                    |
//+------------------------------------------------------------------+
enum ENUM_SYMBOLS_MODE
  {
   SYMBOLS_MODE_CURRENT,                                    // Work with the current symbol only
   SYMBOLS_MODE_DEFINES,                                    // Work with the specified symbol list
   SYMBOLS_MODE_MARKET_WATCH,                               // Work with the Market Watch window symbols
   SYMBOLS_MODE_ALL                                         // Work with the full symbol list
  };
//+------------------------------------------------------------------+
//| Data sets                                                        |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Major Forex symbols                                              |
//+------------------------------------------------------------------+
string DataSymbolsFXMajors[]=
  {


Ausschlaggebend für die Entscheidung war die Tatsache, dass diese Daten nicht nur für die Bibliothek, sondern auch für die bibliotheksbasierten Programme notwendig sind. Diese Aufzählung bezieht sich mehr auf allgemeine Programmdaten als auf die Bibliothek. So sollen beispielsweise die Daten zusammen mit vielen anderen Aufzählungen als Programmeingaben verwendet werden, d.h. sie werden in die notwendige Kompilierungssprache umgewandelt (die später implementiert werden wird). Daher sollte es in der Datas.mqh stehen.

Anstelle der Enumeration aus Defines.mqhfügen wir die Enumeration mit der Liste der Symbolereignisflags und Enumeration mit der Liste der möglichen Symbolereignisse hinzu:

//+------------------------------------------------------------------+
//| Data for working with symbols                                    |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| List of symbol event flags                                       |
//+------------------------------------------------------------------+
enum ENUM_SYMBOL_EVENT_FLAGS
  {
   SYMBOL_EVENT_FLAG_NO_EVENT                =  0,          // No event
   SYMBOL_EVENT_FLAG_TRADE_MODE              =  1,          // Change order execution permissions
   SYMBOL_EVENT_FLAG_SESSION_DEALS           =  2,          // Change the number of deals in the current session
   SYMBOL_EVENT_FLAG_SESSION_BUY_ORDERS      =  4,          // Change the total number of the current buy orders
   SYMBOL_EVENT_FLAG_SESSION_SELL_ORDERS     =  8,          // Change the total number of the current sell orders
   SYMBOL_EVENT_FLAG_VOLUME                  =  16,         // Change in the last deal volume exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_VOLUME_HIGH_DAY         =  32,         // Change of the maximum volume per day exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_VOLUME_LOW_DAY          =  64,         // Change of the minimum volume per day exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_SPREAD                  =  128,        // Change of a spread exceeds the specified change value in +/-
   SYMBOL_EVENT_FLAG_STOPLEVEL               =  256,        // Change of a Stop order level exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_FREEZELEVEL             =  512,        // Change of the freeze level exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_BID_LAST                =  1024,       // Change of the Bid or Last price exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_BID_LAST_HIGH           =  2048,       // Change of the maximum Bid or Last price per day exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_BID_LAST_LOW            =  4096,       // Change of the minimum Bid or Last price per day exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_ASK                     =  8192,       // Change of the Ask price exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_ASK_HIGH                =  16384,      // Change of the maximum Ask price per day exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_ASK_LOW                 =  32768,      // Change of the minimum Ask price per day exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_VOLUME_REAL_DAY         =  65536,      // Change of the real volume per day exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_VOLUME_HIGH_REAL_DAY    =  131072,     // Change of the maximum real volume per day exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_VOLUME_LOW_REAL_DAY     =  262144,     // Change of the minimum real volume per day exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_OPTION_STRIKE           =  524288,     // Change of the strike price exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_VOLUME_LIMIT            =  1048576,    // Change of the maximum available total position volume and pending orders in one direction
   SYMBOL_EVENT_FLAG_SWAP_LONG               =  2097152,    // Change swap long
   SYMBOL_EVENT_FLAG_SWAP_SHORT              =  4194304,    // Change swap short
   SYMBOL_EVENT_FLAG_SESSION_VOLUME          =  8388608,    // Change of the total volume of deals in the current session exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_SESSION_TURNOVER        =  16777216,   // Change of the total turnover in the current session exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_SESSION_INTEREST        =  33554432,   // Change of the total volume of open positions in the current session exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_SESSION_BUY_ORD_VOLUME  =  67108864,   // Change of the total volume of buy orders exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_SESSION_SELL_ORD_VOLUME =  134217728// Change of the total volume of sell orders exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_SESSION_OPEN            =  268435456// Change of the session open price exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_SESSION_CLOSE           =  536870912// Change of the session close price exceeds the specified value in +/-
   SYMBOL_EVENT_FLAG_SESSION_AW              =  1073741824  // Change of the average weighted session price exceeds the specified value in +/-
  };
//+------------------------------------------------------------------+
//| List of possible symbol events                                   |
//+------------------------------------------------------------------+
enum ENUM_SYMBOL_EVENT
  {
   SYMBOL_EVENT_NO_EVENT = ACCOUNT_EVENTS_NEXT_CODE,        // No event
   SYMBOL_EVENT_MW_ADD,                                     // Adding a symbol to the Market Watch window
   SYMBOL_EVENT_MW_DEL,                                     // Removing a symbol from the Market Watch window
   SYMBOL_EVENT_MW_SORT,                                    // Sorting symbols in the Market Watch window
   SYMBOL_EVENT_TRADE_DISABLE,                              // Disable order execution
   SYMBOL_EVENT_TRADE_LONGONLY,                             // Allow buy only
   SYMBOL_EVENT_TRADE_SHORTONLY,                            // Allow sell only
   SYMBOL_EVENT_TRADE_CLOSEONLY,                            // Enable close only
   SYMBOL_EVENT_TRADE_FULL,                                 // No trading limitations
   SYMBOL_EVENT_SESSION_DEALS_INC,                          // The increase in the number of deals in the current session exceeds the specified value
   SYMBOL_EVENT_SESSION_DEALS_DEC,                          // The decrease in the number of deals in the current session exceeds the specified value
   SYMBOL_EVENT_SESSION_BUY_ORDERS_INC,                     // The increase in the total number of buy orders currently exceeds the specified value
   SYMBOL_EVENT_SESSION_BUY_ORDERS_DEC,                     // The decrease in the total number of buy orders currently exceeds the specified value
   SYMBOL_EVENT_SESSION_SELL_ORDERS_INC,                    // The increase in the total number of sell orders currently exceeds the specified value
   SYMBOL_EVENT_SESSION_SELL_ORDERS_DEC,                    // The decrease in the total number of sell orders currently exceeds the specified value
   SYMBOL_EVENT_VOLUME_INC,                                 // Volume increase in the last deal exceeds the specified value
   SYMBOL_EVENT_VOLUME_DEC,                                 // Volume decrease in the last deal exceeds the specified value
   SYMBOL_EVENT_VOLUME_HIGH_DAY_INC,                        // The increase in the maximum volume per day exceeds the specified value
   SYMBOL_EVENT_VOLUME_HIGH_DAY_DEC,                        // The decrease in the maximum volume per day exceeds the specified value
   SYMBOL_EVENT_VOLUME_LOW_DAY_INC,                         // The increase in the minimum volume per day exceeds the specified value
   SYMBOL_EVENT_VOLUME_LOW_DAY_DEC,                         // The decrease in the minimum volume per day exceeds the specified value
   SYMBOL_EVENT_SPREAD_INC,                                 // The increase in a spread exceeds the specified change
   SYMBOL_EVENT_SPREAD_DEC,                                 // The decrease in a spread exceeds the specified change
   SYMBOL_EVENT_STOPLEVEL_INC,                              // The increase of a Stop order level exceeds the specified value
   SYMBOL_EVENT_STOPLEVEL_DEC,                              // The decrease of a Stop order level exceeds the specified value
   SYMBOL_EVENT_FREEZELEVEL_INC,                            // The increase in the freeze level exceeds the specified value
   SYMBOL_EVENT_FREEZELEVEL_DEC,                            // The decrease in the freeze level exceeds the specified value
   SYMBOL_EVENT_BID_LAST_INC,                               // The increase in the Bid or Last price exceeds the specified value
   SYMBOL_EVENT_BID_LAST_DEC,                               // The decrease in the Bid or Last price exceeds the specified value
   SYMBOL_EVENT_BID_LAST_HIGH_INC,                          // The increase in the maximum Bid or Last price per day exceeds the specified value
   SYMBOL_EVENT_BID_LAST_HIGH_DEC,                          // The decrease in the maximum Bid or Last price per day exceeds the specified value relative to the specified price
   SYMBOL_EVENT_BID_LAST_LOW_INC,                           // The increase in the minimum Bid or Last price per day exceeds the specified value relative to the specified price
   SYMBOL_EVENT_BID_LAST_LOW_DEC,                           // The decrease in the minimum Bid or Last price per day exceeds the specified value
   SYMBOL_EVENT_ASK_INC,                                    // The increase in the Ask price exceeds the specified value
   SYMBOL_EVENT_ASK_DEC,                                    // The decrease in the Ask price exceeds the specified value
   SYMBOL_EVENT_ASK_HIGH_INC,                               // The increase in the maximum Ask price per day exceeds the specified value
   SYMBOL_EVENT_ASK_HIGH_DEC,                               // The decrease in the maximum Ask price per day exceeds the specified value
   SYMBOL_EVENT_ASK_LOW_INC,                                // The increase in the minimum Ask price per day exceeds the specified value
   SYMBOL_EVENT_ASK_LOW_DEC,                                // The decrease in the minimum Ask price per day exceeds the specified value
   SYMBOL_EVENT_VOLUME_REAL_DAY_INC,                        // The increase in the real volume per day exceeds the specified value
   SYMBOL_EVENT_VOLUME_REAL_DAY_DEC,                        // The decrease in the real volume per day exceeds the specified value
   SYMBOL_EVENT_VOLUME_HIGH_REAL_DAY_INC,                   // The increase in the maximum real volume per day exceeds the specified value
   SYMBOL_EVENT_VOLUME_HIGH_REAL_DAY_DEC,                   // The decrease in the maximum real volume per day exceeds the specified value
   SYMBOL_EVENT_VOLUME_LOW_REAL_DAY_INC,                    // The increase in the minimum real volume per day exceeds the specified value
   SYMBOL_EVENT_VOLUME_LOW_REAL_DAY_DEC,                    // The decrease in the minimum real volume per day exceeds the specified value
   SYMBOL_EVENT_OPTION_STRIKE_INC,                          // The increase in the strike price exceeds the specified value
   SYMBOL_EVENT_OPTION_STRIKE_DEC,                          // The decrease in the strike price exceeds the specified value
   SYMBOL_EVENT_VOLUME_LIMIT_INC,                           // The increase in the maximum available total position volume and pending orders in one direction
   SYMBOL_EVENT_VOLUME_LIMIT_DEC,                           // The decrease in the maximum available total position volume and pending orders in one direction
   SYMBOL_EVENT_SWAP_LONG_INC,                              // The increase in the swap long
   SYMBOL_EVENT_SWAP_LONG_DEC,                              // The decrease in the swap long
   SYMBOL_EVENT_SWAP_SHORT_INC,                             // The increase in the swap short
   SYMBOL_EVENT_SWAP_SHORT_DEC,                             // The decrease in the swap short
   SYMBOL_EVENT_SESSION_VOLUME_INC,                         // The increase in the total volume of deals in the current session exceeds the specified value
   SYMBOL_EVENT_SESSION_VOLUME_DEC,                         // The decrease in the total volume of deals in the current session exceeds the specified value
   SYMBOL_EVENT_SESSION_TURNOVER_INC,                       // The increase in the total turnover in the current session exceeds the specified value
   SYMBOL_EVENT_SESSION_TURNOVER_DEC,                       // The decrease in the total turnover in the current session exceeds the specified value
   SYMBOL_EVENT_SESSION_INTEREST_INC,                       // The increase in the total volume of open positions in the current session exceeds the specified value
   SYMBOL_EVENT_SESSION_INTEREST_DEC,                       // The decrease in the total volume of open positions in the current session exceeds the specified value
   SYMBOL_EVENT_SESSION_BUY_ORD_VOLUME_INC,                 // The increase in the total volume of buy orders exceeds the specified value
   SYMBOL_EVENT_SESSION_BUY_ORD_VOLUME_DEC,                 // The decrease in the total volume of buy orders exceeds the specified value
   SYMBOL_EVENT_SESSION_SELL_ORD_VOLUME_INC,                // The increase in the total volume of sell orders exceeds the specified value
   SYMBOL_EVENT_SESSION_SELL_ORD_VOLUME_DEC,                // The decrease in the total volume of sell orders exceeds the specified value
   SYMBOL_EVENT_SESSION_OPEN_INC,                           // The increase in the session open price exceeds the specified value relative to the specified price
   SYMBOL_EVENT_SESSION_OPEN_DEC,                           // The decrease in the session open price exceeds the specified value relative to the specified price
   SYMBOL_EVENT_SESSION_CLOSE_INC,                          // The increase in the session close price exceeds the specified value relative to the specified price
   SYMBOL_EVENT_SESSION_CLOSE_DEC,                          // The decrease in the session close price exceeds the specified value relative to the specified price
   SYMBOL_EVENT_SESSION_AW_INC,                             // The increase in the average weighted session price exceeds the specified value
   SYMBOL_EVENT_SESSION_AW_DEC,                             // The decrease in the average weighted session price exceeds the specified value
  };
#define SYMBOL_EVENTS_NEXT_CODE       (SYMBOL_EVENT_SESSION_AW_DEC+1)   // The code of the next event after the last symbol event code
//+------------------------------------------------------------------+


Hier ist alles so wie bei der Enumeration der Flags und den möglichen Konto- und Handelsereignissen. Wir haben Ereignisflags und Ereignis-IDs im vierten Teil der Bibliotheksbeschreibung besprochen.

Um Symbole nach ihrer Position im Fenster der Marktübersicht zu sortieren, fügen Sie noch eine weitere ganzzahlige Symboleigenschaft hinzu:

//+------------------------------------------------------------------+
//| Symbol integer properties                                        |
//+------------------------------------------------------------------+
enum ENUM_SYMBOL_PROP_INTEGER
  {
   SYMBOL_PROP_STATUS = 0,                                  // Symbol status
   SYMBOL_PROP_INDEX_MW,                                    // Symbol index in the Market Watch window
   SYMBOL_PROP_CUSTOM,                                      // Custom symbol flag
   SYMBOL_PROP_CHART_MODE,                                  // The price type used for generating bars – Bid or Last (from the ENUM_SYMBOL_CHART_MODE enumeration)
   SYMBOL_PROP_EXIST,                                       // Flag indicating that the symbol under this name exists
   SYMBOL_PROP_SELECT,                                      // The indication that the symbol is selected in Market Watch
   SYMBOL_PROP_VISIBLE,                                     // The indication that the symbol is displayed in Market Watch
   SYMBOL_PROP_SESSION_DEALS,                               // The number of deals in the current session 
   SYMBOL_PROP_SESSION_BUY_ORDERS,                          // The total number of Buy orders at the moment
   SYMBOL_PROP_SESSION_SELL_ORDERS,                         // The total number of Sell orders at the moment
   SYMBOL_PROP_VOLUME,                                      // Last deal volume
   SYMBOL_PROP_VOLUMEHIGH,                                  // Maximum volume within a day
   SYMBOL_PROP_VOLUMELOW,                                   // Minimum volume within a day
   SYMBOL_PROP_TIME,                                        // Latest quote time
   SYMBOL_PROP_DIGITS,                                      // Number of decimal places
   SYMBOL_PROP_DIGITS_LOTS,                                 // Number of decimal places for a lot
   SYMBOL_PROP_SPREAD,                                      // Spread in points
   SYMBOL_PROP_SPREAD_FLOAT,                                // Floating spread flag
   SYMBOL_PROP_TICKS_BOOKDEPTH,                             // Maximum number of orders displayed in the Depth of Market
   SYMBOL_PROP_TRADE_CALC_MODE,                             // Contract price calculation method (from the ENUM_SYMBOL_CALC_MODE enumeration)
   SYMBOL_PROP_TRADE_MODE,                                  // Order execution type (from the ENUM_SYMBOL_TRADE_MODE enumeration)
   SYMBOL_PROP_START_TIME,                                  // Symbol trading start date (usually used for futures)
   SYMBOL_PROP_EXPIRATION_TIME,                             // Symbol trading end date (usually used for futures)
   SYMBOL_PROP_TRADE_STOPS_LEVEL,                           // Minimum distance in points from the current close price for setting Stop orders
   SYMBOL_PROP_TRADE_FREEZE_LEVEL,                          // Freeze distance for trading operations (in points)
   SYMBOL_PROP_TRADE_EXEMODE,                               // Deal execution mode (from the ENUM_SYMBOL_TRADE_EXECUTION enumeration)
   SYMBOL_PROP_SWAP_MODE,                                   // Swap calculation model (from the ENUM_SYMBOL_SWAP_MODE enumeration)
   SYMBOL_PROP_SWAP_ROLLOVER3DAYS,                          // Triple-day swap (from the ENUM_DAY_OF_WEEK enumeration)
   SYMBOL_PROP_MARGIN_HEDGED_USE_LEG,                       // Calculating hedging margin using the larger leg (Buy or Sell)
   SYMBOL_PROP_EXPIRATION_MODE,                             // Flags of allowed order expiration modes
   SYMBOL_PROP_FILLING_MODE,                                // Flags of allowed order filling modes
   SYMBOL_PROP_ORDER_MODE,                                  // Flags of allowed order types
   SYMBOL_PROP_ORDER_GTC_MODE,                              // Expiration of Stop Loss and Take Profit orders if SYMBOL_EXPIRATION_MODE=SYMBOL_EXPIRATION_GTC (from the ENUM_SYMBOL_ORDER_GTC_MODE enumeration)
   SYMBOL_PROP_OPTION_MODE,                                 // Option type (from the ENUM_SYMBOL_OPTION_MODE enumeration)
   SYMBOL_PROP_OPTION_RIGHT,                                // Option right (Call/Put) (from the ENUM_SYMBOL_OPTION_RIGHT enumeration)
   //--- skipped property
   SYMBOL_PROP_BACKGROUND_COLOR                             // The color of the background used for the symbol in Market Watch
  }; 
#define SYMBOL_PROP_INTEGER_TOTAL    (36)                   // Total number of integer properties
#define SYMBOL_PROP_INTEGER_SKIP     (1)                    // Number of symbol integer properties not used in sorting
//+------------------------------------------------------------------+


Da wir die neue Eigenschaft hinzugefügt haben, sollten wir die Gesamtzahl der ganzzahligen Eigenschaften auf 36 statt bisher 35 erhöhen.

Fügen wir schließlich die neue Eigenschaft zur Liste der möglichen Sortierkriterien für Symbole hinzu:

//+------------------------------------------------------------------+
//| Possible symbol sorting criteria                                 |
//+------------------------------------------------------------------+
#define FIRST_SYM_DBL_PROP          (SYMBOL_PROP_INTEGER_TOTAL-SYMBOL_PROP_INTEGER_SKIP)
#define FIRST_SYM_STR_PROP          (SYMBOL_PROP_INTEGER_TOTAL-SYMBOL_PROP_INTEGER_SKIP+SYMBOL_PROP_DOUBLE_TOTAL-SYMBOL_PROP_DOUBLE_SKIP)
enum ENUM_SORT_SYMBOLS_MODE
  {
//--- Sortieren nach den Integer-Eigenschaften
   SORT_BY_SYMBOL_STATUS = 0,                               // Sort by symbol status
   SORT_BY_SYMBOL_INDEX_MW,                                 // Sort by index in the Market Watch window
   SORT_BY_SYMBOL_CUSTOM,                                   // Sort by custom symbol property
   SORT_BY_SYMBOL_CHART_MODE,                               // Sort by price type for constructing bars – Bid or Last (from the ENUM_SYMBOL_CHART_MODE enumeration)
   SORT_BY_SYMBOL_EXIST,                                    // Sort by the flag that a symbol with such a name exists
   SORT_BY_SYMBOL_SELECT,                                   // Sort by the flag indicating that a symbol is selected in Market Watch
   SORT_BY_SYMBOL_VISIBLE,                                  // Sort by the flag indicating that a selected symbol is displayed in Market Watch
   SORT_BY_SYMBOL_SESSION_DEALS,                            // Sort by the number of deals in the current session 
   SORT_BY_SYMBOL_SESSION_BUY_ORDERS,                       // Sort by the total number of current buy orders
   SORT_BY_SYMBOL_SESSION_SELL_ORDERS,                      // Sort by the total number of current sell orders
   SORT_BY_SYMBOL_VOLUME,                                   // Sort by last deal volume
   SORT_BY_SYMBOL_VOLUMEHIGH,                               // Sort by maximum volume for a day
   SORT_BY_SYMBOL_VOLUMELOW,                                // Sort by minimum volume for a day
   SORT_BY_SYMBOL_TIME,                                     // Sort by the last quote time
   SORT_BY_SYMBOL_DIGITS,                                   // Sort by a number of decimal places
   SORT_BY_SYMBOL_DIGITS_LOT,                               // Sort by a number of decimal places in a lot
   SORT_BY_SYMBOL_SPREAD,                                   // Sort by spread in points
   SORT_BY_SYMBOL_SPREAD_FLOAT,                             // Sort by floating spread
   SORT_BY_SYMBOL_TICKS_BOOKDEPTH,                          // Sort by a maximum number of requests displayed in the market depth
   SORT_BY_SYMBOL_TRADE_CALC_MODE,                          // Sort by contract price calculation method (from the ENUM_SYMBOL_CALC_MODE enumeration)
   SORT_BY_SYMBOL_TRADE_MODE,                               // Sort by order execution type (from the ENUM_SYMBOL_TRADE_MODE enumeration)
   SORT_BY_SYMBOL_START_TIME,                               // Sort by an instrument trading start date (usually used for futures)
   SORT_BY_SYMBOL_EXPIRATION_TIME,                          // Sort by an instrument trading end date (usually used for futures)
   SORT_BY_SYMBOL_TRADE_STOPS_LEVEL,                        // Sort by the minimum indent from the current close price (in points) for setting Stop orders
   SORT_BY_SYMBOL_TRADE_FREEZE_LEVEL,                       // Sort by trade operation freeze distance (in points)
   SORT_BY_SYMBOL_TRADE_EXEMODE,                            // Sort by trade execution mode (from the ENUM_SYMBOL_TRADE_EXECUTION enumeration)
   SORT_BY_SYMBOL_SWAP_MODE,                                // Sort by swap calculation model (from the ENUM_SYMBOL_SWAP_MODE enumeration)
   SORT_BY_SYMBOL_SWAP_ROLLOVER3DAYS,                       // Sort by week day for accruing a triple swap (from the ENUM_DAY_OF_WEEK enumeration)
   SORT_BY_SYMBOL_MARGIN_HEDGED_USE_LEG,                    // Sort by the calculation mode of a hedged margin using the larger leg (Buy or Sell)
   SORT_BY_SYMBOL_EXPIRATION_MODE,                          // Sort by flags of allowed order expiration modes
   SORT_BY_SYMBOL_FILLING_MODE,                             // Sort by flags of allowed order filling modes
   SORT_BY_SYMBOL_ORDER_MODE,                               // Sort by flags of allowed order types
   SORT_BY_SYMBOL_ORDER_GTC_MODE,                           // Sort by StopLoss and TakeProfit orders lifetime
   SORT_BY_SYMBOL_OPTION_MODE,                              // Sort by option type (from the ENUM_SYMBOL_OPTION_MODE enumeration)
   SORT_BY_SYMBOL_OPTION_RIGHT,                             // Sort by option right (Call/Put) (from the ENUM_SYMBOL_OPTION_RIGHT enumeration)
//--- Sortieren nach den Double-Eigenschaften
   SORT_BY_SYMBOL_BID = FIRST_SYM_DBL_PROP,                 // Sort by Bid
   SORT_BY_SYMBOL_BIDHIGH,                                  // Sort by maximum Bid for a day
   SORT_BY_SYMBOL_BIDLOW,                                   // Sort by minimum Bid for a day
   SORT_BY_SYMBOL_ASK,                                      // Sort by Ask
   SORT_BY_SYMBOL_ASKHIGH,                                  // Sort by maximum Ask for a day
   SORT_BY_SYMBOL_ASKLOW,                                   // Sort by minimum Ask for a day
   SORT_BY_SYMBOL_LAST,                                     // Sort by the last deal price
   SORT_BY_SYMBOL_LASTHIGH,                                 // Sort by maximum Last for a day
   SORT_BY_SYMBOL_LASTLOW,                                  // Sort by minimum Last for a day
   SORT_BY_SYMBOL_VOLUME_REAL,                              // Sort by Volume for a day
   SORT_BY_SYMBOL_VOLUMEHIGH_REAL,                          // Sort by maximum Volume for a day
   SORT_BY_SYMBOL_VOLUMELOW_REAL,                           // Sort by minimum Volume for a day
   SORT_BY_SYMBOL_OPTION_STRIKE,                            // Sort by an option execution price
   SORT_BY_SYMBOL_POINT,                                    // Sort by a single point value
   SORT_BY_SYMBOL_TRADE_TICK_VALUE,                         // Sort by SYMBOL_TRADE_TICK_VALUE_PROFIT value
   SORT_BY_SYMBOL_TRADE_TICK_VALUE_PROFIT,                  // Sort by a calculated tick price for a profitable position
   SORT_BY_SYMBOL_TRADE_TICK_VALUE_LOSS,                    // Sort by a calculated tick price for a loss-making position
   SORT_BY_SYMBOL_TRADE_TICK_SIZE,                          // Sort by a minimum price change
   SORT_BY_SYMBOL_TRADE_CONTRACT_SIZE,                      // Sort by a trading contract size
   SORT_BY_SYMBOL_TRADE_ACCRUED_INTEREST,                   // Sort by accrued interest
   SORT_BY_SYMBOL_TRADE_FACE_VALUE,                         // Sort by face value
   SORT_BY_SYMBOL_TRADE_LIQUIDITY_RATE,                     // Sort by liquidity rate
   SORT_BY_SYMBOL_VOLUME_MIN,                               // Sort by a minimum volume for performing a deal
   SORT_BY_SYMBOL_VOLUME_MAX,                               // Sort by a maximum volume for performing a deal
   SORT_BY_SYMBOL_VOLUME_STEP,                              // Sort by a minimum volume change step for deal execution
   SORT_BY_SYMBOL_VOLUME_LIMIT,                             // Sort by a maximum allowed aggregate volume of an open position and pending orders in one direction
   SORT_BY_SYMBOL_SWAP_LONG,                                // Sort by a long swap value
   SORT_BY_SYMBOL_SWAP_SHORT,                               // Sort by a short swap value
   SORT_BY_SYMBOL_MARGIN_INITIAL,                           // Sort by an initial margin
   SORT_BY_SYMBOL_MARGIN_MAINTENANCE,                       // Sort by a maintenance margin for an instrument
   SORT_BY_SYMBOL_MARGIN_LONG_INITIAL,                      // Sort by initial margin requirement applicable to Long orders
   SORT_BY_SYMBOL_MARGIN_BUY_STOP_INITIAL,                  // Sort by initial margin requirement applicable to BuyStop orders
   SORT_BY_SYMBOL_MARGIN_BUY_LIMIT_INITIAL,                 // Sort by initial margin requirement applicable to BuyLimit orders
   SORT_BY_SYMBOL_MARGIN_BUY_STOPLIMIT_INITIAL,             // Sort by initial margin requirement applicable to BuyStopLimit orders
   SORT_BY_SYMBOL_MARGIN_LONG_MAINTENANCE,                  // Sort by maintenance margin requirement applicable to Long orders
   SORT_BY_SYMBOL_MARGIN_BUY_STOP_MAINTENANCE,              // Sort by maintenance margin requirement applicable to BuyStop orders
   SORT_BY_SYMBOL_MARGIN_BUY_LIMIT_MAINTENANCE,             // Sort by maintenance margin requirement applicable to BuyLimit orders
   SORT_BY_SYMBOL_MARGIN_BUY_STOPLIMIT_MAINTENANCE,         // Sort by maintenance margin requirement applicable to BuyStopLimit orders
   SORT_BY_SYMBOL_MARGIN_SHORT_INITIAL,                     // Sort by initial margin requirement applicable to Short orders
   SORT_BY_SYMBOL_MARGIN_SELL_STOP_INITIAL,                 // Sort by initial margin requirement applicable to SellStop orders
   SORT_BY_SYMBOL_MARGIN_SELL_LIMIT_INITIAL,                // Sort by initial margin requirement applicable to SellLimit orders
   SORT_BY_SYMBOL_MARGIN_SELL_STOPLIMIT_INITIAL,            // Sort by initial margin requirement applicable to SellStopLimit orders
   SORT_BY_SYMBOL_MARGIN_SHORT_MAINTENANCE,                 // Sort by maintenance margin requirement applicable to Short orders
   SORT_BY_SYMBOL_MARGIN_SELL_STOP_MAINTENANCE,             // Sort by maintenance margin requirement applicable to SellStop orders
   SORT_BY_SYMBOL_MARGIN_SELL_LIMIT_MAINTENANCE,            // Sort by maintenance margin requirement applicable to SellLimit orders
   SORT_BY_SYMBOL_MARGIN_SELL_STOPLIMIT_MAINTENANCE,        // Sort by maintenance margin requirement applicable to SellStopLimit orders
   SORT_BY_SYMBOL_SESSION_VOLUME,                           // Sort by summary volume of the current session deals
   SORT_BY_SYMBOL_SESSION_TURNOVER,                         // Sort by the summary turnover of the current session
   SORT_BY_SYMBOL_SESSION_INTEREST,                         // Sort by the summary open interest
   SORT_BY_SYMBOL_SESSION_BUY_ORDERS_VOLUME,                // Sort by the current volume of Buy orders
   SORT_BY_SYMBOL_SESSION_SELL_ORDERS_VOLUME,               // Sort by the current volume of Sell orders
   SORT_BY_SYMBOL_SESSION_OPEN,                             // Sort by a session Open price
   SORT_BY_SYMBOL_SESSION_CLOSE,                            // Sort by a session Close price
   SORT_BY_SYMBOL_SESSION_AW,                               // Sort by an average weighted price of the current session
   SORT_BY_SYMBOL_SESSION_PRICE_SETTLEMENT,                 // Sort by a settlement price of the current session
   SORT_BY_SYMBOL_SESSION_PRICE_LIMIT_MIN,                  // Sort by a minimum price of the current session 
   SORT_BY_SYMBOL_SESSION_PRICE_LIMIT_MAX,                  // Sort by a maximum price of the current session
   SORT_BY_SYMBOL_MARGIN_HEDGED,                            // Sort by a contract size or a margin value per one lot of hedged positions
//--- Sortieren nach den String-Eigenschaften
   SORT_BY_SYMBOL_NAME = FIRST_SYM_STR_PROP,                // Sort by a symbol name
   SORT_BY_SYMBOL_BASIS,                                    // Sort by an underlying asset of a derivative
   SORT_BY_SYMBOL_CURRENCY_BASE,                            // Sort by a base currency of a symbol
   SORT_BY_SYMBOL_CURRENCY_PROFIT,                          // Sort by a profit currency
   SORT_BY_SYMBOL_CURRENCY_MARGIN,                          // Sort by a margin currency
   SORT_BY_SYMBOL_BANK,                                     // Sort by a feeder of the current quote
   SORT_BY_SYMBOL_DESCRIPTION,                              // Sort by a symbol string description
   SORT_BY_SYMBOL_FORMULA,                                  // Sort by the formula used for custom symbol pricing
   SORT_BY_SYMBOL_ISIN,                                     // Sort by the name of a symbol in the ISIN system
   SORT_BY_SYMBOL_PAGE,                                     // Sort by an address of the web page containing symbol information
   SORT_BY_SYMBOL_PATH                                      // Sort by a path in the symbol tree
  };
//+------------------------------------------------------------------+

Wir sind fertig mit der Datei Defines.mqh.

Nun müssen wir die Objektklasse der Symbole verbessern. Da wir die Änderungen einiger Symboleigenschaften verfolgen werden, müssen wir ihren aktuellen Wert mit dem vorherigen vergleichen, entweder absolut oder um eine Erhöhung eines bestimmten vorgegebenen Schwellenwerts zu erkennen. Dazu müssen wir die Struktur der Symboleigenschaften erstellen und die Felder der Struktur der aktuellen Werte mit den Feldern der Struktur der vorherigen Werte vergleichen. Wir haben bereits die Logik der Definition der Objektereignisse bei der Implementierung der Verfolgung der Kontoereignisse diskutiert. Hier werden wir dasselbe tun, mit der Ausnahme, dass das Basisobjekt bereits die Methoden zum Speichern und Senden von Ereignissen an das Programm enthält.

Binden Sie die Basisobjektdatei in die Klasse CSymbol ein. Erstellen Sie im 'private' Abschnitt der Klasse die Struktur der verfolgten Symboleigenschaften und deklarieren Sie die beiden Variablen der Struktur zum Speichern der aktuellen und vorherigen Zustände der Symboleigenschaften:

//+------------------------------------------------------------------+
//|                                                       Symbol.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/de/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/de/users/artmedia70"
#property version   "1.00"
#property strict    // Notwendig für mql4
//+------------------------------------------------------------------+
//| Include-Dateien                                                  |
//+------------------------------------------------------------------+
#include "..\BaseObj.mqh"
//+------------------------------------------------------------------+
//| Abstract symbol class                                            |
//+------------------------------------------------------------------+
class CSymbol : public CBaseObj
  {
private:
   struct MqlDataSymbol
     {
      //--- Symbol integer properties
      ENUM_SYMBOL_TRADE_MODE trade_mode;     // SYMBOL_TRADE_MODE Order filling modes
      long session_deals;                    // SYMBOL_SESSION_DEALS The number of deals in the current session 
      long session_buy_orders;               // SYMBOL_SESSION_BUY_ORDERS The total number of current buy orders
      long session_sell_orders;              // SYMBOL_SESSION_SELL_ORDERS The total number of current sell orders
      long volume;                           // SYMBOL_VOLUME Last deal volume
      long volume_high_day;                  // SYMBOL_VOLUMEHIGH Maximum volume within a day
      long volume_low_day;                   // SYMBOL_VOLUMELOW Minimum volume within a day
      int spread;                            // SYMBOL_SPREAD Spread in points
      int stops_level;                       // SYMBOL_TRADE_STOPS_LEVEL Minimum distance in points from the current close price for setting Stop orders
      int freeze_level;                      // SYMBOL_TRADE_FREEZE_LEVEL Freeze distance for trading operations (in points)
      
      //--- Symbol real properties
      double bid_last;                       // SYMBOL_BID/SYMBOL_LAST Bid - the best sell offer/Last deal price
      double bid_last_high;                  // SYMBOL_BIDHIGH/SYMBOL_LASTHIGH Maximum Bid within the day/Maximum Last per day
      double bid_last_low;                   // SYMBOL_BIDLOW/SYMBOL_LASTLOW Minimum Bid within the day/Minimum Last per day
      double ask;                            // SYMBOL_ASK Ask - nest buy offer
      double ask_high;                       // SYMBOL_ASKHIGH Maximum Ask of the day
      double ask_low;                        // SYMBOL_ASKLOW Minimum Ask of the day
      double volume_real_day;                // SYMBOL_VOLUME_REAL Real Volume of the day
      double volume_high_real_day;           // SYMBOL_VOLUMEHIGH_REAL Maximum real Volume of the day
      double volume_low_real_day;            // SYMBOL_VOLUMELOW_REAL Minimum real Volume of the day
      double option_strike;                  // SYMBOL_OPTION_STRIKE Strike price
      double volume_limit;                   // SYMBOL_VOLUME_LIMIT Maximum permissible total volume for a position and pending orders in one direction
      double swap_long;                      // SYMBOL_SWAP_LONG Long swap value
      double swap_short;                     // SYMBOL_SWAP_SHORT Short swap value
      double session_volume;                 // SYMBOL_SESSION_VOLUME The total volume of deals in the current session
      double session_turnover;               // SYMBOL_SESSION_TURNOVER The total turnover in the current session
      double session_interest;               // SYMBOL_SESSION_INTEREST The total volume of open positions
      double session_buy_ord_volume;         // SYMBOL_SESSION_BUY_ORDERS_VOLUME The total volume of Buy orders at the moment
      double session_sell_ord_volume;        // SYMBOL_SESSION_SELL_ORDERS_VOLUME The total volume of Sell orders at the moment
      double session_open;                   // SYMBOL_SESSION_OPEN Session open price
      double session_close;                  // SYMBOL_SESSION_CLOSE Session close price
      double session_aw;                     // SYMBOL_SESSION_AW The average weighted price of the session
     };
   MqlDataSymbol    m_struct_curr_symbol;    // Current symbol data
   MqlDataSymbol    m_struct_prev_symbol;    // Previous symbol data
//---


Als Nächstes, deklarieren wir Klassenvariablen zum Speichern von spezifizierten kontrollierten Eigenschaftsänderungswerten, aufgetretenen Änderungswerten und Flags, die das Vorhandensein von überwachten Ereignissen: anzeigen.

   //--- Execution
   bool              m_is_change_trade_mode;                   // Flag of changing trading mode for a symbol
   //--- Current session deals
   long              m_control_session_deals_inc;              // Controlled value of the growth of the number of deals
   long              m_control_session_deals_dec;              // Controlled value of the decrease in the number of deals
   long              m_changed_session_deals_value;            // Value of change in the number of deals
   bool              m_is_change_session_deals_inc;            // Flag of a change in the number of deals exceeding the growth value
   bool              m_is_change_session_deals_dec;            // Flag of a change in the number of deals exceeding the decrease value
   //--- Buy orders of the current session
   long              m_control_session_buy_ord_inc;            // Controlled value of the growth of the number of Buy orders
   long              m_control_session_buy_ord_dec;            // Controlled value of the decrease in the number of Buy orders
   long              m_changed_session_buy_ord_value;          // Buy orders change value
   bool              m_is_change_session_buy_ord_inc;          // Flag of a change in the number of Buy orders exceeding the growth value
   bool              m_is_change_session_buy_ord_dec;          // Flag of a change in the number of Buy orders being less than the growth value
   //--- Sell orders of the current session
   long              m_control_session_sell_ord_inc;           // Controlled value of the growth of the number of Sell orders
   long              m_control_session_sell_ord_dec;           // Controlled value of the decrease in the number of Sell orders
   long              m_changed_session_sell_ord_value;         // Sell orders change value
   bool              m_is_change_session_sell_ord_inc;         // Flag of a change in the number of Sell orders exceeding the growth value
   bool              m_is_change_session_sell_ord_dec;         // Flag of a change in the number of Sell orders exceeding the decrease value
   //--- Volume of the last deal
   long              m_control_volume_inc;                     // Controlled value of the volume growth in the last deal
   long              m_control_volume_dec;                     // Controlled value of the volume decrease in the last deal
   long              m_changed_volume_value;                   // Value of the volume change in the last deal
   bool              m_is_change_volume_inc;                   // Flag of the volume change in the last deal exceeding the growth value
   bool              m_is_change_volume_dec;                   // Flag of the volume change in the last deal being less than the growth value
   //--- Maximum volume within a day
   long              m_control_volume_high_day_inc;            // Controlled value of the maximum volume growth for a day
   long              m_control_volume_high_day_dec;            // Controlled value of the maximum volume decrease for a day
   long              m_changed_volume_high_day_value;          // Maximum volume change value within a day
   bool              m_is_change_volume_high_day_inc;          // Flag of the maximum day volume exceeding the growth value
   bool              m_is_change_volume_high_day_dec;          // Flag of the maximum day volume exceeding the decrease value
   //--- Minimum volume within a day
   long              m_control_volume_low_day_inc;             // Controlled value of the minimum volume growth for a day
   long              m_control_volume_low_day_dec;             // Controlled value of the minimum volume decrease for a day
   long              m_changed_volume_low_day_value;           // Minimum volume change value within a day
   bool              m_is_change_volume_low_day_inc;           // Flag of the minimum day volume exceeding the growth value
   bool              m_is_change_volume_low_day_dec;           // Flag of the minimum day volume exceeding the decrease value
   //--- Spread
   int               m_control_spread_inc;                     // Controlled spread growth value in points
   int               m_control_spread_dec;                     // Controlled spread decrease value in points
   int               m_changed_spread_value;                   // Spread change value in points
   bool              m_is_change_spread_inc;                   // Flag of spread change in points exceeding the growth value
   bool              m_is_change_spread_dec;                   // Flag of spread change in points exceeding the decrease value
   //--- StopLevel
   int               m_control_stops_level_inc;                // Controlled StopLevel growth value in points
   int               m_control_stops_level_dec;                // Controlled StopLevel decrease value in points
   int               m_changed_stops_level_value;              // StopLevel change value in points
   bool              m_is_change_stops_level_inc;              // Flag of StopLevel change in points exceeding the growth value
   bool              m_is_change_stops_level_dec;              // Flag of StopLevel change in points exceeding the decrease value
   //--- Freeze distance
   int               m_control_freeze_level_inc;               // Controlled FreezeLevel growth value in points
   int               m_control_freeze_level_dec;               // Controlled FreezeLevel decrease value in points
   int               m_changed_freeze_level_value;             // FreezeLevel change value in points
   bool              m_is_change_freeze_level_inc;             // Flag of FreezeLevel change in points exceeding the growth value
   bool              m_is_change_freeze_level_dec;             // Flag of FreezeLevel change in points exceeding the decrease value
   
   //--- Bid/Last
   double            m_control_bid_last_inc;                   // Controlled value of Bid or Last price growth
   double            m_control_bid_last_dec;                   // Controlled value of Bid or Last price decrease
   double            m_changed_bid_last_value;                 // Bid or Last price change value
   bool              m_is_change_bid_last_inc;                 // Flag of Bid or Last price change exceeding the growth value
   bool              m_is_change_bid_last_dec;                 // Flag of Bid or Last price change exceeding the decrease value
   //--- Maximum Bid/Last of the day
   double            m_control_bid_last_high_inc;              // Controlled growth value of the maximum Bid or Last price of the day
   double            m_control_bid_last_high_dec;              // Controlled decrease value of the maximum Bid or Last price of the day
   double            m_changed_bid_last_high_value;            // Maximum Bid or Last change value for the day
   bool              m_is_change_bid_last_high_inc;            // Flag of the maximum Bid or Last price change for the day exceeding the growth value
   bool              m_is_change_bid_last_high_dec;            // Flag of the maximum Bid or Last price change for the day exceeding the decrease value
   //--- Minimum Bid/Last of the day
   double            m_control_bid_last_low_inc;               // Controlled growth value of the minimum Bid or Last price of the day
   double            m_control_bid_last_low_dec;               // Controlled decrease value of the minimum Bid or Last price of the day
   double            m_changed_bid_last_low_value;             // Minimum Bid or Last change value for the day
   bool              m_is_change_bid_last_low_inc;             // Flag of the minimum Bid or Last price change for the day exceeding the growth value
   bool              m_is_change_bid_last_low_dec;             // Flag of the minimum Bid or Last price change for the day exceeding the decrease value
   //--- Ask
   double            m_control_ask_inc;                        // Controlled value of the Ask price growth
   double            m_control_ask_dec;                        // Controlled value of the Ask price decrease
   double            m_changed_ask_value;                      // Ask price change value
   bool              m_is_change_ask_inc;                      // Flag of the Ask price change exceeding the growth value
   bool              m_is_change_ask_dec;                      // Flag of the Ask price change exceeding the decrease value
   //--- Maximum Ask price for the day
   double            m_control_ask_high_inc;                   // Controlled growth value of the maximum Ask price of the day
   double            m_control_ask_high_dec;                   // Controlled decrease value of the maximum Ask price of the day
   double            m_changed_ask_high_value;                 // Maximum Ask price change value for the day
   bool              m_is_change_ask_high_inc;                 // Flag of the maximum Ask price change for the day exceeding the growth value
   bool              m_is_change_ask_high_dec;                 // Flag of the maximum Ask price change for the day exceeding the decrease value
   //--- Minimum Ask price for the day
   double            m_control_ask_low_inc;                    // Controlled growth value of the minimum Ask price of the day
   double            m_control_ask_low_dec;                    // Controlled decrease value of the minimum Ask price of the day
   double            m_changed_ask_low_value;                  // Minimum Ask price change value for the day
   bool              m_is_change_ask_low_inc;                  // Flag of the minimum Ask price change for the day exceeding the growth value
   bool              m_is_change_ask_low_dec;                  // Flag of the minimum Ask price change for the day exceeding the decrease value
   //--- Real Volume for the day
   double            m_control_volume_real_inc;                // Controlled value of the real volume growth of the day
   double            m_control_volume_real_dec;                // Controlled value of the real volume decrease of the day
   double            m_changed_volume_real_value;              // Real volume change value of the day
   bool              m_is_change_volume_real_inc;              // Flag of the real volume change for the day exceeding the growth value
   bool              m_is_change_volume_real_dec;              // Flag of the real volume change for the day exceeding the decrease value
   //--- Maximum real volume for the day
   double            m_control_volume_high_real_day_inc;       // Controlled value of the maximum real volume growth of the day
   double            m_control_volume_high_real_day_dec;       // Controlled value of the maximum real volume decrease of the day
   double            m_changed_volume_high_real_day_value;     // Maximum real volume change value of the day
   bool              m_is_change_volume_high_real_day_inc;     // Flag of the maximum real volume change for the day exceeding the growth value
   bool              m_is_change_volume_high_real_day_dec;     // Flag of the maximum real volume change for the day exceeding the decrease value
   //--- Minimum real volume for the day
   double            m_control_volume_low_real_day_inc;        // Controlled value of the minimum real volume growth of the day
   double            m_control_volume_low_real_day_dec;        // Controlled value of the minimum real volume decrease of the day
   double            m_changed_volume_low_real_day_value;      // Minimum real volume change value of the day
   bool              m_is_change_volume_low_real_day_inc;      // Flag of the minimum real volume change for the day exceeding the growth value
   bool              m_is_change_volume_low_real_day_dec;      // Flag of the minimum real volume change for the day exceeding the decrease value
   //--- Strike price
   double            m_control_option_strike_inc;              // Controlled value of the strike price growth
   double            m_control_option_strike_dec;              // Controlled value of the strike price decrease
   double            m_changed_option_strike_value;            // Strike price change value
   bool              m_is_change_option_strike_inc;            // Flag of the strike price change exceeding the growth value
   bool              m_is_change_option_strike_dec;            // Flag of the strike price change exceeding the decrease value
   //--- Total volume of positions and orders
   double            m_changed_volume_limit_value;             // Minimum total volume change value
   bool              m_is_change_volume_limit_inc;             // Flag of the minimum total volume increase
   bool              m_is_change_volume_limit_dec;             // Flag of the minimum total volume decrease
   //---  Swap long
   double            m_changed_swap_long_value;                // Swap long change value
   bool              m_is_change_swap_long_inc;                // Flag of the swap long increase
   bool              m_is_change_swap_long_dec;                // Flag of the swap long decrease
   //---  Swap short
   double            m_changed_swap_short_value;               // Swap short change value
   bool              m_is_change_swap_short_inc;               // Flag of the swap short increase
   bool              m_is_change_swap_short_dec;               // Flag of the swap short decrease
   //--- The total volume of deals in the current session
   double            m_control_session_volume_inc;             // Controlled value of the total trade volume growth in the current session
   double            m_control_session_volume_dec;             // Controlled value of the total trade volume decrease in the current session
   double            m_changed_session_volume_value;           // The total deal volume change value in the current session
   bool              m_is_change_session_volume_inc;           // Flag of total trade volume change in the current session exceeding the growth value
   bool              m_is_change_session_volume_dec;           // Flag of total trade volume change in the current session exceeding the decrease value
   //--- The total turnover in the current session
   double            m_control_session_turnover_inc;           // Controlled value of the total turnover growth in the current session
   double            m_control_session_turnover_dec;           // Controlled value of the total turnover decrease in the current session
   double            m_changed_session_turnover_value;         // Total turnover change value in the current session
   bool              m_is_change_session_turnover_inc;         // Flag of total turnover change in the current session exceeding the growth value
   bool              m_is_change_session_turnover_dec;         // Flag of total turnover change in the current session exceeding the decrease value
   //--- The total volume of open positions
   double            m_control_session_interest_inc;           // Controlled value of the total open position volume growth in the current session
   double            m_control_session_interest_dec;           // Controlled value of the total open position volume decrease in the current session
   double            m_changed_session_interest_value;         // Change value of the open positions total volume in the current session
   bool              m_is_change_session_interest_inc;         // Flag of total open positions' volume change in the current session exceeding the growth value
   bool              m_is_change_session_interest_dec;         // Flag of total open positions' volume change in the current session exceeding the decrease value
   //--- The total volume of Buy orders at the moment
   double            m_control_session_buy_ord_volume_inc;     // Controlled value of the current total buy order volume growth
   double            m_control_session_buy_ord_volume_dec;     // Controlled value of the current total buy order volume decrease
   double            m_changed_session_buy_ord_volume_value;   // Change value of the current total buy order volume
   bool              m_is_change_session_buy_ord_volume_inc;   // Flag of changing the current total buy orders volume exceeding the growth value
   bool              m_is_change_session_buy_ord_volume_dec;   // Flag of changing the current total buy orders volume exceeding the decrease value
   //--- The total volume of Sell orders at the moment
   double            m_control_session_sell_ord_volume_inc;    // Controlled value of the current total sell order volume growth
   double            m_control_session_sell_ord_volume_dec;    // Controlled value of the current total sell order volume decrease
   double            m_changed_session_sell_ord_volume_value;  // Change value of the current total sell order volume
   bool              m_is_change_session_sell_ord_volume_inc;  // Flag of changing the current total sell orders volume exceeding the growth value
   bool              m_is_change_session_sell_ord_volume_dec;  // Flag of changing the current total sell orders volume exceeding the decrease value
   //--- Session open price
   double            m_control_session_open_inc;               // Controlled value of the session open price growth
   double            m_control_session_open_dec;               // Controlled value of the session open price decrease
   double            m_changed_session_open_value;             // Session open price change value
   bool              m_is_change_session_open_inc;             // Flag of the session open price change exceeding the growth value
   bool              m_is_change_session_open_dec;             // Flag of the session open price change exceeding the decrease value
   //--- Session close price
   double            m_control_session_close_inc;              // Controlled value of the session close price growth
   double            m_control_session_close_dec;              // Controlled value of the session close price decrease
   double            m_changed_session_close_value;            // Session close price change value
   bool              m_is_change_session_close_inc;            // Flag of the session close price change exceeding the growth value
   bool              m_is_change_session_close_dec;            // Flag of the session close price change exceeding the decrease value
   //--- The average weighted session price
   double            m_control_session_aw_inc;                 // Controlled value of the average weighted session price growth
   double            m_control_session_aw_dec;                 // Controlled value of the average weighted session price decrease
   double            m_changed_session_aw_value;               // The average weighted session price change value
   bool              m_is_change_session_aw_inc;               // Flag of the average weighted session price change value exceeding the growth value
   bool              m_is_change_session_aw_dec;               // Flag of the average weighted session price change value exceeding the decrease value
   


Deklarieren Sie im 'private' Bereich die virtuellen Methoden (die bereits in der Basisklasse CBaseObj deklariert sind) für Initialisierung von verfolgten Variablen und Symboleigenschaften, sowie das Verfahren zum Überprüfen der Änderungen in den Eigenschaften, die den Ereigniscode und zurückgeben, wobei die Methode einen Ereignistyp durch ihren Code setzt und in die Ereignisliste schreibt:

//--- Initialize the variables of (1) tracked, (2) controlled symbol data
   virtual void      InitChangesParams(void);
   virtual void      InitControlsParams(void);
//--- Check symbol changes, return a change code
   virtual int       SetEventCode(void);
//--- Set an event type and fill in the event list
   virtual void      SetTypeEvent(void);
   


Schreiben wir seine Implementierung außerhalb des Klassenkörpers.
Das Verfahren zur Initialisierung der verfolgten Symboleigenschaften:

//+------------------------------------------------------------------+
//| Initialize the variables of tracked symbol data                  |
//+------------------------------------------------------------------+
void CSymbol::InitChangesParams(void)
  {
//--- List and code of changes
   this.m_list_events.Clear();                           // Clear the change list
   this.m_list_events.Sort();                            // Sort the change list
//--- Execution
   this.m_is_change_trade_mode=false;                    // Flag of changing trading mode for a symbol
//--- Current session deals
   this.m_changed_session_deals_value=0;                 // Value of change in the number of deals
   this.m_is_change_session_deals_inc=false;             // Flag of a change in the number of deals exceeding the growth value
   this.m_is_change_session_deals_dec=false;             // Flag of a change in the number of deals exceeding the decrease value
//--- Buy orders of the current session
   this.m_changed_session_buy_ord_value=0;               // Buy orders change value
   this.m_is_change_session_buy_ord_inc=false;           // Flag of a change in the number of Buy orders exceeding the growth value
   this.m_is_change_session_buy_ord_dec=false;           // Flag of a change in the number of Buy orders exceeding the decrease value
//--- Sell orders of the current session
   this.m_changed_session_sell_ord_value=0;              // Sell orders change value
   this.m_is_change_session_sell_ord_inc=false;          // Flag of a change in the number of Sell orders exceeding the growth value
   this.m_is_change_session_sell_ord_dec=false;          // Flag of a change in the number of Sell orders exceeding the decrease value
//--- Volume of the last deal
   this.m_changed_volume_value=0;                        // Value of the volume change in the last deal
   this.m_is_change_volume_inc=false;                    // Flag of the volume change in the last deal exceeding the growth value
   this.m_is_change_volume_dec=false;                    // Flag of the volume change in the last deal exceeding the decrease value
//--- Maximum volume within a day
   this.m_changed_volume_high_day_value=0;               // Maximum volume change value within a day
   this.m_is_change_volume_high_day_inc=false;           // Flag of the maximum day volume exceeding the growth value
   this.m_is_change_volume_high_day_dec=false;           // Flag of the maximum day volume exceeding the decrease value
//--- Minimum volume within a day
   this.m_changed_volume_low_day_value=0;                // Minimum volume change value within a day
   this.m_is_change_volume_low_day_inc=false;            // Flag of the minimum day volume exceeding the growth value
   this.m_is_change_volume_low_day_dec=false;            // Flag of the minimum day volume exceeding the decrease value
//--- Spread
   this.m_changed_spread_value=0;                        // Spread change value in points
   this.m_is_change_spread_inc=false;                    // Flag of spread change in points exceeding the growth value
   this.m_is_change_spread_dec=false;                    // Flag of spread change in points exceeding the decrease value
//--- StopLevel
   this.m_changed_stops_level_value=0;                   // StopLevel change value in points
   this.m_is_change_stops_level_inc=false;               // Flag of StopLevel change in points exceeding the growth value
   this.m_is_change_stops_level_dec=false;               // Flag of StopLevel change in points exceeding the decrease value
//--- Freeze distance
   this.m_changed_freeze_level_value=0;                  // FreezeLevel change value in points
   this.m_is_change_freeze_level_inc=false;              // Flag of FreezeLevel change in points exceeding the growth value
   this.m_is_change_freeze_level_dec=false;              // Flag of FreezeLevel change in points exceeding the decrease value
   
//--- Bid/Last
   this.m_changed_bid_last_value=0;                      // Bid or Last price change value
   this.m_is_change_bid_last_inc=false;                  // Flag of Bid or Last price change exceeding the growth value
   this.m_is_change_bid_last_dec=false;                  // Flag of Bid or Last price change exceeding the decrease value
//--- Maximum Bid/Last of the day
   this.m_changed_bid_last_high_value=0;                 // Maximum Bid or Last change value for the day
   this.m_is_change_bid_last_high_inc=false;             // Flag of the maximum Bid or Last price change for the day exceeding the growth value
   this.m_is_change_bid_last_high_dec=false;             // Flag of the maximum Bid or Last price change for the day exceeding the decrease value
//--- Minimum Bid/Last of the day
   this.m_changed_bid_last_low_value=0;                  // Minimum Bid or Last change value for the day
   this.m_is_change_bid_last_low_inc=false;              // Flag of the minimum Bid or Last price change for the day exceeding the growth value
   this.m_is_change_bid_last_low_dec=false;              // Flag of the minimum Bid or Last price change for the day exceeding the decrease value
//--- Ask
   this.m_changed_ask_value=0;                           // Ask price change value
   this.m_is_change_ask_inc=false;                       // Flag of the Ask price change exceeding the growth value
   this.m_is_change_ask_dec=false;                       // Flag of the Ask price change exceeding the decrease value
//--- Maximum Ask price for the day
   this.m_changed_ask_high_value=0;                      // Maximum Ask price change value for the day
   this.m_is_change_ask_high_inc=false;                  // Flag of the maximum day Ask exceeding the growth value
   this.m_is_change_ask_high_dec=false;                  // Flag of the maximum day Ask exceeding the decrease value
//--- Minimum Ask price for the day
   this.m_changed_ask_low_value=0;                       // Minimum Ask price change value for the day
   this.m_is_change_ask_low_inc=false;                   // Flag of the minimum Ask volume exceeding the growth value
   this.m_is_change_ask_low_dec=false;                   // Flag of the minimum Ask volume exceeding the decrease value
//--- Real Volume for the day
   this.m_changed_volume_real_value=0;                   // Real volume change value of the day
   this.m_is_change_volume_real_inc=false;               // Flag of the real volume change for the day exceeding the growth value
   this.m_is_change_volume_real_dec=false;               // Flag of the real volume change for the day exceeding the decrease value
//--- Maximum real volume for the day
   this.m_changed_volume_high_real_day_value=0;          // Maximum real volume change value of the day
   this.m_is_change_volume_high_real_day_inc=false;      // Flag of the maximum real volume change for the day exceeding the growth value
   this.m_is_change_volume_high_real_day_dec=false;      // Flag of the maximum real volume change for the day exceeding the decrease value
//--- Minimum real volume for the day
   this.m_changed_volume_low_real_day_value=0;           // Minimum real volume change value of the day
   this.m_is_change_volume_low_real_day_inc=false;       // Flag of the minimum real volume change for the day exceeding the growth value
   this.m_is_change_volume_low_real_day_dec=false;       // Flag of the minimum real volume change for the day exceeding the decrease value
//--- Strike price
   this.m_changed_option_strike_value=0;                 // Strike price change value
   this.m_is_change_option_strike_inc=false;             // Flag of the strike price change exceeding the growth value
   this.m_is_change_option_strike_dec=false;             // Flag of the strike price change exceeding the decrease value
//--- Total volume of positions and orders
   this.m_changed_volume_limit_value=0;                  // Minimum total volume change value
   this.m_is_change_volume_limit_inc=false;              // Flag of the minimum total volume increase
   this.m_is_change_volume_limit_dec=false;              // Flag of the minimum total volume decrease
//---  Swap long
   this.m_changed_swap_long_value=0;                     // Swap long change value
   this.m_is_change_swap_long_inc=false;                 // Flag of the swap long increase
   this.m_is_change_swap_long_dec=false;                 // Flag of the swap long decrease
//---  Swap short
   this.m_changed_swap_short_value=0;                    // Swap short change value
   this.m_is_change_swap_short_inc=false;                // Flag of the swap short increase
   this.m_is_change_swap_short_dec=false;                // Flag of the swap short decrease
//--- The total volume of deals in the current session
   this.m_changed_session_volume_value=0;                // The total deal volume change value in the current session
   this.m_is_change_session_volume_inc=false;            // Flag of total trade volume change in the current session exceeding the growth value
   this.m_is_change_session_volume_dec=false;            // Flag of total trade volume change in the current session exceeding the decrease value
//--- The total turnover in the current session
   this.m_changed_session_turnover_value=0;              // Total turnover change value in the current session
   this.m_is_change_session_turnover_inc=false;          // Flag of total turnover change in the current session exceeding the growth value
   this.m_is_change_session_turnover_dec=false;          // Flag of total turnover change in the current session exceeding the decrease value
//--- The total volume of open positions
   this.m_changed_session_interest_value=0;              // Change value of the open positions total volume in the current session
   this.m_is_change_session_interest_inc=false;          // Flag of total open positions' volume change in the current session exceeding the growth value
   this.m_is_change_session_interest_dec=false;          // Flag of total open positions' volume change in the current session exceeding the decrease value
//--- The total volume of Buy orders at the moment
   this.m_changed_session_buy_ord_volume_value=0;        // Change value of the current total buy order volume
   this.m_is_change_session_buy_ord_volume_inc=false;    // Flag of changing the current total buy orders volume exceeding the growth value
   this.m_is_change_session_buy_ord_volume_dec=false;    // Flag of changing the current total buy orders volume exceeding the decrease value
//--- The total volume of Sell orders at the moment
   this.m_changed_session_sell_ord_volume_value=0;       // Change value of the current total sell order volume
   this.m_is_change_session_sell_ord_volume_inc=false;   // Flag of changing the current total sell orders volume exceeding the growth value
   this.m_is_change_session_sell_ord_volume_dec=false;   // Flag of changing the current total sell orders volume exceeding the decrease value
//--- Session open price
   this.m_changed_session_open_value=0;                  // Session open price change value
   this.m_is_change_session_open_inc=false;              // Flag of the session open price change exceeding the growth value
   this.m_is_change_session_open_dec=false;              // Flag of the session open price change exceeding the decrease value
//--- Session close price
   this.m_changed_session_close_value=0;                 // Session close price change value
   this.m_is_change_session_close_inc=false;             // Flag of the session close price change exceeding the growth value
   this.m_is_change_session_close_dec=false;             // Flag of the session close price change exceeding the decrease value
//--- The average weighted session price
   this.m_changed_session_aw_value=0;                    // The average weighted session price change value
   this.m_is_change_session_aw_inc=false;                // Flag of the average weighted session price change value exceeding the growth value
   this.m_is_change_session_aw_dec=false;                // Flag of the average weighted session price change value exceeding the decrease value
  }
//+------------------------------------------------------------------+


Initialwerte werden einfach den Variablen der verfolgten Symboleigenschaften in der Methode zugewiesen. Dies sind die initialen Variablen, die zuvor im 'private' Abschnitt der Klasse deklariert wurden.

Das Verfahren zum Initialisieren von kontrollierten Werten von Symboleigenschaften:

//+------------------------------------------------------------------+
//| Initialize the variables of controlled symbol data               |
//+------------------------------------------------------------------+
void CSymbol::InitControlsParams(void)
  {
//--- Current session deals
   this.m_control_session_deals_inc=10;                  // Controlled value of the growth of the number of deals
   this.m_control_session_deals_dec=10;                  // Controlled value of the decrease in the number of deals
//--- Buy orders of the current session
   this.m_control_session_buy_ord_inc=10;                // Controlled value of the growth of the number of Buy orders
   this.m_control_session_buy_ord_dec=10;                // Controlled value of the decrease in the number of Buy orders
//--- Sell orders of the current session
   this.m_control_session_sell_ord_inc=10;               // Controlled value of the growth of the number of Sell orders
   this.m_control_session_sell_ord_dec=10;               // Controlled value of the decrease in the number of Sell orders
//--- Volume of the last deal
   this.m_control_volume_inc=10;                         // Controlled value of the volume growth in the last deal
   this.m_control_volume_dec=10;                         // Controlled value of the volume decrease in the last deal
//--- Maximum volume within a day
   this.m_control_volume_high_day_inc=50;                // Controlled value of the maximum volume growth for a day
   this.m_control_volume_high_day_dec=50;                // Controlled value of the maximum volume decrease for a day
//--- Minimum volume within a day
   this.m_control_volume_low_day_inc=50;                 // Controlled value of the minimum volume growth for a day
   this.m_control_volume_low_day_dec=50;                 // Controlled value of the minimum volume decrease for a day
//--- Spread
   this.m_control_spread_inc=2;                          // Controlled spread growth value in points
   this.m_control_spread_dec=2;                          // Controlled spread decrease value in points
//--- StopLevel
   this.m_control_stops_level_inc=2;                     // Controlled StopLevel growth value in points
   this.m_control_stops_level_dec=2;                     // Controlled StopLevel decrease value in points
//--- Freeze distance
   this.m_control_freeze_level_inc=2;                    // Controlled FreezeLevel growth value in points
   this.m_control_freeze_level_dec=2;                    // Controlled FreezeLevel decrease value in points
   
//--- Bid/Last
   this.m_control_bid_last_inc=DBL_MAX;                  // Controlled value of Bid or Last price growth
   this.m_control_bid_last_dec=DBL_MAX;                  // Controlled value of Bid or Last price decrease
//--- Maximum Bid/Last of the day
   this.m_control_bid_last_high_inc=DBL_MAX;             // Controlled growth value of the maximum Bid or Last price of the day
   this.m_control_bid_last_high_dec=DBL_MAX;             // Controlled decrease value of the maximum Bid or Last price of the day
//--- Minimum Bid/Last of the day
   this.m_control_bid_last_low_inc=DBL_MAX;              // Controlled growth value of the minimum Bid or Last price of the day
   this.m_control_bid_last_low_dec=DBL_MAX;              // Controlled decrease value of the minimum Bid or Last price of the day
//--- Ask
   this.m_control_ask_inc=DBL_MAX;                       // Controlled value of the Ask price growth
   this.m_control_ask_dec=DBL_MAX;                       // Controlled value of the Ask price decrease
//--- Maximum Ask price for the day
   this.m_control_ask_high_inc=DBL_MAX;                  // Controlled growth value of the maximum Ask price of the day
   this.m_control_ask_high_dec=DBL_MAX;                  // Controlled decrease value of the maximum Ask price of the day
//--- Minimum Ask price for the day
   this.m_control_ask_low_inc=DBL_MAX;                   // Controlled growth value of the minimum Ask price of the day
   this.m_control_ask_low_dec=DBL_MAX;                   // Controlled decrease value of the minimum Ask price of the day
//--- Real Volume for the day
   this.m_control_volume_real_inc=50;                    // Controlled value of the real volume growth of the day
   this.m_control_volume_real_dec=50;                    // Controlled value of the real volume decrease of the day
//--- Maximum real volume for the day
   this.m_control_volume_high_real_day_inc=20;           // Controlled value of the maximum real volume growth of the day
   this.m_control_volume_high_real_day_dec=20;           // Controlled value of the maximum real volume decrease of the day
//--- Minimum real volume for the day
   this.m_control_volume_low_real_day_inc=10;            // Controlled value of the minimum real volume growth of the day
   this.m_control_volume_low_real_day_dec=10;            // Controlled value of the minimum real volume decrease of the day
//--- Strike price
   this.m_control_option_strike_inc=0;                   // Controlled value of the strike price growth
   this.m_control_option_strike_dec=0;                   // Controlled value of the strike price decrease
//--- The total volume of deals in the current session
   this.m_control_session_volume_inc=10;                 // Controlled value of the total trade volume growth in the current session
   this.m_control_session_volume_dec=10;                 // Controlled value of the total trade volume decrease in the current session
//--- The total turnover in the current session
   this.m_control_session_turnover_inc=1000;             // Controlled value of the total turnover growth in the current session
   this.m_control_session_turnover_dec=500;              // Controlled value of the total turnover decrease in the current session
//--- The total volume of open positions
   this.m_control_session_interest_inc=50;               // Controlled value of the total open position volume growth in the current session
   this.m_control_session_interest_dec=20;               // Controlled value of the total open position volume decrease in the current session
//--- The total volume of Buy orders at the moment
   this.m_control_session_buy_ord_volume_inc=50;         // Controlled value of the current total buy order volume growth
   this.m_control_session_buy_ord_volume_dec=20;         // Controlled value of the current total buy order volume decrease
//--- The total volume of Sell orders at the moment
   this.m_control_session_sell_ord_volume_inc=50;        // Controlled value of the current total sell order volume growth
   this.m_control_session_sell_ord_volume_dec=20;        // Controlled value of the current total sell order volume decrease
//--- Session open price
   this.m_control_session_open_inc=0;                    // Controlled value of the session open price growth
   this.m_control_session_open_dec=0;                    // Controlled value of the session open price decrease
//--- Session close price
   this.m_control_session_close_inc=0;                   // Controlled value of the session close price growth
   this.m_control_session_close_dec=0;                   // Controlled value of the session close price decrease
//--- The average weighted session price
   this.m_control_session_aw_inc=0;                      // Controlled value of the average weighted session price growth
   this.m_control_session_aw_dec=0;                      // Controlled value of the average weighted session price decrease
  }
//+------------------------------------------------------------------+


Initialwerte werden Variablen von kontrollierten Symboleigenschaften in der Methode einfach zugewiesen. Dies sind die initialen Variablen, die zuvor im 'private' Abschnitt der Klasse deklariert wurden. Wenn die Eigenschaften die in den Variablen eingestellten Werte überschreiten, wird ein entsprechendes Kontoereignis erzeugt. Um eine Kontrolle der Eigenschaften zu deaktivieren, sollte der Wert von DBL_MAX seiner Variable zugewiesen werden. Um alle Änderungen zu verfolgen, weisen Sie der Variablen 0 zu.

Die Methode überprüft die aufgetretene Änderung der Symboleigenschaft und gibt den aufgetretenen Änderungscode zurück:

//+------------------------------------------------------------------+
//| Check symbol changes, return a change code                       |
//+------------------------------------------------------------------+
int CSymbol::SetEventCode(void)
  {
   this.m_event_code=SYMBOL_EVENT_FLAG_NO_EVENT;

   if(this.m_struct_curr_symbol.trade_mode!=this.m_struct_prev_symbol.trade_mode)
      this.m_event_code+=SYMBOL_EVENT_FLAG_TRADE_MODE;
   if(this.m_struct_curr_symbol.session_deals!=this.m_struct_prev_symbol.session_deals)
      this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_DEALS;
   if(this.m_struct_curr_symbol.session_buy_orders!=this.m_struct_prev_symbol.session_buy_orders)
      this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_BUY_ORDERS;
   if(this.m_struct_curr_symbol.session_sell_orders!=this.m_struct_prev_symbol.session_sell_orders)
      this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_SELL_ORDERS;
   if(this.m_struct_curr_symbol.volume!=this.m_struct_prev_symbol.volume)
      this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME;
   if(this.m_struct_curr_symbol.volume_high_day!=this.m_struct_prev_symbol.volume_high_day)
      this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME_HIGH_DAY;
   if(this.m_struct_curr_symbol.volume_low_day!=this.m_struct_prev_symbol.volume_low_day)
      this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME_LOW_DAY;
   if(this.m_struct_curr_symbol.spread!=this.m_struct_prev_symbol.spread)
      this.m_event_code+=SYMBOL_EVENT_FLAG_SPREAD;
   if(this.m_struct_curr_symbol.stops_level!=this.m_struct_prev_symbol.stops_level)
      this.m_event_code+=SYMBOL_EVENT_FLAG_STOPLEVEL;
   if(this.m_struct_curr_symbol.freeze_level!=this.m_struct_prev_symbol.freeze_level)
      this.m_event_code+=SYMBOL_EVENT_FLAG_FREEZELEVEL;

   if(this.m_struct_curr_symbol.bid_last!=this.m_struct_prev_symbol.bid_last)
      this.m_event_code+=SYMBOL_EVENT_FLAG_BID_LAST;
   if(this.m_struct_curr_symbol.bid_last_high!=this.m_struct_prev_symbol.bid_last_high)
      this.m_event_code+=SYMBOL_EVENT_FLAG_BID_LAST_HIGH;
   if(this.m_struct_curr_symbol.bid_last_low!=this.m_struct_prev_symbol.bid_last_low)
      this.m_event_code+=SYMBOL_EVENT_FLAG_BID_LAST_LOW;
   if(this.m_struct_curr_symbol.ask!=this.m_struct_prev_symbol.ask)
      this.m_event_code+=SYMBOL_EVENT_FLAG_ASK;
   if(this.m_struct_curr_symbol.ask_high!=this.m_struct_prev_symbol.ask_high)
      this.m_event_code+=SYMBOL_EVENT_FLAG_ASK_HIGH;
   if(this.m_struct_curr_symbol.ask_low!=this.m_struct_prev_symbol.ask_low)
      this.m_event_code+=SYMBOL_EVENT_FLAG_ASK_LOW;
   if(this.m_struct_curr_symbol.volume_real_day!=this.m_struct_prev_symbol.volume_real_day)
      this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME_REAL_DAY;
   if(this.m_struct_curr_symbol.volume_high_real_day!=this.m_struct_prev_symbol.volume_high_real_day)
      this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME_HIGH_REAL_DAY;
   if(this.m_struct_curr_symbol.volume_low_real_day!=this.m_struct_prev_symbol.volume_low_real_day)
      this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME_LOW_REAL_DAY;
   if(this.m_struct_curr_symbol.option_strike!=this.m_struct_prev_symbol.option_strike)
      this.m_event_code+=SYMBOL_EVENT_FLAG_OPTION_STRIKE;
   if(this.m_struct_curr_symbol.volume_limit!=this.m_struct_prev_symbol.volume_limit)
      this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME_LIMIT;
   if(this.m_struct_curr_symbol.swap_long!=this.m_struct_prev_symbol.swap_long)
      this.m_event_code+=SYMBOL_EVENT_FLAG_SWAP_LONG;
   if(this.m_struct_curr_symbol.swap_short!=this.m_struct_prev_symbol.swap_short)
      this.m_event_code+=SYMBOL_EVENT_FLAG_SWAP_SHORT;
   if(this.m_struct_curr_symbol.session_volume!=this.m_struct_prev_symbol.session_volume)
      this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_VOLUME;
   if(this.m_struct_curr_symbol.session_turnover!=this.m_struct_prev_symbol.session_turnover)
      this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_TURNOVER;
   if(this.m_struct_curr_symbol.session_interest!=this.m_struct_prev_symbol.session_interest)
      this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_INTEREST;
   if(this.m_struct_curr_symbol.session_buy_ord_volume!=this.m_struct_prev_symbol.session_buy_ord_volume)
      this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_BUY_ORD_VOLUME;
   if(this.m_struct_curr_symbol.session_sell_ord_volume!=this.m_struct_prev_symbol.session_sell_ord_volume)
      this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_SELL_ORD_VOLUME;
   if(this.m_struct_curr_symbol.session_open!=this.m_struct_prev_symbol.session_open)
      this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_OPEN;
   if(this.m_struct_curr_symbol.session_close!=this.m_struct_prev_symbol.session_close)
      this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_CLOSE;
   if(this.m_struct_curr_symbol.session_aw!=this.m_struct_prev_symbol.session_aw)
      this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_AW;
//---
   return this.m_event_code;
  }
//+------------------------------------------------------------------+


Zunächst wird der Ereigniscode in der Methode zurückgesetzt. Anschließend werden die Werte der kontrollierten Symbolparameter in der aktuellen Datenstruktur mit der vorherigen Datenstruktur verglichen. Wenn die Daten nicht ähnlich sind, wird das entsprechende Flag zum Ereigniscode hinzugefügt.

Die Methode, die einen Ereignistyp festlegt und das aufgetretene Ereignis in die Ereignisliste schreibt:

//+------------------------------------------------------------------+
//| Set a symbol object event type                                   |
//+------------------------------------------------------------------+
void CSymbol::SetTypeEvent(void)
  {
   this.InitChangesParams();
   ENUM_SYMBOL_EVENT event_id=SYMBOL_EVENT_NO_EVENT;
//--- Change of trading modes on a symbol
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_TRADE_MODE))
     {
      event_id=
        (
         this.TradeMode()==SYMBOL_TRADE_MODE_DISABLED  ? SYMBOL_EVENT_TRADE_DISABLE    :
         this.TradeMode()==SYMBOL_TRADE_MODE_LONGONLY  ? SYMBOL_EVENT_TRADE_LONGONLY   :
         this.TradeMode()==SYMBOL_TRADE_MODE_SHORTONLY ? SYMBOL_EVENT_TRADE_SHORTONLY  :
         this.TradeMode()==SYMBOL_TRADE_MODE_CLOSEONLY ? SYMBOL_EVENT_TRADE_CLOSEONLY  :
         SYMBOL_EVENT_TRADE_FULL
        );
      this.m_is_change_trade_mode=true;
      if(this.EventAdd(event_id,this.TickTime(),this.TradeMode(),this.Name()))
         this.m_struct_prev_symbol.trade_mode=this.m_struct_curr_symbol.trade_mode;
     }
//--- Change of the number of deals in the current session
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_DEALS))
     {
      this.m_changed_session_deals_value=this.m_struct_curr_symbol.session_deals-this.m_struct_prev_symbol.session_deals;
      if(this.m_changed_session_deals_value>this.m_control_session_deals_inc)
        {
         this.m_is_change_session_deals_inc=true;
         event_id=SYMBOL_EVENT_SESSION_DEALS_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_deals_value,this.Name()))
            this.m_struct_prev_symbol.session_deals=this.m_struct_curr_symbol.session_deals;
        }
      else if(this.m_changed_session_deals_value<-this.m_control_session_deals_dec)
        {
         this.m_is_change_session_deals_dec=true;
         event_id=SYMBOL_EVENT_SESSION_DEALS_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_deals_value,this.Name()))
            this.m_struct_prev_symbol.session_deals=this.m_struct_curr_symbol.session_deals;
        }
     }
//--- Change of the total number of the current buy orders
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_BUY_ORDERS))
     {
      this.m_changed_session_buy_ord_value=this.m_struct_curr_symbol.session_buy_orders-this.m_struct_prev_symbol.session_buy_orders;
      if(this.m_changed_session_buy_ord_value>this.m_control_session_buy_ord_inc)
        {
         this.m_is_change_session_buy_ord_inc=true;
         event_id=SYMBOL_EVENT_SESSION_BUY_ORDERS_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_buy_ord_value,this.Name()))
            this.m_struct_prev_symbol.session_buy_orders=this.m_struct_curr_symbol.session_buy_orders;
        }
      else if(this.m_changed_session_buy_ord_value<-this.m_control_session_buy_ord_dec)
        {
         this.m_is_change_session_buy_ord_dec=true;
         event_id=SYMBOL_EVENT_SESSION_BUY_ORDERS_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_buy_ord_value,this.Name()))
            this.m_struct_prev_symbol.session_buy_orders=this.m_struct_curr_symbol.session_buy_orders;
        }
     }
//--- Change of the total number of the current sell orders
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_SELL_ORDERS))
     {
      this.m_changed_session_sell_ord_value=this.m_struct_curr_symbol.session_sell_orders-this.m_struct_prev_symbol.session_sell_orders;
      if(this.m_changed_session_sell_ord_value>this.m_control_session_sell_ord_inc)
        {
         this.m_is_change_session_sell_ord_inc=true;
         event_id=SYMBOL_EVENT_SESSION_SELL_ORDERS_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_sell_ord_value,this.Name()))
            this.m_struct_prev_symbol.session_sell_orders=this.m_struct_curr_symbol.session_sell_orders;
        }
      else if(this.m_changed_session_sell_ord_value<-this.m_control_session_sell_ord_dec)
        {
         this.m_is_change_session_sell_ord_dec=true;
         event_id=SYMBOL_EVENT_SESSION_SELL_ORDERS_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_sell_ord_value,this.Name()))
            this.m_struct_prev_symbol.session_sell_orders=this.m_struct_curr_symbol.session_sell_orders;
        }
     }
//--- Volume change in the last deal
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME))
     {
      this.m_changed_volume_value=this.m_struct_curr_symbol.volume-this.m_struct_prev_symbol.volume;
      if(this.m_changed_volume_value>this.m_control_volume_inc)
        {
         this.m_is_change_volume_inc=true;
         event_id=SYMBOL_EVENT_VOLUME_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_value,this.Name()))
            this.m_struct_prev_symbol.volume=this.m_struct_curr_symbol.volume;
        }
      else if(this.m_changed_volume_value<-this.m_control_volume_dec)
        {
         this.m_is_change_volume_dec=true;
         event_id=SYMBOL_EVENT_VOLUME_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_value,this.Name()))
            this.m_struct_prev_symbol.volume=this.m_struct_curr_symbol.volume;
        }
     }
//--- Maximum volume change for a day
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME_HIGH_DAY))
     {
      this.m_changed_volume_high_day_value=this.m_struct_curr_symbol.volume_high_day-this.m_struct_prev_symbol.volume_high_day;
      if(this.m_changed_volume_high_day_value>this.m_control_volume_high_day_inc)
        {
         this.m_is_change_volume_high_day_inc=true;
         event_id=SYMBOL_EVENT_VOLUME_HIGH_DAY_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_high_day_value,this.Name()))
            this.m_struct_prev_symbol.volume_high_day=this.m_struct_curr_symbol.volume_high_day;
        }
      else if(this.m_changed_volume_high_day_value<-this.m_control_volume_high_day_dec)
        {
         this.m_is_change_volume_high_day_dec=true;
         event_id=SYMBOL_EVENT_VOLUME_HIGH_DAY_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_high_day_value,this.Name()))
            this.m_struct_prev_symbol.volume_high_day=this.m_struct_curr_symbol.volume_high_day;
        }
     }
//--- Minimum volume change for a day
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME_LOW_DAY))
     {
      this.m_changed_volume_low_day_value=this.m_struct_curr_symbol.volume_low_day-this.m_struct_prev_symbol.volume_low_day;
      if(this.m_changed_volume_low_day_value>this.m_control_volume_low_day_inc)
        {
         this.m_is_change_volume_low_day_inc=true;
         event_id=SYMBOL_EVENT_VOLUME_LOW_DAY_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_low_day_value,this.Name()))
            this.m_struct_prev_symbol.volume_low_day=this.m_struct_curr_symbol.volume_low_day;
        }
      else if(this.m_changed_volume_low_day_value<-this.m_control_volume_low_day_dec)
        {
         this.m_is_change_volume_low_day_dec=true;
         event_id=SYMBOL_EVENT_VOLUME_LOW_DAY_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_low_day_value,this.Name()))
            this.m_struct_prev_symbol.volume_low_day=this.m_struct_curr_symbol.volume_low_day;
        }
     }
//--- Spread value change in points
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SPREAD))
     {
      this.m_changed_spread_value=this.m_struct_curr_symbol.spread-this.m_struct_prev_symbol.spread;
      if(this.m_changed_spread_value>this.m_control_spread_inc)
        {
         this.m_is_change_spread_inc=true;
         event_id=SYMBOL_EVENT_SPREAD_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_spread_value,this.Name()))
            this.m_struct_prev_symbol.spread=this.m_struct_curr_symbol.spread;
        }
      else if(this.m_changed_spread_value<-this.m_control_spread_dec)
        {
         this.m_is_change_spread_dec=true;
         event_id=SYMBOL_EVENT_SPREAD_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_spread_value,this.Name()))
            this.m_struct_prev_symbol.spread=this.m_struct_curr_symbol.spread;
        }
     }
//--- StopLevel change in points
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_STOPLEVEL))
     {
      this.m_changed_stops_level_value=this.m_struct_curr_symbol.stops_level-this.m_struct_prev_symbol.stops_level;
      if(this.m_changed_stops_level_value>this.m_control_stops_level_inc)
        {
         this.m_is_change_stops_level_inc=true;
         event_id=SYMBOL_EVENT_STOPLEVEL_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_stops_level_value,this.Name()))
            this.m_struct_prev_symbol.stops_level=this.m_struct_curr_symbol.stops_level;
        }
      else if(this.m_changed_stops_level_value<-this.m_control_stops_level_dec)
        {
         this.m_is_change_stops_level_dec=true;
         event_id=SYMBOL_EVENT_STOPLEVEL_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_stops_level_value,this.Name()))
            this.m_struct_prev_symbol.stops_level=this.m_struct_curr_symbol.stops_level;
        }
     }
//--- FreezeLevel change in points
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_FREEZELEVEL))
     {
      this.m_changed_freeze_level_value=this.m_struct_curr_symbol.freeze_level-this.m_struct_prev_symbol.freeze_level;
      if(this.m_changed_freeze_level_value>this.m_control_freeze_level_inc)
        {
         this.m_is_change_freeze_level_inc=true;
         event_id=SYMBOL_EVENT_FREEZELEVEL_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_freeze_level_value,this.Name()))
            this.m_struct_prev_symbol.freeze_level=this.m_struct_curr_symbol.freeze_level;
        }
      else if(this.m_changed_freeze_level_value<-this.m_control_freeze_level_dec)
        {
         this.m_is_change_freeze_level_dec=true;
         event_id=SYMBOL_EVENT_FREEZELEVEL_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_freeze_level_value,this.Name()))
            this.m_struct_prev_symbol.freeze_level=this.m_struct_curr_symbol.freeze_level;
        }
     }
//--- Bid/Last price change
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_BID_LAST))
     {
      this.m_changed_bid_last_value=this.m_struct_curr_symbol.bid_last-this.m_struct_prev_symbol.bid_last;
      if(this.m_changed_bid_last_value>this.m_control_bid_last_inc)
        {
         this.m_is_change_bid_last_inc=true;
         event_id=SYMBOL_EVENT_BID_LAST_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_bid_last_value,this.Name()))
            this.m_struct_prev_symbol.bid_last=this.m_struct_curr_symbol.bid_last;
        }
      else if(this.m_changed_bid_last_value<-this.m_control_bid_last_dec)
        {
         this.m_is_change_bid_last_dec=true;
         event_id=SYMBOL_EVENT_BID_LAST_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_bid_last_value,this.Name()))
            this.m_struct_prev_symbol.bid_last=this.m_struct_curr_symbol.bid_last;
        }
     }
//--- Maximum Bid/Last change for a day
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_BID_LAST_HIGH))
     {
      this.m_changed_bid_last_high_value=this.m_struct_curr_symbol.bid_last_high-this.m_struct_prev_symbol.bid_last_high;
      if(this.m_changed_bid_last_high_value>this.m_control_bid_last_high_inc)
        {
         this.m_is_change_bid_last_high_inc=true;
         event_id=SYMBOL_EVENT_BID_LAST_HIGH_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_bid_last_high_value,this.Name()))
            this.m_struct_prev_symbol.bid_last_high=this.m_struct_curr_symbol.bid_last_high;
        }
      else if(this.m_changed_bid_last_high_value<-this.m_control_bid_last_high_dec)
        {
         this.m_is_change_bid_last_high_dec=true;
         event_id=SYMBOL_EVENT_BID_LAST_HIGH_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_bid_last_high_value,this.Name()))
            this.m_struct_prev_symbol.bid_last_high=this.m_struct_curr_symbol.bid_last_high;
        }
     }
//--- Minimum Bid/Last change for a day
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_BID_LAST_LOW))
     {
      this.m_changed_bid_last_low_value=this.m_struct_curr_symbol.bid_last_low-this.m_struct_prev_symbol.bid_last_low;
      if(this.m_changed_bid_last_low_value>this.m_control_bid_last_low_inc)
        {
         this.m_is_change_bid_last_low_inc=true;
         event_id=SYMBOL_EVENT_BID_LAST_LOW_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_bid_last_low_value,this.Name()))
            this.m_struct_prev_symbol.bid_last_low=this.m_struct_curr_symbol.bid_last_low;
        }
      else if(this.m_changed_bid_last_low_value<-this.m_control_bid_last_low_dec)
        {
         this.m_is_change_bid_last_low_dec=true;
         event_id=SYMBOL_EVENT_BID_LAST_LOW_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_bid_last_low_value,this.Name()))
            this.m_struct_prev_symbol.bid_last_low=this.m_struct_curr_symbol.bid_last_low;
        }
     }
//--- Ask price change
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_ASK))
     {
      this.m_changed_ask_value=this.m_struct_curr_symbol.ask-this.m_struct_prev_symbol.ask;
      if(this.m_changed_ask_value>this.m_control_ask_inc)
        {
         this.m_is_change_ask_inc=true;
         event_id=SYMBOL_EVENT_ASK_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_ask_value,this.Name()))
            this.m_struct_prev_symbol.ask=this.m_struct_curr_symbol.ask;
        }
      else if(this.m_changed_ask_value<-this.m_control_ask_dec)
        {
         this.m_is_change_ask_dec=true;
         event_id=SYMBOL_EVENT_ASK_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_ask_value,this.Name()))
            this.m_struct_prev_symbol.ask=this.m_struct_curr_symbol.ask;
        }
     }
//--- Maximum As change for a day
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_ASK_HIGH))
     {
      this.m_changed_ask_high_value=this.m_struct_curr_symbol.ask_high-this.m_struct_prev_symbol.ask_high;
      if(this.m_changed_ask_high_value>this.m_control_ask_high_inc)
        {
         this.m_is_change_ask_high_inc=true;
         event_id=SYMBOL_EVENT_ASK_HIGH_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_ask_high_value,this.Name()))
            this.m_struct_prev_symbol.ask_high=this.m_struct_curr_symbol.ask_high;
        }
      else if(this.m_changed_ask_high_value<-this.m_control_ask_high_dec)
        {
         this.m_is_change_ask_high_dec=true;
         event_id=SYMBOL_EVENT_ASK_HIGH_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_ask_high_value,this.Name()))
            this.m_struct_prev_symbol.ask_high=this.m_struct_curr_symbol.ask_high;
        }
     }
//--- Minimum Ask change for a day
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_ASK_LOW))
     {
      this.m_changed_ask_low_value=this.m_struct_curr_symbol.ask_low-this.m_struct_prev_symbol.ask_low;
      if(this.m_changed_ask_low_value>this.m_control_ask_low_inc)
        {
         this.m_is_change_ask_low_inc=true;
         event_id=SYMBOL_EVENT_ASK_LOW_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_ask_low_value,this.Name()))
            this.m_struct_prev_symbol.ask_low=this.m_struct_curr_symbol.ask_low;
        }
      else if(this.m_changed_ask_low_value<-this.m_control_ask_low_dec)
        {
         this.m_is_change_ask_low_dec=true;
         event_id=SYMBOL_EVENT_ASK_LOW_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_ask_low_value,this.Name()))
            this.m_struct_prev_symbol.ask_low=this.m_struct_curr_symbol.ask_low;
        }
     }
//--- Real volume change for a day
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME_REAL_DAY))
     {
      this.m_changed_volume_real_value=this.m_struct_curr_symbol.volume_real_day-this.m_struct_prev_symbol.volume_real_day;
      if(this.m_changed_volume_real_value>this.m_control_volume_real_inc)
        {
         this.m_is_change_volume_real_inc=true;
         event_id=SYMBOL_EVENT_VOLUME_REAL_DAY_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_real_value,this.Name()))
            this.m_struct_prev_symbol.volume_real_day=this.m_struct_curr_symbol.volume_real_day;
        }
      else if(this.m_changed_volume_real_value<-this.m_control_volume_real_dec)
        {
         this.m_is_change_volume_real_dec=true;
         event_id=SYMBOL_EVENT_VOLUME_REAL_DAY_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_real_value,this.Name()))
            this.m_struct_prev_symbol.volume_real_day=this.m_struct_curr_symbol.volume_real_day;
        }
     }
//--- Maximum real volume change for a day
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME_HIGH_REAL_DAY))
     {
      this.m_changed_volume_high_real_day_value=this.m_struct_curr_symbol.volume_high_real_day-this.m_struct_prev_symbol.volume_high_real_day;
      if(this.m_changed_volume_high_real_day_value>this.m_control_volume_high_real_day_inc)
        {
         this.m_is_change_volume_high_real_day_inc=true;
         event_id=SYMBOL_EVENT_VOLUME_HIGH_REAL_DAY_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_high_real_day_value,this.Name()))
            this.m_struct_prev_symbol.volume_high_real_day=this.m_struct_curr_symbol.volume_high_real_day;
        }
      else if(this.m_changed_volume_high_real_day_value<-this.m_control_volume_high_real_day_dec)
        {
         this.m_is_change_volume_high_real_day_dec=true;
         event_id=SYMBOL_EVENT_VOLUME_HIGH_REAL_DAY_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_high_real_day_value,this.Name()))
            this.m_struct_prev_symbol.volume_high_real_day=this.m_struct_curr_symbol.volume_high_real_day;
        }
     }
//--- Minimum real volume change for a day
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME_LOW_REAL_DAY))
     {
      this.m_changed_volume_low_real_day_value=this.m_struct_curr_symbol.volume_low_real_day-this.m_struct_prev_symbol.volume_low_real_day;
      if(this.m_changed_volume_low_real_day_value>this.m_control_volume_low_real_day_inc)
        {
         this.m_is_change_volume_low_real_day_inc=true;
         event_id=SYMBOL_EVENT_VOLUME_LOW_REAL_DAY_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_low_real_day_value,this.Name()))
            this.m_struct_prev_symbol.volume_low_real_day=this.m_struct_curr_symbol.volume_low_real_day;
        }
      else if(this.m_changed_volume_low_real_day_value<-this.m_control_volume_low_real_day_dec)
        {
         this.m_is_change_volume_low_real_day_dec=true;
         event_id=SYMBOL_EVENT_VOLUME_LOW_REAL_DAY_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_low_real_day_value,this.Name()))
            this.m_struct_prev_symbol.volume_low_real_day=this.m_struct_curr_symbol.volume_low_real_day;
        }
     }
//--- Strike price change
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_OPTION_STRIKE))
     {
      this.m_changed_option_strike_value=this.m_struct_curr_symbol.option_strike-this.m_struct_prev_symbol.option_strike;
      if(this.m_changed_option_strike_value>this.m_control_option_strike_inc)
        {
         this.m_is_change_option_strike_inc=true;
         event_id=SYMBOL_EVENT_OPTION_STRIKE_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_option_strike_value,this.Name()))
            this.m_struct_prev_symbol.option_strike=this.m_struct_curr_symbol.option_strike;
        }
      else if(this.m_changed_option_strike_value<-this.m_control_option_strike_dec)
        {
         this.m_is_change_option_strike_dec=true;
         event_id=SYMBOL_EVENT_OPTION_STRIKE_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_option_strike_value,this.Name()))
            this.m_struct_prev_symbol.option_strike=this.m_struct_curr_symbol.option_strike;
        }
     }
//--- Change of the maximum available total position volume and pending orders in one direction
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME_LIMIT))
     {
      this.m_changed_volume_limit_value=this.m_struct_curr_symbol.volume_limit-this.m_struct_prev_symbol.volume_limit;
      if(this.m_changed_volume_limit_value>0)
        {
         this.m_is_change_volume_limit_inc=true;
         event_id=SYMBOL_EVENT_VOLUME_LIMIT_INC;
        }
      else
        {
         this.m_is_change_volume_limit_dec=true;
         event_id=SYMBOL_EVENT_VOLUME_LIMIT_DEC;
        }
      if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_limit_value,this.Name()))
         this.m_struct_prev_symbol.volume_limit=this.m_struct_curr_symbol.volume_limit;
     }
//--- Swap long change
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SWAP_LONG))
     {
      this.m_changed_swap_long_value=this.m_struct_curr_symbol.swap_long-this.m_struct_prev_symbol.swap_long;
      if(this.m_changed_swap_long_value>0)
        {
         this.m_is_change_swap_long_inc=true;
         event_id=SYMBOL_EVENT_SWAP_LONG_INC;
        }
      else
        {
         this.m_is_change_swap_long_dec=true;
         event_id=SYMBOL_EVENT_SWAP_LONG_DEC;
        }
      if(this.EventAdd(event_id,this.TickTime(),this.m_changed_swap_long_value,this.Name()))
         this.m_struct_prev_symbol.swap_long=this.m_struct_curr_symbol.swap_long;
     }
//--- Swap short change
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SWAP_SHORT))
     {
      this.m_changed_swap_short_value=this.m_struct_curr_symbol.swap_short-this.m_struct_prev_symbol.swap_short;
      if(this.m_changed_swap_short_value>0)
        {
         this.m_is_change_swap_short_inc=true;
         event_id=SYMBOL_EVENT_SWAP_SHORT_INC;
        }
      else
        {
         this.m_is_change_swap_short_dec=true;
         event_id=SYMBOL_EVENT_SWAP_SHORT_DEC;
        }
      if(this.EventAdd(event_id,this.TickTime(),this.m_changed_swap_short_value,this.Name()))
         this.m_struct_prev_symbol.swap_short=this.m_struct_curr_symbol.swap_short;
     }
//--- Change of the total volume of deals during the current session
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_VOLUME))
     {
      this.m_changed_session_volume_value=this.m_struct_curr_symbol.session_volume-this.m_struct_prev_symbol.session_volume;
      if(this.m_changed_session_volume_value>this.m_control_session_volume_inc)
        {
         this.m_is_change_session_volume_inc=true;
         event_id=SYMBOL_EVENT_SESSION_VOLUME_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_volume_value,this.Name()))
            this.m_struct_prev_symbol.session_volume=this.m_struct_curr_symbol.session_volume;
        }
      else if(this.m_changed_session_volume_value<-this.m_control_session_volume_dec)
        {
         this.m_is_change_session_volume_dec=true;
         event_id=SYMBOL_EVENT_SESSION_VOLUME_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_volume_value,this.Name()))
            this.m_struct_prev_symbol.session_volume=this.m_struct_curr_symbol.session_volume;
        }
     }
//--- Change of the total turnover during the current session
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_TURNOVER))
     {
      this.m_changed_session_turnover_value=this.m_struct_curr_symbol.session_turnover-this.m_struct_prev_symbol.session_turnover;
      if(this.m_changed_session_turnover_value>this.m_control_session_turnover_inc)
        {
         this.m_is_change_session_turnover_inc=true;
         event_id=SYMBOL_EVENT_SESSION_TURNOVER_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_turnover_value,this.Name()))
            this.m_struct_prev_symbol.session_turnover=this.m_struct_curr_symbol.session_turnover;
        }
      else if(this.m_changed_session_turnover_value<-this.m_control_session_turnover_dec)
        {
         this.m_is_change_session_turnover_dec=true;
         event_id=SYMBOL_EVENT_SESSION_TURNOVER_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_turnover_value,this.Name()))
            this.m_struct_prev_symbol.session_turnover=this.m_struct_curr_symbol.session_turnover;
        }
     }
//--- Change of the total volume of open positions during the current session
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_INTEREST))
     {
      this.m_changed_session_interest_value=this.m_struct_curr_symbol.session_interest-this.m_struct_prev_symbol.session_interest;
      if(this.m_changed_session_interest_value>this.m_control_session_interest_inc)
        {
         this.m_is_change_session_interest_inc=true;
         event_id=SYMBOL_EVENT_SESSION_INTEREST_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_interest_value,this.Name()))
            this.m_struct_prev_symbol.session_interest=this.m_struct_curr_symbol.session_interest;
        }
      else if(this.m_changed_session_interest_value<-this.m_control_session_interest_dec)
        {
         this.m_is_change_session_interest_dec=true;
         event_id=SYMBOL_EVENT_SESSION_INTEREST_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_interest_value,this.Name()))
            this.m_struct_prev_symbol.session_interest=this.m_struct_curr_symbol.session_interest;
        }
     }
//--- Change of the current total volume of buy orders
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_BUY_ORD_VOLUME))
     {
      this.m_changed_session_buy_ord_volume_value=this.m_struct_curr_symbol.session_buy_ord_volume-this.m_struct_prev_symbol.session_buy_ord_volume;
      if(this.m_changed_session_buy_ord_volume_value>this.m_control_session_buy_ord_volume_inc)
        {
         this.m_is_change_session_buy_ord_volume_inc=true;
         event_id=SYMBOL_EVENT_SESSION_BUY_ORD_VOLUME_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_buy_ord_volume_value,this.Name()))
            this.m_struct_prev_symbol.session_buy_ord_volume=this.m_struct_curr_symbol.session_buy_ord_volume;
        }
      else if(this.m_changed_session_buy_ord_volume_value<-this.m_control_session_buy_ord_volume_dec)
        {
         this.m_is_change_session_buy_ord_volume_dec=true;
         event_id=SYMBOL_EVENT_SESSION_BUY_ORD_VOLUME_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_buy_ord_volume_value,this.Name()))
            this.m_struct_prev_symbol.session_buy_ord_volume=this.m_struct_curr_symbol.session_buy_ord_volume;
        }
     }
//--- Change of the current total volume of sell orders
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_SELL_ORD_VOLUME))
     {
      this.m_changed_session_sell_ord_volume_value=this.m_struct_curr_symbol.session_sell_ord_volume-this.m_struct_prev_symbol.session_sell_ord_volume;
      if(this.m_changed_session_sell_ord_volume_value>this.m_control_session_sell_ord_volume_inc)
        {
         this.m_is_change_session_sell_ord_volume_inc=true;
         event_id=SYMBOL_EVENT_SESSION_SELL_ORD_VOLUME_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_sell_ord_volume_value,this.Name()))
            this.m_struct_prev_symbol.session_sell_ord_volume=this.m_struct_curr_symbol.session_sell_ord_volume;
        }
      else if(this.m_changed_session_sell_ord_volume_value<-this.m_control_session_sell_ord_volume_dec)
        {
         this.m_is_change_session_sell_ord_volume_dec=true;
         event_id=SYMBOL_EVENT_SESSION_SELL_ORD_VOLUME_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_sell_ord_volume_value,this.Name()))
            this.m_struct_prev_symbol.session_sell_ord_volume=this.m_struct_curr_symbol.session_sell_ord_volume;
        }
     }
//--- Session open price change
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_OPEN))
     {
      this.m_changed_session_open_value=this.m_struct_curr_symbol.session_open-this.m_struct_prev_symbol.session_open;
      if(this.m_changed_session_open_value>this.m_control_session_open_inc)
        {
         this.m_is_change_session_open_inc=true;
         event_id=SYMBOL_EVENT_SESSION_OPEN_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_open_value,this.Name()))
            this.m_struct_prev_symbol.session_open=this.m_struct_curr_symbol.session_open;
        }
      else if(this.m_changed_session_open_value<-this.m_control_session_open_dec)
        {
         this.m_is_change_session_open_dec=true;
         event_id=SYMBOL_EVENT_SESSION_OPEN_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_open_value,this.Name()))
            this.m_struct_prev_symbol.session_open=this.m_struct_curr_symbol.session_open;
        }
     }
//--- Session close price change
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_CLOSE))
     {
      this.m_changed_session_close_value=this.m_struct_curr_symbol.session_close-this.m_struct_prev_symbol.session_close;
      if(this.m_changed_session_close_value>this.m_control_session_close_inc)
        {
         this.m_is_change_session_close_inc=true;
         event_id=SYMBOL_EVENT_SESSION_CLOSE_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_close_value,this.Name()))
            this.m_struct_prev_symbol.session_close=this.m_struct_curr_symbol.session_close;
        }
      else if(this.m_changed_session_close_value<-this.m_control_session_close_dec)
        {
         this.m_is_change_session_close_dec=true;
         event_id=SYMBOL_EVENT_SESSION_CLOSE_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_close_value,this.Name()))
            this.m_struct_prev_symbol.session_close=this.m_struct_curr_symbol.session_close;
        }
     }
//--- Average weighted session price change
   if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_AW))
     {
      this.m_changed_session_aw_value=this.m_struct_curr_symbol.session_aw-this.m_struct_prev_symbol.session_aw;
      if(this.m_changed_session_aw_value>this.m_control_session_aw_inc)
        {
         this.m_is_change_session_aw_inc=true;
         event_id=SYMBOL_EVENT_SESSION_AW_INC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_aw_value,this.Name()))
            this.m_struct_prev_symbol.session_aw=this.m_struct_curr_symbol.session_aw;
        }
      else if(this.m_changed_session_aw_value<-this.m_control_session_aw_dec)
        {
         this.m_is_change_session_aw_dec=true;
         event_id=SYMBOL_EVENT_SESSION_AW_DEC;
         if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_aw_value,this.Name()))
            this.m_struct_prev_symbol.session_aw=this.m_struct_curr_symbol.session_aw;
        }
     }
  }
//+------------------------------------------------------------------+


Die Methode ist aufgrund der Blöcke identischer Prüfungen von Änderungen in den verfolgten Symboleigenschaften ziemlich "sperrig". Im Teil 13 haben wir bereits eine ähnliche Methode zur Verfolgung von Kontoänderungen berücksichtigt. Hier ist die Logik ähnlich, nur dass sich die gesamte Funktionalität der Speicherereignisse nun im Basisobjekt CBaseObj befindet.
Lassen Sie es uns am Beispiel der Änderung des durchschnittlichen gewichteten Sitzungspreises betrachten.
Setzen Sie gleich zu Beginn der Methode die Werte der verfolgten Eigenschaften mit der Methode InitChangesParams() zurück und setzen Sie den Ereignisstatus auf "No event".

  • Überprüfen Sie mit der Methode IsPresentEventFlag(), die sich ebenfalls im Basisobjekt befindet, ob das Flag der Symbolwertänderung SYMBOL_SESSION_AW im Ereigniscode vorhanden ist, der in der Variablen m_event_code gesetzt ist.
    Wenn das Flag der geprüften Wertänderung im Ereigniscode vorhanden ist,
    • berechnen Sie den Eigenschaftswert und prüfen Sie, ob der Wert den kontrollierten überschreitet.
      • Wenn der berechnete Wert den kontrollierten überschreitet,
        • setzen Sie das Flag des gewichteten Durchschnittspreisereignisses,
        • schreiben Sie auf die Ereignis-ID "durchschnittliche gewichtete Preiserhöhung" und
        • rufen Sie die Methode zum Hinzufügen des Ereignisses mit EventAdd() zur Liste der Basisklasse CBaseObj auf.
          Wenn das Ereignis erfolgreich zur Liste hinzugefügt wurde,
          • speichern Sie den aktuellen Eigenschaftswert als vorherigen Wert für eine weitere Überprüfung.
Um den Fall einer Verminderung des Eigenschaftswertes zu registrieren, werden alle Prüfungen auf die gleiche Weise durchgeführt. Der einzige Unterschied besteht darin, dass wir den Wert überprüfen, der unter den kontrollierten Wert fällt.
Senden Sie die Daten an die Methode zum Hinzufügen eines Ereignisses zur Liste EventAdd():
  1. event-ID (event_id beim Überprüfen des Events gefüllt)
  2. die aktuelle Zeit in Millisekunden (TickTime() Methode der Basisklasse CBaseObj)
  3. berechneter Wert, um den sich die Symboleigenschaft geändert hat (m_changed_session_aw_value)
  4. Objektname (hier ist es der Symbolname)

Nehmen wir auch eine kleine Änderung am Konstruktor der geschützten Klasse vor: Um die neue Eigenschaft "Symbolindex im Fenster der Marktübersicht" des Objektsymbols auszufüllen, müssen wir diesen Index beim Scannen von Market Watch-Symbolen übergeben. Der Index ist direkt an den Klassenkonstruktor zu übergeben:

protected:
//--- 'Protected' Konstruktor
                     CSymbol(ENUM_SYMBOL_STATUS symbol_status,const string name,const int index);


Fügen Sie im gleichen 'protected' Klassenabschnitt noch eine weitere Methode hinzu, die die Anzahl der Dezimalstellen durch die Methode für die Swap-Kosten zurückgibt:

//--- Get and return integer properties of a selected symbol from its parameters
   bool              SymbolExists(const string name)     const;
   long              SymbolExists(void)                  const;
   long              SymbolCustom(void)                  const;
   long              SymbolChartMode(void)               const;
   long              SymbolMarginHedgedUseLEG(void)      const;
   long              SymbolOrderFillingMode(void)        const;
   long              SymbolOrderMode(void)               const;
   long              SymbolExpirationMode(void)          const;
   long              SymbolOrderGTCMode(void)            const;
   long              SymbolOptionMode(void)              const;
   long              SymbolOptionRight(void)             const;
   long              SymbolBackgroundColor(void)         const;
   long              SymbolCalcMode(void)                const;
   long              SymbolSwapMode(void)                const;
   long              SymbolDigitsLot(void);
   int               SymbolDigitsBySwap(void);
//--- Get and return real properties of a selected symbol from its parameters


Swaps werden in Geld, Punkten und Prozentsatz berechnet. Für jede dieser Typen der Kosten für die Swaps müssen wir die entsprechende Anzahl von Dezimalstellen zurückgeben. Das ist genau das, was die Methode tut. Schreiben wir sie außerhalb des Klassenkörpers:

//+------------------------------------------------------------------+
//| Return the number of decimal places                              |
//| depending on the swap calculation method                         |
//+------------------------------------------------------------------+
int CSymbol::SymbolDigitsBySwap(void)
  {
   return
     (
      this.SwapMode()==SYMBOL_SWAP_MODE_POINTS           || 
      this.SwapMode()==SYMBOL_SWAP_MODE_REOPEN_CURRENT   || 
      this.SwapMode()==SYMBOL_SWAP_MODE_REOPEN_BID       ?  this.Digits() :
      this.SwapMode()==SYMBOL_SWAP_MODE_CURRENCY_SYMBOL  || 
      this.SwapMode()==SYMBOL_SWAP_MODE_CURRENCY_MARGIN  || 
      this.SwapMode()==SYMBOL_SWAP_MODE_CURRENCY_DEPOSIT ?  this.DigitsCurrency():
      this.SwapMode()==SYMBOL_SWAP_MODE_INTEREST_CURRENT || 
      this.SwapMode()==SYMBOL_SWAP_MODE_INTEREST_OPEN    ?  1  :  0
     );
  }  
//+------------------------------------------------------------------+


Machen wir die Methode Refresh() virtuell, da sie auch in der Basisklasse aller Objekte CBaseObj definiert ist. Ersetzen Sie auch den Typ der Methode RefreshRates() für das Aktualisieren der Kurse von void auf bool. Da die Methode RefreshRates() ganz am Anfang der Methode Refresh() aufgerufen werden soll. Wenn keine Daten darin erhalten wurden, gibt das Verfahren false zurück. Dementsprechend wird ein Verlassen der Methode Refresh() sofort durchgeführt.
Fügen Sie die Definition der Methode, die die Symbol-Ereignisbeschreibung zurückgibt hinzu:

//--- Update all symbol data
   virtual void      Refresh(void);
//--- Update quote data by a symbol
   bool              RefreshRates(void);
//--- Return description of symbol events
   string            EventDescription(const ENUM_SYMBOL_EVENT event);


Im Abschnitt der vereinfachten Zugriffsmethoden im Abschnitt 'public' der Klasse, in den Methoden, die symbolische ganzzahlige Eigenschaften zurückgeben,
fügen Sie die Methode zur Rückgabe eines Symbolindex im Fenster der Marktübersicht hinzu:

//+------------------------------------------------------------------+
//| Methods of a simplified access to the order object properties    |
//+------------------------------------------------------------------+
//--- Integer properties
   long              Status(void)                                 const { return this.GetProperty(SYMBOL_PROP_STATUS);                                      }
   int               IndexInMarketWatch(void)                     const { return (int)this.GetProperty(SYMBOL_PROP_INDEX_MW);                               }
   bool              IsCustom(void)                               const { return (bool)this.GetProperty(SYMBOL_PROP_CUSTOM);                                }
   color             ColorBackground(void)                        const { return (color)this.GetProperty(SYMBOL_PROP_BACKGROUND_COLOR);                     }
   ENUM_SYMBOL_CHART_MODE ChartMode(void)                         const { return (ENUM_SYMBOL_CHART_MODE)this.GetProperty(SYMBOL_PROP_CHART_MODE);          }
   bool              IsExist(void)                                const { return (bool)this.GetProperty(SYMBOL_PROP_EXIST);                                 }
   bool              IsExist(const string name)                   const { return this.SymbolExists(name);                                                   }
   bool              IsSelect(void)                               const { return (bool)this.GetProperty(SYMBOL_PROP_SELECT);                                }
   bool              IsVisible(void)                              const { return (bool)this.GetProperty(SYMBOL_PROP_VISIBLE);                               }
   long              SessionDeals(void)                           const { return this.GetProperty(SYMBOL_PROP_SESSION_DEALS);                               }
   long              SessionBuyOrders(void)                       const { return this.GetProperty(SYMBOL_PROP_SESSION_BUY_ORDERS);                          }
   long              SessionSellOrders(void)                      const { return this.GetProperty(SYMBOL_PROP_SESSION_SELL_ORDERS);                         }
   long              Volume(void)                                 const { return this.GetProperty(SYMBOL_PROP_VOLUME);                                      }
   long              VolumeHigh(void)                             const { return this.GetProperty(SYMBOL_PROP_VOLUMEHIGH);                                  }
   long              VolumeLow(void)                              const { return this.GetProperty(SYMBOL_PROP_VOLUMELOW);                                   }
   datetime          Time(void)                                   const { return (datetime)this.GetProperty(SYMBOL_PROP_TIME);                              }
   int               Digits(void)                                 const { return (int)this.GetProperty(SYMBOL_PROP_DIGITS);                                 }
   int               DigitsLot(void)                              const { return (int)this.GetProperty(SYMBOL_PROP_DIGITS_LOTS);                            }
   int               Spread(void)                                 const { return (int)this.GetProperty(SYMBOL_PROP_SPREAD);                                 }
   bool              IsSpreadFloat(void)                          const { return (bool)this.GetProperty(SYMBOL_PROP_SPREAD_FLOAT);                          }
   int               TicksBookdepth(void)                         const { return (int)this.GetProperty(SYMBOL_PROP_TICKS_BOOKDEPTH);                        }
   ENUM_SYMBOL_CALC_MODE TradeCalcMode(void)                      const { return (ENUM_SYMBOL_CALC_MODE)this.GetProperty(SYMBOL_PROP_TRADE_CALC_MODE);      }
   ENUM_SYMBOL_TRADE_MODE TradeMode(void)                         const { return (ENUM_SYMBOL_TRADE_MODE)this.GetProperty(SYMBOL_PROP_TRADE_MODE);          }
   datetime          StartTime(void)                              const { return (datetime)this.GetProperty(SYMBOL_PROP_START_TIME);                        }
   datetime          ExpirationTime(void)                         const { return (datetime)this.GetProperty(SYMBOL_PROP_EXPIRATION_TIME);                   }
   int               TradeStopLevel(void)                         const { return (int)this.GetProperty(SYMBOL_PROP_TRADE_STOPS_LEVEL);                      }
   int               TradeFreezeLevel(void)                       const { return (int)this.GetProperty(SYMBOL_PROP_TRADE_FREEZE_LEVEL);                     }
   ENUM_SYMBOL_TRADE_EXECUTION TradeExecutionMode(void)           const { return (ENUM_SYMBOL_TRADE_EXECUTION)this.GetProperty(SYMBOL_PROP_TRADE_EXEMODE);  }
   ENUM_SYMBOL_SWAP_MODE SwapMode(void)                           const { return (ENUM_SYMBOL_SWAP_MODE)this.GetProperty(SYMBOL_PROP_SWAP_MODE);            }
   ENUM_DAY_OF_WEEK  SwapRollover3Days(void)                      const { return (ENUM_DAY_OF_WEEK)this.GetProperty(SYMBOL_PROP_SWAP_ROLLOVER3DAYS);        }
   bool              IsMarginHedgedUseLeg(void)                   const { return (bool)this.GetProperty(SYMBOL_PROP_MARGIN_HEDGED_USE_LEG);                 }
   int               ExpirationModeFlags(void)                    const { return (int)this.GetProperty(SYMBOL_PROP_EXPIRATION_MODE);                        }
   int               FillingModeFlags(void)                       const { return (int)this.GetProperty(SYMBOL_PROP_FILLING_MODE);                           }
   int               OrderModeFlags(void)                         const { return (int)this.GetProperty(SYMBOL_PROP_ORDER_MODE);                             }
   ENUM_SYMBOL_ORDER_GTC_MODE OrderModeGTC(void)                  const { return (ENUM_SYMBOL_ORDER_GTC_MODE)this.GetProperty(SYMBOL_PROP_ORDER_GTC_MODE);  }
   ENUM_SYMBOL_OPTION_MODE OptionMode(void)                       const { return (ENUM_SYMBOL_OPTION_MODE)this.GetProperty(SYMBOL_PROP_OPTION_MODE);        }
   ENUM_SYMBOL_OPTION_RIGHT OptionRight(void)                     const { return (ENUM_SYMBOL_OPTION_RIGHT)this.GetProperty(SYMBOL_PROP_OPTION_RIGHT);      }
//--- Real properties


In den Methoden zur Rückgabe der double-Eigenschaften
fügen Sie die Methode der Rückgabe von Bid oder letztem Preis, die Methode der Rückgabe des höchsten Bid oder dem letzten Preis des Tages und die Methode der Rückgabe des niedrigsten Bid oder dem letzten Preis des Tages hinzu:.

//--- Real properties
   double            Bid(void)                                    const { return this.GetProperty(SYMBOL_PROP_BID);                                         }
   double            BidHigh(void)                                const { return this.GetProperty(SYMBOL_PROP_BIDHIGH);                                     }
   double            BidLow(void)                                 const { return this.GetProperty(SYMBOL_PROP_BIDLOW);                                      }
   double            Ask(void)                                    const { return this.GetProperty(SYMBOL_PROP_ASK);                                         }
   double            AskHigh(void)                                const { return this.GetProperty(SYMBOL_PROP_ASKHIGH);                                     }
   double            AskLow(void)                                 const { return this.GetProperty(SYMBOL_PROP_ASKLOW);                                      }
   double            Last(void)                                   const { return this.GetProperty(SYMBOL_PROP_LAST);                                        }
   double            LastHigh(void)                               const { return this.GetProperty(SYMBOL_PROP_LASTHIGH);                                    }
   double            LastLow(void)                                const { return this.GetProperty(SYMBOL_PROP_LASTLOW);                                     }
   double            VolumeReal(void)                             const { return this.GetProperty(SYMBOL_PROP_VOLUME_REAL);                                 }
   double            VolumeHighReal(void)                         const { return this.GetProperty(SYMBOL_PROP_VOLUMEHIGH_REAL);                             }
   double            VolumeLowReal(void)                          const { return this.GetProperty(SYMBOL_PROP_VOLUMELOW_REAL);                              }
   double            OptionStrike(void)                           const { return this.GetProperty(SYMBOL_PROP_OPTION_STRIKE);                               }
   double            Point(void)                                  const { return this.GetProperty(SYMBOL_PROP_POINT);                                       }
   double            TradeTickValue(void)                         const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE);                            }
   double            TradeTickValueProfit(void)                   const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT);                     }
   double            TradeTickValueLoss(void)                     const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS);                       }
   double            TradeTickSize(void)                          const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_SIZE);                             }
   double            TradeContractSize(void)                      const { return this.GetProperty(SYMBOL_PROP_TRADE_CONTRACT_SIZE);                         }
   double            TradeAccuredInterest(void)                   const { return this.GetProperty(SYMBOL_PROP_TRADE_ACCRUED_INTEREST);                      }
   double            TradeFaceValue(void)                         const { return this.GetProperty(SYMBOL_PROP_TRADE_FACE_VALUE);                            }
   double            TradeLiquidityRate(void)                     const { return this.GetProperty(SYMBOL_PROP_TRADE_LIQUIDITY_RATE);                        }
   double            LotsMin(void)                                const { return this.GetProperty(SYMBOL_PROP_VOLUME_MIN);                                  }
   double            LotsMax(void)                                const { return this.GetProperty(SYMBOL_PROP_VOLUME_MAX);                                  }
   double            LotsStep(void)                               const { return this.GetProperty(SYMBOL_PROP_VOLUME_STEP);                                 }
   double            VolumeLimit(void)                            const { return this.GetProperty(SYMBOL_PROP_VOLUME_LIMIT);                                }
   double            SwapLong(void)                               const { return this.GetProperty(SYMBOL_PROP_SWAP_LONG);                                   }
   double            SwapShort(void)                              const { return this.GetProperty(SYMBOL_PROP_SWAP_SHORT);                                  }
   double            MarginInitial(void)                          const { return this.GetProperty(SYMBOL_PROP_MARGIN_INITIAL);                              }
   double            MarginMaintenance(void)                      const { return this.GetProperty(SYMBOL_PROP_MARGIN_MAINTENANCE);                          }
   double            MarginLongInitial(void)                      const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG_INITIAL);                         }
   double            MarginBuyStopInitial(void)                   const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL);                     }
   double            MarginBuyLimitInitial(void)                  const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL);                    }
   double            MarginBuyStopLimitInitial(void)              const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL);                }
   double            MarginLongMaintenance(void)                  const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE);                     }
   double            MarginBuyStopMaintenance(void)               const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE);                 }
   double            MarginBuyLimitMaintenance(void)              const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE);                }
   double            MarginBuyStopLimitMaintenance(void)          const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE);            }
   double            MarginShortInitial(void)                     const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT_INITIAL);                        }
   double            MarginSellStopInitial(void)                  const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL);                    }
   double            MarginSellLimitInitial(void)                 const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL);                   }
   double            MarginSellStopLimitInitial(void)             const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL);               }
   double            MarginShortMaintenance(void)                 const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE);                    }
   double            MarginSellStopMaintenance(void)              const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE);                }
   double            MarginSellLimitMaintenance(void)             const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE);               }
   double            MarginSellStopLimitMaintenance(void)         const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE);           }
   double            SessionVolume(void)                          const { return this.GetProperty(SYMBOL_PROP_SESSION_VOLUME);                              }
   double            SessionTurnover(void)                        const { return this.GetProperty(SYMBOL_PROP_SESSION_TURNOVER);                            }
   double            SessionInterest(void)                        const { return this.GetProperty(SYMBOL_PROP_SESSION_INTEREST);                            }
   double            SessionBuyOrdersVolume(void)                 const { return this.GetProperty(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME);                   }
   double            SessionSellOrdersVolume(void)                const { return this.GetProperty(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME);                  }
   double            SessionOpen(void)                            const { return this.GetProperty(SYMBOL_PROP_SESSION_OPEN);                                }
   double            SessionClose(void)                           const { return this.GetProperty(SYMBOL_PROP_SESSION_CLOSE);                               }
   double            SessionAW(void)                              const { return this.GetProperty(SYMBOL_PROP_SESSION_AW);                                  }
   double            SessionPriceSettlement(void)                 const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT);                    }
   double            SessionPriceLimitMin(void)                   const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN);                     }
   double            SessionPriceLimitMax(void)                   const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX);                     }
   double            MarginHedged(void)                           const { return this.GetProperty(SYMBOL_PROP_MARGIN_HEDGED);                               }
   double            NormalizedPrice(const double price)          const;
   double            BidLast(void)                                const;
   double            BidLastHigh(void)                            const;
   double            BidLastLow(void                            const;
//--- String properties


Lasst uns ihre Implementierung außerhalb des Klassenkörpers schreiben:

//+------------------------------------------------------------------+
//| Return Bid or Last price                                         |
//| depending on the chart construction method                       |
//+------------------------------------------------------------------+
double CSymbol::BidLast(void) const
  {
   return(this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.GetProperty(SYMBOL_PROP_BID) : this.GetProperty(SYMBOL_PROP_LAST));
  }  
//+------------------------------------------------------------------+
//| Return maximum Bid or Last price for a day                       |
//| depending on the chart construction method                       |
//+------------------------------------------------------------------+
double CSymbol::BidLastHigh(void) const
  {
   return(this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.GetProperty(SYMBOL_PROP_BIDHIGH) : this.GetProperty(SYMBOL_PROP_LASTHIGH));
  }  
//+------------------------------------------------------------------+
//| Return minimum Bid or Last price for a day                       |
//| depending on the chart construction method                       |
//+------------------------------------------------------------------+
double CSymbol::BidLastLow(void) const
  {
   return(this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.GetProperty(SYMBOL_PROP_BIDLOW) : this.GetProperty(SYMBOL_PROP_LASTLOW));
  }
//+------------------------------------------------------------------+


Hier ist alles einfach: Je nachdem, welche Preise für die Erstellung des Preischarts verwendet wurden, wird eine entsprechende Symboleigenschaft (mit Bid oder letztem Preis) zurückgegeben.

Schreiben Sie auch die Methoden zum Setzen von kontrollierten Eigenschaften und die Rückgabe von Eigenschaftenänderungswerten und Symbol-Ereignisflags im 'public' Abschnitt:.

//+------------------------------------------------------------------+
//| Get and set the parameters of tracked changes                    |
//+------------------------------------------------------------------+
   //--- Execution
   //--- Flag of changing the trading mode for a symbol
   bool              IsChangedTradeMode(void)                              const { return this.m_is_change_trade_mode;                       } 
   //--- Current session deals
   //--- setting the controlled value of (1) growth, (2) decrease in the number of deals during the current session
   //--- getting (3) the number of deals change value during the current session,
   //--- getting the flag of the number of deals change during the current session exceeding the (4) growth, (5) decrease value
   void              SetControlSessionDealsInc(const long value)                 { this.m_control_session_deals_inc=::fabs(value);           }
   void              SetControlSessionDealsDec(const long value)                 { this.m_control_session_deals_dec=::fabs(value);           }
   long              GetValueChangedSessionDeals(void)                     const { return this.m_changed_session_deals_value;                }
   bool              IsIncreaseSessionDeals(void)                          const { return this.m_is_change_session_deals_inc;                }
   bool              IsDecreaseSessionDeals(void)                          const { return this.m_is_change_session_deals_dec;                }
   //--- Buy orders of the current session
   //--- setting the controlled value of (1) growth, (2) decrease in the current number of Buy orders
   //--- getting (3) the current number of Buy orders change value,
   //--- getting the flag of the current Buy orders' number change exceeding the (4) growth, (5) decrease value
   void              SetControlSessionBuyOrdInc(const long value)                { this.m_control_session_buy_ord_inc=::fabs(value);         }
   void              SetControlSessionBuyOrdDec(const long value)                { this.m_control_session_buy_ord_dec=::fabs(value);         }
   long              GetValueChangedSessionBuyOrders(void)                 const { return this.m_changed_session_buy_ord_value;              }
   bool              IsIncreaseSessionBuyOrders(void)                      const { return this.m_is_change_session_buy_ord_inc;              }
   bool              IsDecreaseSessionBuyOrders(void)                      const { return this.m_is_change_session_buy_ord_dec;              }
   //--- Sell orders of the current session
   //--- setting the controlled value of (1) growth, (2) decrease in the current number of Sell orders
   //--- getting (3) the current number of Sell orders change value,
   //--- getting the flag of the current Sell orders' number change exceeding the (4) growth, (5) decrease value
   void              SetControlSessionSellOrdInc(const long value)               { this.m_control_session_sell_ord_inc=::fabs(value);        }
   void              SetControlSessionSellOrdDec(const long value)               { this.m_control_session_sell_ord_dec=::fabs(value);        }
   long              GetValueChangedSessionSellOrders(void)                const { return this.m_changed_session_sell_ord_value;             }
   bool              IsIncreaseSessionSellOrders(void)                     const { return this.m_is_change_session_sell_ord_inc;             }
   bool              IsDecreaseSessionSellOrders(void)                     const { return this.m_is_change_session_sell_ord_dec;             }
   //--- Volume of the last deal
   //--- setting the last deal volume controlled (1) growth, (2) decrease value
   //--- getting (3) volume change values in the last deal,
   //--- getting the flag of the volume change in the last deal exceeding the (4) growth, (5) decrease value
   void              SetControlVolumeInc(const long value)                       { this.m_control_volume_inc=::fabs(value);                  }
   void              SetControlVolumeDec(const long value)                       { this.m_control_volume_dec=::fabs(value);                  }
   long              GetValueChangedVolume(void)                           const { return this.m_changed_volume_value;                       }
   bool              IsIncreaseVolume(void)                                const { return this.m_is_change_volume_inc;                       }
   bool              IsDecreaseVolume(void)                                const { return this.m_is_change_volume_dec;                       }
   //--- Maximum volume within a day
   //--- setting the maximum day volume controlled (1) growth, (2) decrease value
   //--- getting (3) the maximum volume change value within a day,
   //--- getting the flag of the maximum day volume change exceeding the (4) growth, (5) decrease value
   void              SetControlVolumeHighInc(const long value)                   { this.m_control_volume_high_day_inc=::fabs(value);         }
   void              SetControlVolumeHighDec(const long value)                   { this.m_control_volume_high_day_dec=::fabs(value);         }
   long              GetValueChangedVolumeHigh(void)                       const { return this.m_changed_volume_high_day_value;              }
   bool              IsIncreaseVolumeHigh(void)                            const { return this.m_is_change_volume_high_day_inc;              }
   bool              IsDecreaseVolumeHigh(void)                            const { return this.m_is_change_volume_high_day_dec;              }
   //--- Minimum volume within a day
   //--- setting the minimum day volume controlled (1) growth, (2) decrease value
   //--- getting (3) the minimum volume change value within a day,
   //--- getting the flag of the minimum day volume change exceeding the (4) growth, (5) decrease value
   void              SetControlVolumeLowInc(const long value)                    { this.m_control_volume_low_day_inc=::fabs(value);          }
   void              SetControlVolumeLowDec(const long value)                    { this.m_control_volume_low_day_dec=::fabs(value);          }
   long              GetValueChangedVolumeLow(void)                        const { return this.m_changed_volume_low_day_value;               }
   bool              IsIncreaseVolumeLow(void)                             const { return this.m_is_change_volume_low_day_inc;               }
   bool              IsDecreaseVolumeLow(void)                             const { return this.m_is_change_volume_low_day_dec;               }
   //--- Spread
   //--- setting the controlled spread decrease (1) growth, (2) decrease value in points
   //--- getting (3) spread change value in points,
   //--- getting the flag of the spread change in points exceeding the (4) growth, (5) decrease value
   void              SetControlSpreadInc(const int value)                        { this.m_control_spread_inc=::fabs(value);                  }
   void              SetControlSpreadDec(const int value)                        { this.m_control_spread_dec=::fabs(value);                  }
   int               GetValueChangedSpread(void)                           const { return this.m_changed_spread_value;                       }
   bool              IsIncreaseSpread(void)                                const { return this.m_is_change_spread_inc;                       }
   bool              IsDecreaseSpread(void)                                const { return this.m_is_change_spread_dec;                       }
   //--- StopLevel
   //--- setting the controlled StopLevel decrease (1) growth, (2) decrease value in points
   //--- getting (3) StopLevel change value in points,
   //--- getting the flag of StopLevel change in points exceeding the (4) growth, (5) decrease value
   void              SetControlStopLevelInc(const int value)                     { this.m_control_stops_level_inc=::fabs(value);             }
   void              SetControlStopLevelDec(const int value)                     { this.m_control_stops_level_dec=::fabs(value);             }
   int               GetValueChangedStopLevel(void)                        const { return this.m_changed_stops_level_value;                  }
   bool              IsIncreaseStopLevel(void)                             const { return this.m_is_change_stops_level_inc;                  }
   bool              IsDecreaseStopLevel(void)                             const { return this.m_is_change_stops_level_dec;                  }
   //--- Freeze distance
   //--- setting the controlled FreezeLevel decrease (1) growth, (2) decrease value in points
   //--- getting (3) FreezeLevel change value in points,
   //--- getting the flag of FreezeLevel change in points exceeding the (4) growth, (5) decrease value
   void              SetControlFreezeLevelInc(const int value)                   { this.m_control_freeze_level_inc=::fabs(value);            }
   void              SetControlFreezeLevelDec(const int value)                   { this.m_control_freeze_level_dec=::fabs(value);            }
   int               GetValueChangedFreezeLevel(void)                      const { return this.m_changed_freeze_level_value;                 }
   bool              IsIncreaseFreezeLevel(void)                           const { return this.m_is_change_freeze_level_inc;                 }
   bool              IsDecreaseFreezeLevel(void)                           const { return this.m_is_change_freeze_level_dec;                 }
   
   //--- Bid/Last
   //--- setting the Bid or Last price controlled (1) growth, (2) decrease value
   //--- getting (3) Bid or Last price change value,
   //--- getting the flag of the Bid or Last price change exceeding the (4) growth, (5) decrease value
   void              SetControlBidLastInc(const double value)                    { this.m_control_bid_last_inc=::fabs(value);                }
   void              SetControlBidLastDec(const double value)                    { this.m_control_bid_last_dec=::fabs(value);                }
   double            GetValueChangedBidLast(void)                          const { return this.m_changed_bid_last_value;                     }
   bool              IsIncreaseBidLast(void)                               const { return this.m_is_change_bid_last_inc;                     }
   bool              IsDecreaseBidLast(void)                               const { return this.m_is_change_bid_last_dec;                     }
   //--- Maximum Bid/Last of the day
   //--- setting the maximum Bid or Last price controlled (1) growth, (2) decrease value
   //--- getting the (3) maximum Bid or Last price change value,
   //--- getting the flag of the maximum Bid or Last price change exceeding the (4) growth, (5) decrease value
   void              SetControlBidLastHighInc(const double value)                { this.m_control_bid_last_high_inc=::fabs(value);           }
   void              SetControlBidLastHighDec(const double value)                { this.m_control_bid_last_high_dec=::fabs(value);           }
   double            GetValueChangedBidLastHigh(void)                      const { return this.m_changed_bid_last_high_value;                }
   bool              IsIncreaseBidLastHigh(void)                           const { return this.m_is_change_bid_last_high_inc;                }
   bool              IsDecreaseBidLastHigh(void)                           const { return this.m_is_change_bid_last_high_dec;                }
   //--- Minimum Bid/Last of the day
   //--- setting the minimum Bid or Last price controlled (1) growth, (2) decrease value
   //--- getting the (3) minimum Bid or Last price change value,
   //--- getting the flag of the minimum Bid or Last price change exceeding the (4) growth, (5) decrease value
   void              SetControlBidLastLowInc(const double value)                 { this.m_control_bid_last_low_inc=::fabs(value);            }
   void              SetControlBidLastLowDec(const double value)                 { this.m_control_bid_last_low_dec=::fabs(value);            }
   double            GetValueChangedBidLastLow(void)                       const { return this.m_changed_bid_last_low_value;                 }
   bool              IsIncreaseBidLastLow(void)                            const { return this.m_is_change_bid_last_low_inc;                 }
   bool              IsDecreaseBidLastLow(void)                            const { return this.m_is_change_bid_last_low_dec;                 }
   //--- Ask
   //--- setting the Ask price controlled (1) growth, (2) decrease value
   //--- getting (3) Ask price change value,
   //--- getting the flag of the Ask price change exceeding the (4) growth, (5) decrease value
   void              SetControlAskInc(const double value)                        { this.m_control_ask_inc=::fabs(value);                     }
   void              SetControlAskDec(const double value)                        { this.m_control_ask_dec=::fabs(value);                     }
   double            GetValueChangedAsk(void)                              const { return this.m_changed_ask_value;                          }
   bool              IsIncreaseAsk(void)                                   const { return this.m_is_change_ask_inc;                          }
   bool              IsDecreaseAsk(void)                                   const { return this.m_is_change_ask_dec;                          }
   //--- Maximum Ask price for the day
   //--- setting the maximum day Ask controlled (1) growth, (2) decrease value
   //--- getting (3) the maximum Ask change value within a day,
   //--- getting the flag of the maximum day Ask change exceeding the (4) growth, (5) decrease value
   void              SetControlAskHighInc(const double value)                    { this.m_control_ask_high_inc=::fabs(value);                }
   void              SetControlAskHighDec(const double value)                    { this.m_control_ask_high_dec=::fabs(value);                }
   double            GetValueChangedAskHigh(void)                          const { return this.m_changed_ask_high_value;                     }
   bool              IsIncreaseAskHigh(void)                               const { return this.m_is_change_ask_high_inc;                     }
   bool              IsDecreaseAskHigh(void)                               const { return this.m_is_change_ask_high_dec;                     }
   //--- Minimum Ask price for the day
   //--- setting the minimum day Ask controlled (1) growth, (2) decrease value
   //--- getting (3) the minimum Ask change value within a day,
   //--- getting the flag of the minimum day Ask change exceeding the (4) growth, (5) decrease value
   void              SetControlAskLowInc(const double value)                     { this.m_control_ask_low_inc=::fabs(value);                 }
   void              SetControlAskLowDec(const double value)                     { this.m_control_ask_low_dec=::fabs(value);                 }
   double            GetValueChangedAskLow(void)                           const { return this.m_changed_ask_low_value;                      }
   bool              IsIncreaseAskLow(void)                                const { return this.m_is_change_ask_low_inc;                      }
   bool              IsDecreaseAskLow(void)                                const { return this.m_is_change_ask_low_dec;                      }
   //--- Real Volume for the day
   //--- setting the real day volume controlled (1) growth, (2) decrease value
   //--- getting (3) the change value of the real day volume,
   //--- getting the flag of the real day volume change exceeding the (4) growth, (5) decrease value
   void              SetControlVolumeRealInc(const double value)                 { this.m_control_volume_real_inc=::fabs(value);             }
   void              SetControlVolumeRealDec(const double value)                 { this.m_control_volume_real_dec=::fabs(value);             }
   double            GetValueChangedVolumeReal(void)                       const { return this.m_changed_volume_real_value;                  }
   bool              IsIncreaseVolumeReal(void)                            const { return this.m_is_change_volume_real_inc;                  }
   bool              IsDecreaseVolumeReal(void)                            const { return this.m_is_change_volume_real_dec;                  }
   //--- Maximum real volume for the day
   //--- setting the maximum real day volume controlled (1) growth, (2) decrease value
   //--- getting (3) the change value of the maximum real day volume,
   //--- getting the flag of the maximum real day volume change exceeding the (4) growth, (5) decrease value
   void              SetControlVolumeHighRealInc(const double value)             { this.m_control_volume_high_real_day_inc=::fabs(value);    }
   void              SetControlVolumeHighRealDec(const double value)             { this.m_control_volume_high_real_day_dec=::fabs(value);    }
   double            GetValueChangedVolumeHighReal(void)                   const { return this.m_changed_volume_high_real_day_value;         }
   bool              IsIncreaseVolumeHighReal(void)                        const { return this.m_is_change_volume_high_real_day_inc;         }
   bool              IsDecreaseVolumeHighReal(void)                        const { return this.m_is_change_volume_high_real_day_dec;         }
   //--- Minimum real volume for the day
   //--- setting the minimum real day volume controlled (1) growth, (2) decrease value
   //--- getting (3) the change value of the minimum real day volume,
   //--- getting the flag of the minimum real day volume change exceeding the (4) growth, (5) decrease value
   void              SetControlVolumeLowRealInc(const double value)              { this.m_control_volume_low_real_day_inc=::fabs(value);     }
   void              SetControlVolumeLowRealDec(const double value)              { this.m_control_volume_low_real_day_dec=::fabs(value);     }
   double            GetValueChangedVolumeLowReal(void)                    const { return this.m_changed_volume_low_real_day_value;          }
   bool              IsIncreaseVolumeLowReal(void)                         const { return this.m_is_change_volume_low_real_day_inc;          }
   bool              IsDecreaseVolumeLowReal(void)                         const { return this.m_is_change_volume_low_real_day_dec;          }
   //--- Strike price
   //--- setting the strike price controlled (1) growth, (2) decrease value
   //--- getting (3) the change value of the strike price,
   //--- getting the flag of the strike price change exceeding the (4) growth, (5) decrease value
   void              SetControlOptionStrikeInc(const double value)               { this.m_control_option_strike_inc=::fabs(value);           }
   void              SetControlOptionStrikeDec(const double value)               { this.m_control_option_strike_dec=::fabs(value);           }
   double            GetValueChangedOptionStrike(void)                     const { return this.m_changed_option_strike_value;                } 
   bool              IsIncreaseOptionStrike(void)                          const { return this.m_is_change_option_strike_inc;                }
   bool              IsDecreaseOptionStrike(void)                          const { return this.m_is_change_option_strike_dec;                }
   //--- Maximum allowed total volume of unidirectional positions and orders
   //--- (1) getting the change value of the maximum allowed total volume of unidirectional positions and orders,
   //--- getting the flag of (2) increasing, (3) decreasing the maximum allowed total volume of unidirectional positions and orders
   double            GetValueChangedVolumeLimit(void)                      const { return this.m_changed_volume_limit_value;                 }
   bool              IsIncreaseVolumeLimit(void)                           const { return this.m_is_change_volume_limit_inc;                 }
   bool              IsDecreaseVolumeLimit(void)                           const { return this.m_is_change_volume_limit_dec;                 }
   //---  Swap long
   //--- (1) getting the swap long change value,
   //--- getting the flag of (2) increasing, (3) decreasing the swap long
   double            GetValueChangedSwapLong(void)                         const { return this.m_changed_swap_long_value;                    }
   bool              IsIncreaseSwapLong(void)                              const { return this.m_is_change_swap_long_inc;                    }
   bool              IsDecreaseSwapLong(void)                              const { return this.m_is_change_swap_long_dec;                    }
   //---  Swap short
   //--- (1) getting the swap short change value,
   //--- getting the flag of (2) increasing, (3) decreasing the swap short
   double            GetValueChangedSwapShort(void)                        const { return this.m_changed_swap_short_value;                   }
   bool              IsIncreaseSwapShort(void)                             const { return this.m_is_change_swap_short_inc;                   }
   bool              IsDecreaseSwapShort(void)                             const { return this.m_is_change_swap_short_dec;                   }
   //--- The total volume of deals in the current session
   //--- setting the controlled value of (1) growth, (2) decrease in the total volume of deals during the current session
   //--- getting (3) the total deal volume change value in the current session,
   //--- getting the flag of the total deal volume change during the current session exceeding the (4) growth, (5) decrease value
   void              SetControlSessionVolumeInc(const double value)              { this.m_control_session_volume_inc=::fabs(value);          }
   void              SetControlSessionVolumeDec(const double value)              { this.m_control_session_volume_dec=::fabs(value);          }
   double            GetValueChangedSessionVolume(void)                    const { return this.m_changed_session_volume_value;               }
   bool              IsIncreaseSessionVolume(void)                         const { return this.m_is_change_session_volume_inc;               }
   bool              IsDecreaseSessionVolume(void)                         const { return this.m_is_change_session_volume_dec;               }
   //--- The total turnover in the current session
   //--- setting the controlled value of the turnover (1) growth, (2) decrease during the current session
   //--- getting (3) the total turnover change value in the current session,
   //--- getting the flag of the total turnover change during the current session exceeding the (4) growth, (5) decrease value
   void              SetControlSessionTurnoverInc(const double value)            { this.m_control_session_turnover_inc=::fabs(value);        }
   void              SetControlSessionTurnoverDec(const double value)            { this.m_control_session_turnover_dec=::fabs(value);        }
   double            GetValueChangedSessionTurnover(void)                  const { return this.m_changed_session_turnover_value;             }
   bool              IsIncreaseSessionTurnover(void)                       const { return this.m_is_change_session_turnover_inc;             }
   bool              IsDecreaseSessionTurnover(void)                       const { return this.m_is_change_session_turnover_dec;             }
   //--- The total volume of open positions
   //--- setting the controlled value of (1) growth, (2) decrease in the total volume of open positions during the current session
   //--- getting (3) the change value of the open positions total volume in the current session,
   //--- getting the flag of the open positions total volume change during the current session exceeding the (4) growth, (5) decrease value
   void              SetControlSessionInterestInc(const double value)            { this.m_control_session_interest_inc=::fabs(value);        }
   void              SetControlSessionInterestDec(const double value)            { this.m_control_session_interest_dec=::fabs(value);        }
   double            GetValueChangedSessionInterest(void)                  const { return this.m_changed_session_interest_value;             }
   bool              IsIncreaseSessionInterest(void)                       const { return this.m_is_change_session_interest_inc;             }
   bool              IsDecreaseSessionInterest(void)                       const { return this.m_is_change_session_interest_dec;             }
   //--- The total volume of Buy orders at the moment
   //--- setting the controlled value of (1) growth, (2) decrease in the current total buy order volume
   //--- getting (3) the change value of the current total buy order volume,
   //--- getting the flag of the current total buy orders' volume change exceeding the (4) growth, (5) decrease value
   void              SetControlSessionBuyOrdVolumeInc(const double value)        { this.m_control_session_buy_ord_volume_inc=::fabs(value);  }
   void              SetControlSessionBuyOrdVolumeDec(const double value)        { this.m_control_session_buy_ord_volume_dec=::fabs(value);  }
   double            GetValueChangedSessionBuyOrdVolume(void)              const { return this.m_changed_session_buy_ord_volume_value;       }
   bool              IsIncreaseSessionBuyOrdVolume(void)                   const { return this.m_is_change_session_buy_ord_volume_inc;       }
   bool              IsDecreaseSessionBuyOrdVolume(void)                   const { return this.m_is_change_session_buy_ord_volume_dec;       }
   //--- The total volume of Sell orders at the moment
   //--- setting the controlled value of (1) growth, (2) decrease in the current total sell order volume
   //--- getting (3) the change value of the current total sell order volume,
   //--- getting the flag of the current total sell orders' volume change exceeding the (4) growth, (5) decrease value
   void              SetControlSessionSellOrdVolumeInc(const double value)       { this.m_control_session_sell_ord_volume_inc=::fabs(value); }
   void              SetControlSessionSellOrdVolumeDec(const double value)       { this.m_control_session_sell_ord_volume_dec=::fabs(value); }
   double            GetValueChangedSessionSellOrdVolume(void)             const { return this.m_changed_session_sell_ord_volume_value;      }
   bool              IsIncreaseSessionSellOrdVolume(void)                  const { return this.m_is_change_session_sell_ord_volume_inc;      }
   bool              IsDecreaseSessionSellOrdVolume(void)                  const { return this.m_is_change_session_sell_ord_volume_dec;      }
   //--- Session open price
   //--- setting the session open price controlled (1) growth, (2) decrease value
   //--- getting (3) the change value of the session open price,
   //--- getting the flag of the session open price change exceeding the (4) growth, (5) decrease value
   void              SetControlSessionPriceOpenInc(const double value)           { this.m_control_session_open_inc=::fabs(value);            }
   void              SetControlSessionPriceOpenDec(const double value)           { this.m_control_session_open_dec=::fabs(value);            }
   double            GetValueChangedSessionPriceOpen(void)                 const { return this.m_changed_session_open_value;                 }
   bool              IsIncreaseSessionPriceOpen(void)                      const { return this.m_is_change_session_open_inc;                 }
   bool              IsDecreaseSessionPriceOpen(void)                      const { return this.m_is_change_session_open_dec;                 }
   //--- Session close price
   //--- setting the session close price controlled (1) growth, (2) decrease value
   //--- getting (3) the change value of the session close price,
   //--- getting the flag of the session close price change exceeding the (4) growth, (5) decrease value
   void              SetControlSessionPriceCloseInc(const double value)          { this.m_control_session_close_inc=::fabs(value);           }
   void              SetControlSessionPriceCloseDec(const double value)          { this.m_control_session_close_dec=::fabs(value);           }
   double            GetValueChangedSessionPriceClose(void)                const { return this.m_changed_session_close_value;                }
   bool              IsIncreaseSessionPriceClose(void)                     const { return this.m_is_change_session_close_inc;                }
   bool              IsDecreaseSessionPriceClose(void)                     const { return this.m_is_change_session_close_dec;                }
   //--- The average weighted session price
   //--- setting the average weighted session price controlled (1) growth, (2) decrease value
   //--- getting (3) the change value of the average weighted session price,
   //--- getting the flag of the average weighted session price change exceeding the (4) growth, (5) decrease value
   void              SetControlSessionPriceAWInc(const double value)             { this.m_control_session_aw_inc=::fabs(value);              }
   void              SetControlSessionPriceAWDec(const double value)             { this.m_control_session_aw_dec=::fabs(value);              }
   double            GetValueChangedSessionPriceAW(void)                   const { return this.m_changed_session_aw_value;                   }
   bool              IsIncreaseSessionPriceAW(void)                        const { return this.m_is_change_session_aw_inc;                   }
   bool              IsDecreaseSessionPriceAW(void)                        const { return this.m_is_change_session_aw_dec;                   }
//---


Hier werden für jede der kontrollierten Eigenschaften die Verfahren zum Einstellen eines Änderungswerts für kontrollierte Eigenschaften bereitgestellt. Bei Überschreitung des Wertes wird ein Ereignis gebildet. Das Ereignis-Flag kann mit der Methode empfangen werden, die das Ereignis-Flag zurückgibt, während der Änderungswert auch mit der entsprechenden Methode erhalten werden kann. Wir haben ähnliche Methoden bei der Implementierung für das Verfolgen von Kontoereignissen im Teil 13 der Bibliotheksbeschreibung diskutiert.

Einige Änderungen wurden im Klassenkonstruktor vorgenommen:

//+------------------------------------------------------------------+
//| Closed parametric constructor                                    |
//+------------------------------------------------------------------+
CSymbol::CSymbol(ENUM_SYMBOL_STATUS symbol_status,const string name,const int index)
  {
   this.m_name=name;
   if(!this.Exist())
     {
      ::Print(DFUN_ERR_LINE,"\"",this.m_name,"\"",": ",TextByLanguage("Ошибка. Такого символа нет на сервере","Error. There is no such symbol on the server"));
      this.m_global_error=ERR_MARKET_UNKNOWN_SYMBOL;
     }
   bool select=::SymbolInfoInteger(this.m_name,SYMBOL_SELECT);
   ::ResetLastError();
   if(!select)
     {
      if(!this.SetToMarketWatch())
        {
         this.m_global_error=::GetLastError();
         ::Print(DFUN_ERR_LINE,"\"",this.m_name,"\": ",TextByLanguage("Не удалось поместить в обзор рынка. Ошибка: ","Failed to put in the market watch. Error: "),this.m_global_error);
        }
     }
   ::ResetLastError();
   if(!::SymbolInfoTick(this.m_name,this.m_tick))
     {
      this.m_global_error=::GetLastError();
      ::Print(DFUN_ERR_LINE,"\"",this.m_name,"\": ",TextByLanguage("Не удалось получить текущие цены. Ошибка: ","Could not get current prices. Error: "),this.m_global_error);
     }
//--- Initialize data
   this.Reset();
   this.InitMarginRates();
   ::ZeroMemory(this.m_struct_prev_symbol);
   this.m_struct_prev_symbol.trade_mode=WRONG_VALUE;
   this.InitChangesParams();
   this.InitControlsParams();
#ifdef __MQL5__
   ::ResetLastError();
   if(!this.MarginRates())
     {
      this.m_global_error=::GetLastError();
      ::Print(DFUN_ERR_LINE,this.Name(),": ",TextByLanguage("Не удалось получить коэффициенты взимания маржи. Ошибка: ","Failed to get margin rates. Error: "),this.m_global_error);
      return;
     }
#endif 
   
//--- Sichern der ganzzahligen Eigenschaften
   this.m_long_prop[SYMBOL_PROP_STATUS]                                             = symbol_status;
   this.m_long_prop[SYMBOL_PROP_INDEX_MW]                                           = index;
   this.m_long_prop[SYMBOL_PROP_VOLUME]                                             = (long)this.m_tick.volume;
   this.m_long_prop[SYMBOL_PROP_SELECT]                                             = ::SymbolInfoInteger(this.m_name,SYMBOL_SELECT);
   this.m_long_prop[SYMBOL_PROP_VISIBLE]                                            = ::SymbolInfoInteger(this.m_name,SYMBOL_VISIBLE);
   this.m_long_prop[SYMBOL_PROP_SESSION_DEALS]                                      = ::SymbolInfoInteger(this.m_name,SYMBOL_SESSION_DEALS);
   this.m_long_prop[SYMBOL_PROP_SESSION_BUY_ORDERS]                                 = ::SymbolInfoInteger(this.m_name,SYMBOL_SESSION_BUY_ORDERS);
   this.m_long_prop[SYMBOL_PROP_SESSION_SELL_ORDERS]                                = ::SymbolInfoInteger(this.m_name,SYMBOL_SESSION_SELL_ORDERS);
   this.m_long_prop[SYMBOL_PROP_VOLUMEHIGH]                                         = ::SymbolInfoInteger(this.m_name,SYMBOL_VOLUMEHIGH);
   this.m_long_prop[SYMBOL_PROP_VOLUMELOW]                                          = ::SymbolInfoInteger(this.m_name,SYMBOL_VOLUMELOW);
   this.m_long_prop[SYMBOL_PROP_DIGITS]                                             = ::SymbolInfoInteger(this.m_name,SYMBOL_DIGITS);
   this.m_long_prop[SYMBOL_PROP_SPREAD]                                             = ::SymbolInfoInteger(this.m_name,SYMBOL_SPREAD);
   this.m_long_prop[SYMBOL_PROP_SPREAD_FLOAT]                                       = ::SymbolInfoInteger(this.m_name,SYMBOL_SPREAD_FLOAT);
   this.m_long_prop[SYMBOL_PROP_TICKS_BOOKDEPTH]                                    = ::SymbolInfoInteger(this.m_name,SYMBOL_TICKS_BOOKDEPTH);
   this.m_long_prop[SYMBOL_PROP_TRADE_MODE]                                         = ::SymbolInfoInteger(this.m_name,SYMBOL_TRADE_MODE);
   this.m_long_prop[SYMBOL_PROP_START_TIME]                                         = ::SymbolInfoInteger(this.m_name,SYMBOL_START_TIME);
   this.m_long_prop[SYMBOL_PROP_EXPIRATION_TIME]                                    = ::SymbolInfoInteger(this.m_name,SYMBOL_EXPIRATION_TIME);
   this.m_long_prop[SYMBOL_PROP_TRADE_STOPS_LEVEL]                                  = ::SymbolInfoInteger(this.m_name,SYMBOL_TRADE_STOPS_LEVEL);
   this.m_long_prop[SYMBOL_PROP_TRADE_FREEZE_LEVEL]                                 = ::SymbolInfoInteger(this.m_name,SYMBOL_TRADE_FREEZE_LEVEL);
   this.m_long_prop[SYMBOL_PROP_TRADE_EXEMODE]                                      = ::SymbolInfoInteger(this.m_name,SYMBOL_TRADE_EXEMODE);
   this.m_long_prop[SYMBOL_PROP_SWAP_ROLLOVER3DAYS]                                 = ::SymbolInfoInteger(this.m_name,SYMBOL_SWAP_ROLLOVER3DAYS);
   this.m_long_prop[SYMBOL_PROP_TIME]                                               = this.TickTime();
   this.m_long_prop[SYMBOL_PROP_EXIST]                                              = this.SymbolExists();
   this.m_long_prop[SYMBOL_PROP_CUSTOM]                                             = this.SymbolCustom();
   this.m_long_prop[SYMBOL_PROP_MARGIN_HEDGED_USE_LEG]                              = this.SymbolMarginHedgedUseLEG();
   this.m_long_prop[SYMBOL_PROP_ORDER_MODE]                                         = this.SymbolOrderMode();
   this.m_long_prop[SYMBOL_PROP_FILLING_MODE]                                       = this.SymbolOrderFillingMode();
   this.m_long_prop[SYMBOL_PROP_EXPIRATION_MODE]                                    = this.SymbolExpirationMode();
   this.m_long_prop[SYMBOL_PROP_ORDER_GTC_MODE]                                     = this.SymbolOrderGTCMode();
   this.m_long_prop[SYMBOL_PROP_OPTION_MODE]                                        = this.SymbolOptionMode();
   this.m_long_prop[SYMBOL_PROP_OPTION_RIGHT]                                       = this.SymbolOptionRight();
   this.m_long_prop[SYMBOL_PROP_BACKGROUND_COLOR]                                   = this.SymbolBackgroundColor();
   this.m_long_prop[SYMBOL_PROP_CHART_MODE]                                         = this.SymbolChartMode();
   this.m_long_prop[SYMBOL_PROP_TRADE_CALC_MODE]                                    = this.SymbolCalcMode();
   this.m_long_prop[SYMBOL_PROP_SWAP_MODE]                                          = this.SymbolSwapMode();
//--- Sichern der Double-Eigenschaften
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKHIGH)]                          = ::SymbolInfoDouble(this.m_name,SYMBOL_ASKHIGH);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKLOW)]                           = ::SymbolInfoDouble(this.m_name,SYMBOL_ASKLOW);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTHIGH)]                         = ::SymbolInfoDouble(this.m_name,SYMBOL_LASTHIGH);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTLOW)]                          = ::SymbolInfoDouble(this.m_name,SYMBOL_LASTLOW);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_POINT)]                            = ::SymbolInfoDouble(this.m_name,SYMBOL_POINT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE)]                 = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_VALUE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT)]          = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_VALUE_PROFIT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS)]            = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_VALUE_LOSS);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_SIZE)]                  = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_SIZE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_CONTRACT_SIZE)]              = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_CONTRACT_SIZE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MIN)]                       = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_MIN);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MAX)]                       = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_MAX);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_STEP)]                      = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_STEP);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_LIMIT)]                     = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_LIMIT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_LONG)]                        = ::SymbolInfoDouble(this.m_name,SYMBOL_SWAP_LONG);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_SHORT)]                       = ::SymbolInfoDouble(this.m_name,SYMBOL_SWAP_SHORT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_INITIAL)]                   = ::SymbolInfoDouble(this.m_name,SYMBOL_MARGIN_INITIAL);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_MAINTENANCE)]               = ::SymbolInfoDouble(this.m_name,SYMBOL_MARGIN_MAINTENANCE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_VOLUME)]                   = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_VOLUME);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_TURNOVER)]                 = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_TURNOVER);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_INTEREST)]                 = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_INTEREST);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME)]        = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_BUY_ORDERS_VOLUME);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME)]       = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_SELL_ORDERS_VOLUME);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_OPEN)]                     = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_OPEN);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_CLOSE)]                    = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_CLOSE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_AW)]                       = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_AW);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT)]         = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_PRICE_SETTLEMENT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN)]          = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_PRICE_LIMIT_MIN);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX)]          = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_PRICE_LIMIT_MAX);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_BID)]                              = this.m_tick.bid;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASK)]                              = this.m_tick.ask;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_LAST)]                             = this.m_tick.last;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDHIGH)]                          = this.SymbolBidHigh();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDLOW)]                           = this.SymbolBidLow();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_REAL)]                      = this.SymbolVolumeReal();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMEHIGH_REAL)]                  = this.SymbolVolumeHighReal();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMELOW_REAL)]                   = this.SymbolVolumeLowReal();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_OPTION_STRIKE)]                    = this.SymbolOptionStrike();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_ACCRUED_INTEREST)]           = this.SymbolTradeAccruedInterest();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_FACE_VALUE)]                 = this.SymbolTradeFaceValue();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_LIQUIDITY_RATE)]             = this.SymbolTradeLiquidityRate();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_HEDGED)]                    = this.SymbolMarginHedged();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_INITIAL)]              = this.m_margin_rate.Long.Initial;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL)]          = this.m_margin_rate.BuyStop.Initial;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL)]         = this.m_margin_rate.BuyLimit.Initial;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL)]     = this.m_margin_rate.BuyStopLimit.Initial;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE)]          = this.m_margin_rate.Long.Maintenance;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE)]      = this.m_margin_rate.BuyStop.Maintenance;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE)]     = this.m_margin_rate.BuyLimit.Maintenance;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE)] = this.m_margin_rate.BuyStopLimit.Maintenance;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_INITIAL)]             = this.m_margin_rate.Short.Initial;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL)]         = this.m_margin_rate.SellStop.Initial;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL)]        = this.m_margin_rate.SellLimit.Initial;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL)]    = this.m_margin_rate.SellStopLimit.Initial;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE)]         = this.m_margin_rate.Short.Maintenance;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE)]     = this.m_margin_rate.SellStop.Maintenance;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE)]    = this.m_margin_rate.SellLimit.Maintenance;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE)]= this.m_margin_rate.SellStopLimit.Maintenance;
//--- Sichern der String-Eigenschaften
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_NAME)]                             = this.m_name;
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_BASE)]                    = ::SymbolInfoString(this.m_name,SYMBOL_CURRENCY_BASE);
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_PROFIT)]                  = ::SymbolInfoString(this.m_name,SYMBOL_CURRENCY_PROFIT);
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_MARGIN)]                  = ::SymbolInfoString(this.m_name,SYMBOL_CURRENCY_MARGIN);
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_DESCRIPTION)]                      = ::SymbolInfoString(this.m_name,SYMBOL_DESCRIPTION);
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_PATH)]                             = ::SymbolInfoString(this.m_name,SYMBOL_PATH);
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_BASIS)]                            = this.SymbolBasis();
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_BANK)]                             = this.SymbolBank();
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_ISIN)]                             = this.SymbolISIN();
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_FORMULA)]                          = this.SymbolFormula();
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_PAGE)]                             = this.SymbolPage();
//--- Sichern weiterer ganzzahliger Eigenschaften
   this.m_long_prop[SYMBOL_PROP_DIGITS_LOTS]                                        = this.SymbolDigitsLot();
//---
   if(!select)
      this.RemoveFromMarketWatch();
  }
//+------------------------------------------------------------------+


Nun empfängt der Konstruktor den Symbolindex in der Marktübersicht, der Symbolname wird dem Objektnamen zugeordnet und die Struktur der bisherigen Symboldaten wird zurückgesetzt. Das bisherige Datenstrukturfeld trade_mode bietet WRONG_VALUE (das Vorhandensein dieses Wertes im Symbolhandelsmodusfeld erlaubt es uns, den ersten Start zu definieren). Die Variablen der Symbol-Eigenschaften changed und controlled werden initialisiert. Der an den Konstrukteur übergebene Index wird in die Symboleigenschaft "Market Watch window index" geschrieben.

Da wir nun die Variable m_name in der Basisklasse CBaseObj haben, um den Objektnamen zu speichern (in unserem Fall ist es ein Symbolname), sollte die Klasse CSymbol nicht mehr die Variable m_symbol_name haben. Alle seine Vorkommen sollten durch m_name ersetzt werden ( ein Symbolname wird im Klassenkonstruktor vergeben).
Markieren Sie eines der this.m_symbol_nameTextvorkommen im CSymbol Klassenverzeichnis und drücken Sie Ctrl+H. Das Fenster Suchen und Ersetzen erscheint mit dem markierten Vorkommen, das bereits in das Suchfeld eingefügt wurde. Geben Sie this.m_name in das Ersetzungsfeld ein und ersetzen Sie alle erkannten Vorkommen this.m_symbol_name durch this.m_name in der Auflistung.
Wir sollten auch die restlichen Klassenvariablen entfernen, die sich nun im Basisobjekt CBaseObj befinden. Ihr Vorhandensein im CSymbol löst während der Kompilierung die Warnung vor variabler Duplikation aus. In den unten angehängten Dateien wurden alle diese Variablen bereits entfernt. Laden Sie einfach die Dateien herunter und werfen Sie einen Blick auf deren Inhalt.

Hinzufügen der Beschreibung der neuen Symboleigenschaft "Market Watch window index" zu dem Verfahren, das die Beschreibung einer ganzzahligen Eigenschaft zurückgibt:

//+------------------------------------------------------------------+
//| Return the description of the symbol integer property            |
//+------------------------------------------------------------------+
string CSymbol::GetPropertyDescription(ENUM_SYMBOL_PROP_INTEGER property)
  {
   return
     (
      property==SYMBOL_PROP_STATUS              ?  TextByLanguage("Статус","Status")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SYMBOL_PROP_INDEX_MW            ?  TextByLanguage("Индекс в окне \"Обзор рынка\"","Index in the \"Market Watch window\"")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+this.GetStatusDescription()
         )  :
      property==SYMBOL_PROP_CUSTOM              ?  TextByLanguage("Пользовательский символ","Custom symbol")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property)   ?  TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))
         )  :
      property==SYMBOL_PROP_CHART_MODE          ?  TextByLanguage("Тип цены для построения баров","Price type used for generating symbols bars")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+this.GetChartModeDescription()
         )  :
      property==SYMBOL_PROP_EXIST               ?  TextByLanguage("Символ с таким именем существует","Symbol with this name exists")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property)   ?  TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))
         )  :
      property==SYMBOL_PROP_SELECT  ?  TextByLanguage("Символ выбран в Market Watch","Symbol selected in Market Watch")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property)   ?  TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))
         )  :
      property==SYMBOL_PROP_VISIBLE ?  TextByLanguage("Символ отображается в Market Watch","Symbol visible in Market Watch")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property)   ?  TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))
         )  :
      property==SYMBOL_PROP_SESSION_DEALS       ?  TextByLanguage("Количество сделок в текущей сессии","Number of deals in the current session")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_SESSION_BUY_ORDERS  ?  TextByLanguage("Общее число ордеров на покупку в текущий момент","Number of Buy orders at the moment")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_SESSION_SELL_ORDERS ?  TextByLanguage("Общее число ордеров на продажу в текущий момент","Number of Sell orders at the moment")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_VOLUME              ?  TextByLanguage("Объем в последней сделке","Volume of the last deal")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_VOLUMEHIGH          ?  TextByLanguage("Максимальный объём за день","Maximal day volume")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_VOLUMELOW           ?  TextByLanguage("Минимальный объём за день","Minimal day volume")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_TIME                ?  TextByLanguage("Время последней котировки","Time of the last quote")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property)==0 ? TextByLanguage("(Ещё не было тиков)","(No ticks yet)") : TimeMSCtoString(this.GetProperty(property)))
         )  :
      property==SYMBOL_PROP_DIGITS              ?  TextByLanguage("Количество знаков после запятой","Digits after decimal point")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SYMBOL_PROP_DIGITS_LOTS         ?  TextByLanguage("Количество знаков после запятой в значении лота","Digits after decimal point in the value of the lot")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SYMBOL_PROP_SPREAD              ?  TextByLanguage("Размер спреда в пунктах","Spread value in points")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SYMBOL_PROP_SPREAD_FLOAT        ?  TextByLanguage("Плавающий спред","Spread is floating")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property)   ?  TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))
         )  :
      property==SYMBOL_PROP_TICKS_BOOKDEPTH     ?  TextByLanguage("Максимальное количество показываемых заявок в стакане","Maximal number of requests shown in Depth of Market")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_TRADE_CALC_MODE     ?  TextByLanguage("Способ вычисления стоимости контракта","Contract price calculation mode")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+this.GetCalcModeDescription()
         )  :
      property==SYMBOL_PROP_TRADE_MODE ?  TextByLanguage("Тип исполнения ордеров","Order execution type")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+this.GetTradeModeDescription()
         )  :
      property==SYMBOL_PROP_START_TIME          ?  TextByLanguage("Дата начала торгов по инструменту","Date of symbol trade beginning")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
         (this.GetProperty(property)==0  ?  TextByLanguage(": (Отсутствует)",": (Not set)") : ": "+TimeMSCtoString(this.GetProperty(property)*1000))
         )  :
      property==SYMBOL_PROP_EXPIRATION_TIME     ?  TextByLanguage("Дата окончания торгов по инструменту","Date of symbol trade end")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
         (this.GetProperty(property)==0  ?  TextByLanguage(": (Отсутствует)",": (Not set)") : ": "+TimeMSCtoString(this.GetProperty(property)*1000))
         )  :
      property==SYMBOL_PROP_TRADE_STOPS_LEVEL   ?  TextByLanguage("Минимальный отступ от цены закрытия для установки Stop ордеров","Minimal indention from close price to place Stop orders")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SYMBOL_PROP_TRADE_FREEZE_LEVEL  ?  TextByLanguage("Дистанция заморозки торговых операций","Distance to freeze trade operations in points")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SYMBOL_PROP_TRADE_EXEMODE       ?  TextByLanguage("Режим заключения сделок","Deal execution mode")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+this.GetTradeExecDescription()
         )  :
      property==SYMBOL_PROP_SWAP_MODE           ?  TextByLanguage("Модель расчета свопа","Swap calculation model")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+this.GetSwapModeDescription()
         )  :
      property==SYMBOL_PROP_SWAP_ROLLOVER3DAYS  ?  TextByLanguage("День недели для начисления тройного свопа","Day of week to charge 3 days swap rollover")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+DayOfWeekDescription(this.SwapRollover3Days())
         )  :
      property==SYMBOL_PROP_MARGIN_HEDGED_USE_LEG  ?  TextByLanguage("Расчет хеджированной маржи по наибольшей стороне","Calculating hedging margin using the larger leg")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property)   ?  TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))
         )  :
      property==SYMBOL_PROP_EXPIRATION_MODE     ?  TextByLanguage("Флаги разрешенных режимов истечения ордера","Flags of allowed order expiration modes")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+this.GetExpirationModeFlagsDescription()
         )  :
      property==SYMBOL_PROP_FILLING_MODE        ?  TextByLanguage("Флаги разрешенных режимов заливки ордера","Flags of allowed order filling modes")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+this.GetFillingModeFlagsDescription()
         )  :
      property==SYMBOL_PROP_ORDER_MODE          ?  TextByLanguage("Флаги разрешённых типов ордеров","Flags of allowed order types")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+this.GetOrderModeFlagsDescription()
         )  :
      property==SYMBOL_PROP_ORDER_GTC_MODE      ?  TextByLanguage("Срок действия StopLoss и TakeProfit ордеров","Expiration of Stop Loss and Take Profit orders")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+this.GetOrderGTCModeDescription()
         )  :
      property==SYMBOL_PROP_OPTION_MODE         ?  TextByLanguage("Тип опциона","Option type")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+this.GetOptionTypeDescription()
         )  :
      property==SYMBOL_PROP_OPTION_RIGHT        ?  TextByLanguage("Право опциона","Option right")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+this.GetOptionRightDescription()
         )  :
      property==SYMBOL_PROP_BACKGROUND_COLOR    ?  TextByLanguage("Цвет фона символа в Market Watch","Background color of symbol in Market Watch")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
         #ifdef __MQL5__
         (this.GetProperty(property)==CLR_DEFAULT || this.GetProperty(property)==CLR_NONE ?  TextByLanguage(": (Отсутствует)",": (Not set)") : ": "+::ColorToString((color)this.GetProperty(property),true))
         #else TextByLanguage(": Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif 
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+


Entfernen Sie die zweite Form der Methode Exist() und die Methode, die die Anzahl der Dezimalstellen des Zahlenwerts zurückgibt, aus der Implementierungsliste der Klassenmethoden von CSymbol:

//+------------------------------------------------------------------+
bool CSymbol::Exist(const string name) const
  {
   int total=::SymbolsTotal(false);
   for(int i=0;i<total;i++)
      if(::SymbolName(i,false)==name)
         return true;
   return false;
  }
//+------------------------------------------------------------------+
//| Return the number of decimal places in the 'double' value        |
//+------------------------------------------------------------------+
int CSymbol::GetDigits(const double value) const
  {
   string val_str=(string)value;
   int len=::StringLen(val_str);
   int n=len-::StringFind(val_str,".",0)-1;
   if(::StringSubstr(val_str,len-1,1)=="0")
      n--;
   return n;
  }
//+------------------------------------------------------------------+


Diese Methoden sind hier einfach redundant — Exist() mit dem Eingabeparameter wird in dieser Klasse nicht benötigt. Deshalb habe ich es in die Datei der Servicefunktionen DELib.mqh verschoben, was der richtige Ort dafür ist, während GetDigits() sich nun in der Basisklasse CBaseObj befindet.

Die Methode Refresh() der Klasse CSymbol wird vom Timer gestartet und aktualisiert alle Symboldaten. Wir werden nach Änderungen der Symboleigenschaften in der gleichen Methode suchen. Wir haben eine andere Methode — RefreshRates(), die ebenfalls vom Timer gestartet wird, aber mit einer höheren Aktualisierungsrate. Bei dieser Methode werden nur die Daten der Symbolangebote aktualisiert. Wenn wir die Suche nach Änderungen der Symboleigenschaften in beiden Methoden implementieren, führt dies zu einer Duplizierung von Ereignismeldungen.
Die mögliche Lösung ist wie folgt: Die Methode RefreshRates() aktualisiert die Kursdaten und gibt das Flag des erfolgreichen Empfangs zurück. Die Methode wird wie bisher von ihrem Timer aus aufgerufen. Aber auch die Möglichkeit, sie von der Methode Refresh() aus aufzurufen, wird hinzugefügt. Somit werden beide Methoden wie bisher aufgerufen — jede in ihrem Timer, während die Suche nach Änderungen der Symboleigenschaften nur in der Methode Refresh() durchgeführt wird.

Fügen wir die notwendigen Änderungen an den Methoden RefreshRates() und Refresh() hinzu:

//+------------------------------------------------------------------+
//| Update quote data by a symbol                                    |
//+------------------------------------------------------------------+
bool CSymbol::RefreshRates(void)
  {
//--- Get quote data
   ::ResetLastError();
   if(!::SymbolInfoTick(this.m_name,this.m_tick))
     {
      this.m_global_error=::GetLastError();
      return false;
     }
//--- Update integer properties
   this.m_long_prop[SYMBOL_PROP_VOLUME]                                             = (long)this.m_tick.volume;
   this.m_long_prop[SYMBOL_PROP_TIME]                                               = this.TickTime();
//--- Update real properties
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASK)]                              = this.m_tick.ask;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKHIGH)]                          = ::SymbolInfoDouble(this.m_name,SYMBOL_ASKHIGH);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKLOW)]                           = ::SymbolInfoDouble(this.m_name,SYMBOL_ASKLOW);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_BID)]                              = this.m_tick.bid;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDHIGH)]                          = this.SymbolBidHigh();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDLOW)]                           = this.SymbolBidLow();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_LAST)]                             = this.m_tick.last;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTHIGH)]                         = ::SymbolInfoDouble(this.m_name,SYMBOL_LASTHIGH);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTLOW)]                          = ::SymbolInfoDouble(this.m_name,SYMBOL_LASTLOW);
   return true;
  }  
//+------------------------------------------------------------------+


Zuerst erhalten Sie die Symbol-Anführungsdaten. Wenn es nicht gelungen ist, es zu erhalten, schreiben Sie den Fehlercode und beenden Sie die Methode, die false zurückgibt. Wenn Daten erhalten wurden, werden die notwendigen Symboleigenschaften eingetragen und true zurückgegeben.

//+------------------------------------------------------------------+
//| Update all symbol data                                           |
//+------------------------------------------------------------------+
void CSymbol::Refresh(void)
  {
//--- Update quote data
   if(!this.RefreshRates())
      return;
#ifdef __MQL5__
   ::ResetLastError();
   if(!this.MarginRates())
     {
      this.m_global_error=::GetLastError();
      return;
     }
#endif 
//--- Prepare event data
   this.m_is_event=false;
   ::ZeroMemory(this.m_struct_curr_symbol);
   this.m_hash_sum=0;
//--- Update integer properties
   this.m_long_prop[SYMBOL_PROP_SELECT]                                             = ::SymbolInfoInteger(this.m_name,SYMBOL_SELECT);
   this.m_long_prop[SYMBOL_PROP_VISIBLE]                                            = ::SymbolInfoInteger(this.m_name,SYMBOL_VISIBLE);
   this.m_long_prop[SYMBOL_PROP_SESSION_DEALS]                                      = ::SymbolInfoInteger(this.m_name,SYMBOL_SESSION_DEALS);
   this.m_long_prop[SYMBOL_PROP_SESSION_BUY_ORDERS]                                 = ::SymbolInfoInteger(this.m_name,SYMBOL_SESSION_BUY_ORDERS);
   this.m_long_prop[SYMBOL_PROP_SESSION_SELL_ORDERS]                                = ::SymbolInfoInteger(this.m_name,SYMBOL_SESSION_SELL_ORDERS);
   this.m_long_prop[SYMBOL_PROP_VOLUMEHIGH]                                         = ::SymbolInfoInteger(this.m_name,SYMBOL_VOLUMEHIGH);
   this.m_long_prop[SYMBOL_PROP_VOLUMELOW]                                          = ::SymbolInfoInteger(this.m_name,SYMBOL_VOLUMELOW);
   this.m_long_prop[SYMBOL_PROP_SPREAD]                                             = ::SymbolInfoInteger(this.m_name,SYMBOL_SPREAD);
   this.m_long_prop[SYMBOL_PROP_TICKS_BOOKDEPTH]                                    = ::SymbolInfoInteger(this.m_name,SYMBOL_TICKS_BOOKDEPTH);
   this.m_long_prop[SYMBOL_PROP_START_TIME]                                         = ::SymbolInfoInteger(this.m_name,SYMBOL_START_TIME);
   this.m_long_prop[SYMBOL_PROP_EXPIRATION_TIME]                                    = ::SymbolInfoInteger(this.m_name,SYMBOL_EXPIRATION_TIME);
   this.m_long_prop[SYMBOL_PROP_TRADE_STOPS_LEVEL]                                  = ::SymbolInfoInteger(this.m_name,SYMBOL_TRADE_STOPS_LEVEL);
   this.m_long_prop[SYMBOL_PROP_TRADE_FREEZE_LEVEL]                                 = ::SymbolInfoInteger(this.m_name,SYMBOL_TRADE_FREEZE_LEVEL);
   this.m_long_prop[SYMBOL_PROP_BACKGROUND_COLOR]                                   = this.SymbolBackgroundColor();

//--- Update real properties
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE)]                 = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_VALUE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT)]          = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_VALUE_PROFIT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS)]            = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_VALUE_LOSS);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_SIZE)]                  = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_SIZE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_CONTRACT_SIZE)]              = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_CONTRACT_SIZE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MIN)]                       = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_MIN);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MAX)]                       = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_MAX);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_STEP)]                      = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_STEP);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_LIMIT)]                     = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_LIMIT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_LONG)]                        = ::SymbolInfoDouble(this.m_name,SYMBOL_SWAP_LONG);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_SHORT)]                       = ::SymbolInfoDouble(this.m_name,SYMBOL_SWAP_SHORT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_INITIAL)]                   = ::SymbolInfoDouble(this.m_name,SYMBOL_MARGIN_INITIAL);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_MAINTENANCE)]               = ::SymbolInfoDouble(this.m_name,SYMBOL_MARGIN_MAINTENANCE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_VOLUME)]                   = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_VOLUME);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_TURNOVER)]                 = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_TURNOVER);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_INTEREST)]                 = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_INTEREST);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME)]        = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_BUY_ORDERS_VOLUME);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME)]       = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_SELL_ORDERS_VOLUME);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_OPEN)]                     = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_OPEN);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_CLOSE)]                    = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_CLOSE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_AW)]                       = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_AW);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT)]         = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_PRICE_SETTLEMENT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN)]          = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_PRICE_LIMIT_MIN);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX)]          = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_PRICE_LIMIT_MAX);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_REAL)]                      = this.SymbolVolumeReal();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMEHIGH_REAL)]                  = this.SymbolVolumeHighReal();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMELOW_REAL)]                   = this.SymbolVolumeLowReal();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_OPTION_STRIKE)]                    = this.SymbolOptionStrike();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_ACCRUED_INTEREST)]           = this.SymbolTradeAccruedInterest();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_FACE_VALUE)]                 = this.SymbolTradeFaceValue();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_LIQUIDITY_RATE)]             = this.SymbolTradeLiquidityRate();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_HEDGED)]                    = this.SymbolMarginHedged();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_INITIAL)]              = this.m_margin_rate.Long.Initial;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL)]          = this.m_margin_rate.BuyStop.Initial;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL)]         = this.m_margin_rate.BuyLimit.Initial;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL)]     = this.m_margin_rate.BuyStopLimit.Initial;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE)]          = this.m_margin_rate.Long.Maintenance;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE)]      = this.m_margin_rate.BuyStop.Maintenance;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE)]     = this.m_margin_rate.BuyLimit.Maintenance;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE)] = this.m_margin_rate.BuyStopLimit.Maintenance;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_INITIAL)]             = this.m_margin_rate.Short.Initial;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL)]         = this.m_margin_rate.SellStop.Initial;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL)]        = this.m_margin_rate.SellLimit.Initial;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL)]    = this.m_margin_rate.SellStopLimit.Initial;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE)]         = this.m_margin_rate.Short.Maintenance;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE)]     = this.m_margin_rate.SellStop.Maintenance;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE)]    = this.m_margin_rate.SellLimit.Maintenance;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE)]= this.m_margin_rate.SellStopLimit.Maintenance;
   
//--- Fill in the current symbol data structure
   this.m_struct_curr_symbol.ask                                                    = this.Ask();
   this.m_struct_curr_symbol.ask_high                                               = this.AskHigh();
   this.m_struct_curr_symbol.ask_low                                                = this.AskLow();
   this.m_struct_curr_symbol.bid_last                                               = (this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.Bid() : this.Last());
   this.m_struct_curr_symbol.bid_last_high                                          = (this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.BidHigh() : this.LastHigh());
   this.m_struct_curr_symbol.bid_last_low                                           = (this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.BidLow() : this.LastLow());
   this.m_struct_curr_symbol.volume                                                 = this.Volume();
   this.m_struct_curr_symbol.session_deals                                          = this.SessionDeals();
   this.m_struct_curr_symbol.session_buy_orders                                     = this.SessionBuyOrders();
   this.m_struct_curr_symbol.session_sell_orders                                    = this.SessionSellOrders();
   this.m_struct_curr_symbol.volume_high_day                                        = this.VolumeHigh();
   this.m_struct_curr_symbol.volume_low_day                                         = this.VolumeLow();
   this.m_struct_curr_symbol.spread                                                 = this.Spread();
   this.m_struct_curr_symbol.stops_level                                            = this.TradeStopLevel();
   this.m_struct_curr_symbol.freeze_level                                           = this.TradeFreezeLevel();
   this.m_struct_curr_symbol.volume_limit                                           = this.VolumeLimit();
   this.m_struct_curr_symbol.swap_long                                              = this.SwapLong();
   this.m_struct_curr_symbol.swap_short                                             = this.SwapShort();
   this.m_struct_curr_symbol.session_volume                                         = this.SessionVolume();
   this.m_struct_curr_symbol.session_turnover                                       = this.SessionTurnover();
   this.m_struct_curr_symbol.session_interest                                       = this.SessionInterest();
   this.m_struct_curr_symbol.session_buy_ord_volume                                 = this.SessionBuyOrdersVolume();
   this.m_struct_curr_symbol.session_sell_ord_volume                                = this.SessionSellOrdersVolume();
   this.m_struct_curr_symbol.session_open                                           = this.SessionOpen();
   this.m_struct_curr_symbol.session_close                                          = this.SessionClose();
   this.m_struct_curr_symbol.session_aw                                             = this.SessionAW();
   this.m_struct_curr_symbol.volume_real_day                                        = this.VolumeReal();
   this.m_struct_curr_symbol.volume_high_real_day                                   = this.VolumeHighReal();
   this.m_struct_curr_symbol.volume_low_real_day                                    = this.VolumeLowReal();
   this.m_struct_curr_symbol.option_strike                                          = this.OptionStrike();
   this.m_struct_curr_symbol.trade_mode                                             = this.TradeMode();

//--- Hash sum calculation
   this.m_hash_sum+=(double)this.m_struct_curr_symbol.volume;
   this.m_hash_sum+=(double)this.m_struct_curr_symbol.session_deals;
   this.m_hash_sum+=(double)this.m_struct_curr_symbol.session_buy_orders;
   this.m_hash_sum+=(double)this.m_struct_curr_symbol.session_sell_orders;
   this.m_hash_sum+=(double)this.m_struct_curr_symbol.volume_high_day;
   this.m_hash_sum+=(double)this.m_struct_curr_symbol.volume_low_day;
   this.m_hash_sum+=(double)this.m_struct_curr_symbol.spread;
   this.m_hash_sum+=(double)this.m_struct_curr_symbol.stops_level;
   this.m_hash_sum+=(double)this.m_struct_curr_symbol.freeze_level;
   this.m_hash_sum+=this.m_struct_curr_symbol.ask;
   this.m_hash_sum+=this.m_struct_curr_symbol.ask_high;
   this.m_hash_sum+=this.m_struct_curr_symbol.ask_low;
   this.m_hash_sum+=this.m_struct_curr_symbol.bid_last;
   this.m_hash_sum+=this.m_struct_curr_symbol.bid_last_high;
   this.m_hash_sum+=this.m_struct_curr_symbol.bid_last_low;
   this.m_hash_sum+=this.m_struct_curr_symbol.volume_limit;
   this.m_hash_sum+=this.m_struct_curr_symbol.swap_long;
   this.m_hash_sum+=this.m_struct_curr_symbol.swap_short;
   this.m_hash_sum+=this.m_struct_curr_symbol.session_volume;
   this.m_hash_sum+=this.m_struct_curr_symbol.session_turnover;
   this.m_hash_sum+=this.m_struct_curr_symbol.session_interest;
   this.m_hash_sum+=this.m_struct_curr_symbol.session_buy_ord_volume;
   this.m_hash_sum+=this.m_struct_curr_symbol.session_sell_ord_volume;
   this.m_hash_sum+=this.m_struct_curr_symbol.session_open;
   this.m_hash_sum+=this.m_struct_curr_symbol.session_close;
   this.m_hash_sum+=this.m_struct_curr_symbol.session_aw;
   this.m_hash_sum+=this.m_struct_curr_symbol.volume_real_day;
   this.m_hash_sum+=this.m_struct_curr_symbol.volume_high_real_day;
   this.m_hash_sum+=this.m_struct_curr_symbol.volume_low_real_day;
   this.m_hash_sum+=this.m_struct_curr_symbol.option_strike;
   this.m_hash_sum+=this.m_struct_curr_symbol.trade_mode;

//--- Erster Start
   if(this.m_struct_prev_symbol.trade_mode==WRONG_VALUE)
     {
      this.m_struct_prev_symbol=this.m_struct_curr_symbol;
      this.m_hash_sum_prev=this.m_hash_sum;
      return;
     }
//--- If symbol's hash sum changed
   if(this.m_hash_sum!=this.m_hash_sum_prev)
     {
      this.m_event_code=this.SetEventCode();
      this.SetTypeEvent();
      CEventBaseObj *event=this.GetEvent(WRONG_VALUE,false);
      if(event!=NULL)
        {
         ENUM_SYMBOL_EVENT event_id=(ENUM_SYMBOL_EVENT)event.ID();
         if(event_id!=SYMBOL_EVENT_NO_EVENT)
           {
            this.m_is_event=true;
           }
        }
      this.m_hash_sum_prev=this.m_hash_sum;
     }
  }
//+------------------------------------------------------------------+


Hier rufen wir zunächst die Methode RefreshRates() auf. Wenn es nicht gelungen ist, die Kursdaten zu erhalten, macht es keinen Sinn, die restlichen Daten zu übernehmen. Beenden Sie die Methode.
Als Nächstes setzen Sie das Ereignisflag, die Struktur der aktuellen Symboleigenschaften gibt und die aktuelle Hash-Summe zurück. Füllen Sie dann alle Symboleigenschaften mit aktuellen Daten und schreiben Sie diese Daten in die Struktur der aktuellen Symboleigenschaften Zustände. Nach dem Ausfüllen der Struktur berechnen Sie die Hash-Summe.
Wenn dies der erste Start ist (die Symboleigenschaft SYMBOL_TRADE_MODE wird auf WRONG_VALUE gesetzt), speichern Sie die Werte der aktuellen Statusstruktur in die vorherige Statusstruktur, schreiben Sie die aktuelle Hash-Summe auf die aktuelle 1 und verlassen Sie die Methode.
Wenn dies nicht der erste Start ist, müssen wir die vorherigen und aktuellen Hash-Summen auf Ungleichheit überprüfen.
Wenn sich die Hash-Summe geändert hat, hat sich
eine Symboleigenschaft geändert. Rufen Sie die Methode zum Platzieren eines Ereigniscodes, die Methode zum Empfangen eines Ereignisses aus dem Ereigniscode und Ereigniseinträgen in der Liste der aufgetretenen Ereignisse und das letzte Ereignis von den neu hinzugefügten Ereignissen auf. Überprüfen Sie den Ereignistyp. Wenn es nicht "No event" ist, aktivieren Sie das Ereignis-Flag. Speichern Sie schließlich die aktuelle Hash-Summe als die vorherige für weitere Prüfungen.

Damit ist die Verbesserung der Klasse CSymbol für die Suche nach Ereignissen und die Arbeit mit einem neuen Basisobjekt abgeschlossen.

Die Klasse der Symbolobjekte ist fertig. Jetzt ist jedes Symbol in der Lage, seine Ereignisse zu verfolgen und in seine Ereignisliste aufzunehmen. Da wir die Symbolkollektion verwenden, müssen wir durch alle Kollektionssymbole gehen und von jedem von ihnen eine Ereignisliste erhalten. Alle diese Ereignisse sollten in die Liste der Sammelereignisse aufgenommen werden (die Kollektion enthält nun die gleiche Liste, da sie sich im Basisobjekt CBaseObj befindet). Es bleibt also nur noch, die erhaltene Ereignisliste zu überblicken, um eine Tatsache zu definieren, dass bei jedem der Kollektionssymbole ein Ereignis oder mehrere Ereignisse aufgetreten sind.

Außerdem können wir mit dem Fenster der Marktübersicht arbeiten. Lassen Sie uns auch die Ereignisverfolgung dafür implementieren, wie z.B. das Hinzufügen/Entfernen eines Symbols und das Sortieren von Symbolen. Dazu müssen wir den Snapshot des Market Watch-Fensters und die Hash-Summe der darin enthaltenen Symbole speichern. Wenn sich die Hash-Summe ändert, verstehen wir nun, dass ein Marktbeobachtungsereignis stattgefunden hat. Es bleibt nur noch, das Ereignis zu bestimmen, indem man den aktuellen Status des Marktübersicht-Fensters mit dem Snapshot vergleicht und ein identifiziertes Ereignis an das Steuerungsprogramm sendet.

Öffnen Sie die Datei SymbolsCollection.mqh der Klasse der Symbolkollektion und nehmen Sie die notwendigen Änderungen vor:

//+------------------------------------------------------------------+
//|                                            SymbolsCollection.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/de/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/de/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include-Dateien                                                  |
//+------------------------------------------------------------------+
#include <Arrays\ArrayString.mqh>
#include "ListObj.mqh"
#include "..\Services\Select.mqh"
#include "..\Objects\Symbols\Symbol.mqh"
#include "..\Objects\Symbols\SymbolFX.mqh"
#include "..\Objects\Symbols\SymbolFXMajor.mqh"
#include "..\Objects\Symbols\SymbolFXMinor.mqh"
#include "..\Objects\Symbols\SymbolFXExotic.mqh"
#include "..\Objects\Symbols\SymbolFXRub.mqh"
#include "..\Objects\Symbols\SymbolMetall.mqh"
#include "..\Objects\Symbols\SymbolIndex.mqh"
#include "..\Objects\Symbols\SymbolIndicative.mqh"
#include "..\Objects\Symbols\SymbolCrypto.mqh"
#include "..\Objects\Symbols\SymbolCommodity.mqh"
#include "..\Objects\Symbols\SymbolExchange.mqh"
#include "..\Objects\Symbols\SymbolFutures.mqh"
#include "..\Objects\Symbols\SymbolCFD.mqh"
#include "..\Objects\Symbols\SymbolStocks.mqh"
#include "..\Objects\Symbols\SymbolBonds.mqh"
#include "..\Objects\Symbols\SymbolOption.mqh"
#include "..\Objects\Symbols\SymbolCollateral.mqh"
#include "..\Objects\Symbols\SymbolCustom.mqh"
#include "..\Objects\Symbols\SymbolCommon.mqh"
//+------------------------------------------------------------------+
//| Symbol collection                                                |
//+------------------------------------------------------------------+
class CSymbolsCollection : public CBaseObj
  {
private:
   CListObj          m_list_all_symbols;                          // The list of all symbol objects
   CArrayString      m_list_names;                                // Symbol name control list
   ENUM_SYMBOLS_MODE m_mode_list;                                 // Mode of working with symbol lists
   ENUM_SYMBOL_EVENT m_last_event;                                // The last event
   string            m_array_symbols[];                           // The array of used symbols passed from the program
   int               m_delta_symbol;                              // Difference in the number of symbols compared to the previous check
   int               m_total_symbols;                             // Number of symbols in the Market Watch window
   int               m_total_symbol_prev;                         // Number of symbols in the Market Watch window during the previous check
//--- Return the flag of a symbol object presence by its name in the (1) list of all symbols, (2) Market Watch window, (3) control list
   bool              IsPresentSymbolInList(const string symbol_name);
   bool              IsPresentSymbolInMW(const string symbol_name);
   bool              IsPresentSymbolInControlList(const string symbol_name);
//--- Create the symbol object and place it to the list
   bool              CreateNewSymbol(const ENUM_SYMBOL_STATUS symbol_status,const string name,const int index);
//--- Return the (1) type of a used symbol list (Market watch/Server),
//--- (2) the number of visible symbols, (3) symbol index in the Market Watch window
   ENUM_SYMBOLS_MODE TypeSymbolsList(const string &symbol_used_array[]);
   int               SymbolsTotalVisible(void)                    const;
   int               SymbolIndexInMW(const string name)           const;
   
//--- Define a symbol affiliation with a group by name and return it
   ENUM_SYMBOL_STATUS SymbolStatus(const string symbol_name)      const;
//--- Return a symbol affiliation with a category by custom criteria
   ENUM_SYMBOL_STATUS StatusByCustomPredefined(const string symbol_name)  const;
//--- Return a symbol affiliation with categories by margin calculation
   ENUM_SYMBOL_STATUS StatusByCalcMode(const string symbol_name)  const;
//--- Return a symbol affiliation with pre-defined (1) majors, (2) minors, (3) exotics, (4) RUB,
//--- (5) indicatives, (6) metals, (7) commodities, (8) indices, (9) cryptocurrency, (10) options
   bool              IsPredefinedFXMajor(const string name)       const;
   bool              IsPredefinedFXMinor(const string name)       const;
   bool              IsPredefinedFXExotic(const string name)      const;
   bool              IsPredefinedFXRUB(const string name)         const;
   bool              IsPredefinedIndicative(const string name)    const;
   bool              IsPredefinedMetall(const string name)        const;
   bool              IsPredefinedCommodity(const string name)     const;
   bool              IsPredefinedIndex(const string name)         const;
   bool              IsPredefinedCrypto(const string name)        const;
   bool              IsPredefinedOption(const string name)        const;

public:
//--- Rückgabe der ganzen Collection 'wie besehen'
   CArrayObj        *GetList(void)                                                                          { return &this.m_list_all_symbols;                                      }
//--- Rückgabe der Auswahlliste von (1) Integer-, (2) Double- und (3) String-Eigenschaften, die dem Vergleichskriterium entsprechen
   CArrayObj        *GetList(ENUM_SYMBOL_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL)    { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); }
   CArrayObj        *GetList(ENUM_SYMBOL_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL)   { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); }
   CArrayObj        *GetList(ENUM_SYMBOL_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL)   { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); }
//--- Return the (1) symbol object, (2) the symbol object index from the list by a name
   CSymbol          *GetSymbolByName(const string name);
   int               GetSymbolIndexByName(const string name);
//--- Return the number of new symbols in the Market Watch window
   int               NewSymbols(void)    const                                                              { return this.m_delta_symbol;                                           }
//--- Return (1) the mode of working with symbol lists, (2) the event flag and (3) the event of one of the collection symbols
   ENUM_SYMBOLS_MODE ModeSymbolsList(void)                        const                                     { return this.m_mode_list;                                              }
   bool              IsEvent(void)                                const                                     { return this.m_is_event;                                               }
   int               GetLastEventsCode(void)                      const                                     { return this.m_event_code;                                             }
   ENUM_SYMBOL_EVENT GetLastEvent(void)                           const                                     { return this.m_last_event;                                             }
//--- Return the number of symbols in the collection
   int               GetSymbolsCollectionTotal(void)              const                                     { return this.m_list_all_symbols.Total();                               }

//--- Konstructor
                     CSymbolsCollection();
   
//--- (1) Set the list of used symbols, (2) creating the symbol list (Market Watch or the complete list)
   bool              SetUsedSymbols(const string &symbol_used_array[]);
   bool              CreateSymbolsList(const bool flag);
//--- Save names of used Market Watch symbols
   void              CopySymbolsNames(void);
//--- Update (1) all, (2) quote data of the collection symbols
   virtual void      Refresh(void);
   void              RefreshRates(void);
//--- Working with the events of the (1) collection symbol list, (2) market watch window
   void              SymbolsEventsControl(void);
   void              MarketWatchEventsControl(const bool send_events=true);
//--- Return the description of the (1) Market Watch window event, (2) mode of working with symbols
   string            EventDescription(const ENUM_SYMBOL_EVENT event);
   string            ModeSymbolsListDescription(void);
  };
//+------------------------------------------------------------------+


Die Klassendatei CArrayString aus der Standardbibliothek soll verwendet werden, um einen Snapshot des Fensters Marktübersicht zu erstellen. Diese Liste soll die Kopie des Symbolsatzes aus der Marktbeobachtung speichern und den aktuellen Status der Symbolleiste im Fenster mit dem im Snapshot vergleichen. Im Falle von Änderungen sollten wir auf sie reagieren, um das Fensterereignis Market Watch zu erstellen.

Das letzte Ereignis, das einem der Kollektionssymbole passiert ist, wird der Variablen m_last_event hinzugefügt. Somit speichert die Variable das letzte Ereignis, das bei einem der verwendeten Symbole aufgetreten ist.
Das Array m_array_symbols übergibt das Array der verwendeten Symbole aus dem Steuerprogramm an die Klasse der Symbolkollektion.
Die aktuelle und vorherige Anzahl der Symbole im Fenster Marktbeobachtung soll in den Variablen m_total_symbols und m_total_symbols_prev Klassenmitglieder gespeichert werden. Der Vergleich der Werte der Variablen ermöglicht es uns, die Ereignisse beim Hinzufügen und Entfernen von Symbolen aus der Marktbeobachtung zu definieren.

Die 'private' Methoden IsPresentSymbolInMW() und IsPresentSymbolInControlList() der Klasse liefern die Anwesenheitsflags des Symbols mit ihrem Namen im Fenster der Marktübersicht und der Snapshot-Liste des Fensters der Marktübersicht entsprechend zurück. Die Methoden SymbolsTotalVisible() und SymbolIndexInMW() geben die Anzahl der sichtbaren Symbole im Fenster der Marktübersicht und den Symbolindex in der Fensterliste entsprechend zurück.

Fügen Sie die folgenden Methoden zum öffentlichen Bereich der Klasse hinzu:
IsEvent() — gibt das Flag einer Event-Präsenz in der Symbolkollektion oder in der Marktübersicht zurück,
GetLastEventsCode() — gibt den Code des letzten Ereignisses in der Symbolkollektion oder in der Marktübersicht zurück,
GetLastEvent() — gibt das letzte Ereignis in der Symbolkollektion oder in der Marktübersicht zurück,
GetSymbolsCollectionTotal() — gibt die Gesamtzahl der Symbole in der Kollektion zurück,
CreateSymbolsList() — erstellt die Symbolkollektion, wenn man mit dem Fenster der Marktübersicht oder der vollständigen Liste der Symbole auf dem Server arbeitet (nicht mehr als 1000),
CopySymbolsNames() — erstellt eine Momentaufnahme der Marktübersicht aus der Liste aller Kollektionssymbole,
Refresh() — jetzt wird die Methode als virtuelle deklariert, da sie im Basisklassenobjekt als virtuelle deklariert wird (während die Symbolkollektion nun basierend auf der Basisobjektklasse CBaseObj erstellt wird),
SymbolsEventsControl() — das Verfahren zum Arbeiten mit der Symbolkollektion zur Definition der Ereignisse der Kollektionssymbole,
MarketWatchEventsControl() — Verfahren zum Arbeiten mit der Liste der Marktübersicht zur Definition von Ereignissen in der Marktübersicht,
EventDescription() — gibt eine Beschreibung der Ergebnisse der Kollektionssymbole zurück,
ModeSymbolsListDescription() — liefert eine Beschreibung der Arbeitsweise mit Symbolen.

Werfen wir einen Blick auf die Implementierung der Methoden.
Initialisieren Sie in der Initialisierungsliste des Konstruktors der Klasse die Variablen für die Arbeit mit dem Fenster der Marktübersicht. Ändern Sie im Klassenkörper die Sortierung der Liste der Kollektionssymbole von der Sortierung nach Name auf Sortierung nach Index im Fenster der Marktübersicht und Löschen Sie die Liste der Momentaufnahme der Marktübersicht.

//+------------------------------------------------------------------+
//| Konstruktor                                                      |
//+------------------------------------------------------------------+
CSymbolsCollection::CSymbolsCollection(void) : m_total_symbol_prev(0),
                                               m_delta_symbol(0),
                                               m_mode_list(SYMBOLS_MODE_CURRENT)
  {
   this.m_list_all_symbols.Sort(SORT_BY_SYMBOL_INDEX_MW);
   this.m_list_all_symbols.Clear();
   this.m_list_all_symbols.Type(COLLECTION_SYMBOLS_ID);
   this.m_list_names.Clear();
  }
//+------------------------------------------------------------------+


Da einige Symbole im Fenster der Marktübersicht möglicherweise nicht sichtbar aber dort noch vorhanden sind (SYMBOL_VISIBLE Symbol-Eigenschaft), werden einige Symbole (in der Regel sind dies Symbole, die für die Berechnung der Margenanforderungen und den Gewinn in der Depotwährung erforderlich sind) automatisch ausgewählt und in der Marktübersicht nicht angezeigt. Um also nur die Anzahl der sichtbaren Symbole zu ermitteln, müssen wir nur Symbole berechnen, die diese Eigenschaft in einer Schleife durch Fenstersymbole gesetzt haben.
Die Methode SymbolsTotalVisible() gibt die Anzahl der sichtbaren Symbole im Fenster der Marktübersicht zurück:

//+------------------------------------------------------------------+
//| Return the number of visible symbols in the Market Watch window  |
//+------------------------------------------------------------------+
int CSymbolsCollection::SymbolsTotalVisible(void) const
  {
   int total=::SymbolsTotal(true),n=0;
   for(int i=0;i<total;i++)
     {
      if(!::SymbolInfoInteger(::SymbolName(i,true),SYMBOL_VISIBLE))
         continue;
      n++;
     }
   return n;
  }
//+------------------------------------------------------------------+


Die Methode, die den Symbolindex in der Liste der Marktübersicht zurückgibt:

//+------------------------------------------------------------------+
//| Return symbol index in the Market Watch window                   |
//+------------------------------------------------------------------+
int CSymbolsCollection::SymbolIndexInMW(const string name) const
  {
   int total=::SymbolsTotal(true);
   for(int i=0;i<total;i++)
     {
      if(!::SymbolInfoInteger(::SymbolName(i,true),SYMBOL_VISIBLE))
         continue;
      if(SymbolName(i,true)==name)
         return i;
     }
   return WRONG_VALUE;
  }
//+------------------------------------------------------------------+


Wenn Sie mit der Symbolliste aus dem Fenster der Marktübersicht arbeiten, müssen Sie den Index jedes einzelnen Symbols in der Fensterliste ermitteln, um die Position der Symbole in der Kollektionsliste mit der Position der Symbole im Fenster der Marktübersicht synchronisieren zu können. Dies kann beispielsweise nützlich sein, um ein benutzerdefiniertes Symbollistenfenster zu erstellen, das vollständig mit dem Terminalfenster synchronisiert ist. Der Index ist eine der Symboleigenschaften, die es uns ermöglichen, die Liste nach ihr zu sortieren. Der Index soll an den Konstruktor der abstrakten Symbolklasse übergeben werden.

Das Verfahren, das das Flag eines sichtbaren Symbolanwesens im Fenster der Marktübersicht zurückgibt:

//+------------------------------------------------------------------+
//| Return the visible symbol object presence flag                   |
//| by its name in the Market Watch window                           |
//+------------------------------------------------------------------+
bool CSymbolsCollection::IsPresentSymbolInMW(const string symbol_name)
  {
   int total=SymbolsTotal(true);
   for(int i=0;i<total;i++)
     {
      string name=::SymbolName(i,true);
      if(!::SymbolInfoInteger(name,SYMBOL_VISIBLE))
         continue;
      if(name==symbol_name)
         return true;
     }
   return false;
  }
//+------------------------------------------------------------------+


Das Verfahren erhält den Symbolnamen, dann in der Schleife durch die vollständige Liste der Symbole ausgewählt in der Marktübersicht, wir überspringen das unsichtbare Symbol, vergleichen den Namen des nächsten Symbols mit dem Namen, der an die Methode übergeben wurde. Liefert true, wenn die Namen übereinstimmen. Wenn das Symbol nicht in der Liste gefunden wird, wird false zurückgeben.

Das Verfahren, das das Flag eines Symbols zurückgibt, das in der Snapshot-Liste der Marktübersicht vorhanden ist:

//+------------------------------------------------------------------+
//| Return the flag of a symbol object presence in the control list  |
//+------------------------------------------------------------------+
bool CSymbolsCollection::IsPresentSymbolInControlList(const string symbol_name)
  {
   int total=this.m_list_names.Total();
   for(int i=0;i<total;i++)
     {
      string name=this.m_list_names.At(i);
      if(name==NULL)
         continue;
      if(name==symbol_name)
         return true;
     }
   return false;
  }
//+------------------------------------------------------------------+


Ein benötigter Symbolname wird an die Methode übergeben. Durch die Schleife über die Snapshotliste der Marktübersicht empfangen Sie das benötigte Symbol, und wenn sein Name mit dem an die Methode übergebenen übereinstimmt, geben Sie true, andernfallsfalse zurück.

Die Methode zum Erstellen der Liste beim Arbeiten mit dem Fenster der Marktübersicht oder der vollständigen Liste der Symbole auf dem Server:

//+------------------------------------------------------------------+
//| Creating the symbol list (Market Watch or the complete list)     |
//+------------------------------------------------------------------+
bool CSymbolsCollection::CreateSymbolsList(const bool flag)
  {
   bool res=true;
   int total=::SymbolsTotal(flag);
   for(int i=0;i<total && i<SYMBOLS_COMMON_TOTAL;i++)
     {
      string name=::SymbolName(i,flag);
      if(flag && !::SymbolInfoInteger(name,SYMBOL_VISIBLE))
         continue;
      ENUM_SYMBOL_STATUS status=this.SymbolStatus(name);
      bool add=this.CreateNewSymbol(status,name,i);
      res &=add;
      if(!add) 
         continue;
     }
   return res;
  }
//+------------------------------------------------------------------+


Die Methode erhält das Flag zum Setzen des Suchmodus: true — Arbeiten mit ausgewählten Symbolen in der Marktübersicht, false — Arbeiten mit der vollständigen Liste der auf dem Server vorhandenen Symbole. Liefert die Gesamtzahl der Symbole in Abhängigkeit von dem Flag — entweder in der Marktübersicht oder auf dem Server, und, in einer Schleife durch die Liste, aber nicht mehrals der Wert, der durch die SYMBOLS_COMMON_TOTAL Konstante der Datei Defines gesetzt wird.mqh (1000 Symbole), Gehen Sie den Namen des nächsten Symbols aus der Liste, Überprüfen Sie seine Sichtbarkeitseigenschaft, wenn Sie mit dem Marktbeobachtungsfenster arbeiten und überspringen Sie es, wenn es unsichtbar ist.
Dann erhalten Sie den Status des Symbolobjekts über seinen Namen und fügen Sie das Symbol mit der Methode CreateNewSymbol() in die Liste aller Kollektionssymbole ein, die im vorherigen Artikel berücksichtigt wurden. (Beachten Sie, dass die Methode durch das Hinzufügen der neuen Symboleigenschaft — seines Index in der Symbolleiste des Marktbeobachtungsfensters — leicht geändert wurde. Nun wird der Index auch an das Symbolobjekt übergeben).
Die Ergebnisse des Hinzufügens jedes Symbols zur Liste aller Kollektionssymbole werden der Variablen hinzugefügt, die das Ergebnis der Methode
zurückgibt, und der Gesamtwert dieser Variablen wird von der Methode nach Abschluss des gesamten Symbolbehandlungszyklus zurückgegeben.

Betrachten wir die verbesserte Methode zum Erstellen eines Symbolobjekts und dessen Platzierung in der Liste:

//+------------------------------------------------------------------+
//| Create a symbol object and place it to the list                  |
//+------------------------------------------------------------------+
bool CSymbolsCollection::CreateNewSymbol(const ENUM_SYMBOL_STATUS symbol_status,const string name,const int index)
  {
   if(this.IsPresentSymbolInList(name))
     {
      return true;
     }
   if(#ifdef __MQL5__ !::SymbolInfoInteger(name,SYMBOL_EXIST) #else !Exist(name) #endif )
     {
      string t1=TextByLanguage("Ошибка входных данных: нет символа ","Input error: no ");
      string t2=TextByLanguage(" на сервере"," symbol on the server");
      ::Print(DFUN,t1,name,t2);
      this.m_global_error=ERR_MARKET_UNKNOWN_SYMBOL;
      return false;
     }
   CSymbol *symbol=NULL;
   switch(symbol_status)
     {
      case SYMBOL_STATUS_FX         :  symbol=new CSymbolFX(name,index);         break;   // Forex symbol
      case SYMBOL_STATUS_FX_MAJOR   :  symbol=new CSymbolFXMajor(name,index);    break;   // Major Forex symbol
      case SYMBOL_STATUS_FX_MINOR   :  symbol=new CSymbolFXMinor(name,index);    break;   // Minor Forex symbol
      case SYMBOL_STATUS_FX_EXOTIC  :  symbol=new CSymbolFXExotic(name,index);   break;   // Exotic Forex symbol
      case SYMBOL_STATUS_FX_RUB     :  symbol=new CSymbolFXRub(name,index);      break;   // Forex symbol/RUR
      case SYMBOL_STATUS_METAL      :  symbol=new CSymbolMetall(name,index);     break;   // Metal
      case SYMBOL_STATUS_INDEX      :  symbol=new CSymbolIndex(name,index);      break;   // Index
      case SYMBOL_STATUS_INDICATIVE :  symbol=new CSymbolIndicative(name,index); break;   // Indicative
      case SYMBOL_STATUS_CRYPTO     :  symbol=new CSymbolCrypto(name,index);     break;   // Cryptocurrency symbol
      case SYMBOL_STATUS_COMMODITY  :  symbol=new CSymbolCommodity(name,index);  break;   // Commodity
      case SYMBOL_STATUS_EXCHANGE   :  symbol=new CSymbolExchange(name,index);   break;   // Exchange symbol
      case SYMBOL_STATUS_FUTURES    :  symbol=new CSymbolFutures(name,index);    break;   // Futures
      case SYMBOL_STATUS_CFD        :  symbol=new CSymbolCFD(name,index);        break;   // CFD
      case SYMBOL_STATUS_STOCKS     :  symbol=new CSymbolStocks(name,index);     break;   // Stock
      case SYMBOL_STATUS_BONDS      :  symbol=new CSymbolBonds(name,index);      break;   // Bond
      case SYMBOL_STATUS_OPTION     :  symbol=new CSymbolOption(name,index);     break;   // Option
      case SYMBOL_STATUS_COLLATERAL :  symbol=new CSymbolCollateral(name,index); break;   // Non-tradable asset
      case SYMBOL_STATUS_CUSTOM     :  symbol=new CSymbolCustom(name,index);     break;   // Custom symbol
      default                       :  symbol=new CSymbolCommon(name,index);     break;   // The rest
     }
   if(symbol==NULL)
     {
      ::Print(DFUN,TextByLanguage("Не удалось создать объект-символ ","Failed to create symbol object "),name);
      return false;
     }
   if(!this.m_list_all_symbols.Add(symbol))
     {
      string t1=TextByLanguage("Не удалось добавить символ ","Failed to add ");
      string t2=TextByLanguage(" в список"," symbol to the list");
      ::Print(DFUN,t1,name,t2);
      delete symbol;
      return false;
     }
   return true;
  }
//+------------------------------------------------------------------+


Wie aus der Auflistung ersichtlich, übergeben wir hier zusätzlich den Index, der ihn mit einem Symbolnamen sendet, an jeden der Konstruktoren der Symbolobjektklasse. Das bedeutet, dass wir jede der Klassen, die von der abstrakten Symbolklasse CSymbol abgeleitet sind, verfeinern müssen.
Betrachten wir diese Verfeinerung am Beispiel der Klasse CSymbolFX:.

//+------------------------------------------------------------------+
//|                                                     SymbolFX.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/de/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/de/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include-Dateien                                                  |
//+------------------------------------------------------------------+
#include "Symbol.mqh"
//+------------------------------------------------------------------+
//| Forex symbol                                                     |
//+------------------------------------------------------------------+
class CSymbolFX : public CSymbol
  {
public:
//--- Konstructor
                     CSymbolFX(const string name,const int index) : CSymbol(SYMBOL_STATUS_FX,name,index) {}
//--- Supported integer properties of a symbol
   virtual bool      SupportProperty(ENUM_SYMBOL_PROP_INTEGER property);
//--- Supported real properties of a symbol
   virtual bool      SupportProperty(ENUM_SYMBOL_PROP_DOUBLE property);
//--- Supported string properties of a symbol
   virtual bool      SupportProperty(ENUM_SYMBOL_PROP_STRING property);
//--- Display a short symbol description in the journal
   virtual void      PrintShort(void);
  };
//+------------------------------------------------------------------+


Hier erhält der Klassenkonstruktor auch seinen Index, und der Index wird an den Konstruktor der Elternklasse CSymbol in der Initialisierungsliste übergeben.
Das ist alles, was in allen vom abstrakten Symbol abgeleiteten Klassen geändert werden muss. Alle Änderungen an den Symbolobjektklassen wurden bereits in den unten angehängten Dateien vorgenommen.

Die verbesserte Methode zum Einstellen der Liste der verwendeten Symbole in der Kollektion:

//+------------------------------------------------------------------+
//| Set the list of used symbols                                     |
//+------------------------------------------------------------------+
bool CSymbolsCollection::SetUsedSymbols(const string &symbol_used_array[])
  {
   ::ArrayCopy(this.m_array_symbols,symbol_used_array);
   this.m_mode_list=this.TypeSymbolsList(this.m_array_symbols);
   this.m_list_all_symbols.Clear();
   this.m_list_all_symbols.Sort(SORT_BY_SYMBOL_INDEX_MW);
   //--- Use only the current symbol
   if(this.m_mode_list==SYMBOLS_MODE_CURRENT)
     {
      string name=::Symbol();
      ENUM_SYMBOL_STATUS status=this.SymbolStatus(name);
      return this.CreateNewSymbol(status,name,this.SymbolIndexInMW(name));
     }
   else
     {
      bool res=true;
      //--- Use the pre-defined symbol list
      if(this.m_mode_list==SYMBOLS_MODE_DEFINES)
        {
         int total=::ArraySize(this.m_array_symbols);
         for(int i=0;i<total;i++)
           {
            string name=this.m_array_symbols[i];
            ENUM_SYMBOL_STATUS status=this.SymbolStatus(name);
            bool add=this.CreateNewSymbol(status,name,this.SymbolIndexInMW(name));
            res &=add;
            if(!add) 
               continue;
           }
         return res;
        }
      //--- Use the full list of the server symbols
      else if(this.m_mode_list==SYMBOLS_MODE_ALL)
        {
         return this.CreateSymbolsList(false);
        }
      //--- Use the symbol list from the Market Watch window
      else if(this.m_mode_list==SYMBOLS_MODE_MARKET_WATCH)
        {
         this.MarketWatchEventsControl(false);
         return true;
        }
     }
   return false;
  }
//+------------------------------------------------------------------+


Hier kopieren Sie das Array der verwendeten Symbole, die vom Steuerungsprogramm an die benutzerdefinierte Anordnung übergeben wurden. Speichern Sie den Modus der Arbeit mit Symbolen und setzen Sie die Sortierung der Liste aller Symbole auf die Sortierung nach Index. Nun erhält die Methode zum Erstellen eines neuen Symbolobjekts seinen Index zusätzlich zum Symbolnamen.
Wenn Sie die vollständige Liste aller Symbole auf dem Server verwenden, rufen Sie die Methode zum Erstellen der Symbolkollektion mit dem Flag = false auf, das den Aufbau der vollständigen Liste der Symbole auf dem Server anzeigt.
Wenn Sie die Liste aus dem Fenster der Marktübersicht verwenden, rufen Sie die Methode der Arbeit mit der Marktübersicht mit dem Flag = false auf, die die Anforderung angibt, die Liste zu erstellen und ihre Daten einzugeben, und nicht das vollständige Verbot der Arbeit mit Ereignissen.

Die Methode zum Arbeiten mit Ereignissen aller Kollektionssymbole:

//+------------------------------------------------------------------+
//| Working with the events of the collection symbol list            |
//+------------------------------------------------------------------+
void CSymbolsCollection::SymbolsEventsControl(void)
  {
   this.m_is_event=false;     
   this.m_list_events.Clear();
   this.m_list_events.Sort(); 
   //--- The full update of all collection symbols
   int total=this.m_list_all_symbols.Total();
   for(int i=0;i<total;i++)
     {
      CSymbol *symbol=this.m_list_all_symbols.At(i);
      if(symbol==NULL)
         continue;
      symbol.Refresh();
      if(!symbol.IsEvent())
         continue;
      this.m_is_event=true;
      CArrayObj *list=symbol.GetListEvents();
      if(list==NULL)
         continue;
      this.m_event_code=symbol.GetEventCode();
      int n=list.Total();
      for(int j=0; j<n; j++)
        {
         CEventBaseObj *event=list.At(j);
         if(event==NULL)
            continue;
         ENUM_SYMBOL_EVENT event_id=(ENUM_SYMBOL_EVENT)event.ID();
         if(event_id==SYMBOL_EVENT_NO_EVENT)
            continue;
         this.m_last_event=event_id;
         if(this.EventAdd((ushort)event.ID(),event.LParam(),event.DParam(),event.SParam()))
           {
            ::EventChartCustom(this.m_chart_id,(ushort)event_id,event.LParam(),event.DParam(),event.SParam());
           }
        }
     }
  }
//+------------------------------------------------------------------+


Das Verfahren funktioniert im Timer. Die Daten werden zuerst initialisiert:
das Flag des Kollektionssymbols wird zurückgesetzt,
die Liste der Ereignisse in der Symbolkollektion wird gelöscht und
das Flag der sortierten Liste wird für die Liste gesetzt.
Weiter, in der Schleife durch alle Symbole in der Symbolkollektion, wird das nächste Symbol übernommen, alle seine Daten aktualisiert und das Vorhandensein des für das Symbol gesetzten Ereignisflags überprüft. Wenn kein Ereignis vorliegt, überprüfen Sie das nächste Symbol in der Kollektion.
Wenn das Symbol das Ereignisflag enthält, setzen Sie das Ereignisflag für die gesamte Kollektion (das Vorhandensein eines Ereignisses, mindestens eines der Symbole bedeutet, dass das Ereignis für die gesamte Kollektion vorhanden ist). Liefert die Liste aller aktuellen Symbolereignisse, setzt den Code des letzten Kollektionsereignisses gleich dem Ereigniscode des aktuellen Symbols aus der Liste. Wenn das Ereignis vorhanden ist, wird der in der Variable zum Speichern des Codes des letzten Kollektionsereignisses eingestellte Wert für das nächste Symbol aktualisiert, während in einer Schleife durch die Liste aller aktuellen Symbolereignisse, wir ein neues Ereignis erhalten und die Ereignis-ID als das letzte Kollektionsereignis speichern. Auf die gleiche Weise aktualisiert das Ereignis des nächsten Symbols das letzte Ereignis der Symbolkollektion.
Als Nächstes erstellen Sie das Kollektionsereignis mit den dafür eingestellten Symbolereignisparametern ( Ereignis-ID, long, double und string) und speichern das Symbolereignis in der Liste der Ereigniskollektion der Symbole.
Wird ein Symbolereignis erfolgreich in der Liste der Ereigniskollektion gespeichert, wird das Ereignis über die Funktion EventChartCustom() mit den gleichen Ereignisparametern zur weiteren Behandlung des Ereignisses im aufrufenden Programm an den Programmplan gesendet.

Wenn wir also die Ereignisliste von jedem der Symbole in der Kollektion erhalten, gehen wir durch die Liste der Ereignisse jedes Symbols, das alle seine Ereignisse an die Liste der Kollektionsereignisse sendet. Nach Abschluss des Zyklus enthält die Liste der Sammelereignisse alle Ereignisse aller Sammelzeichen. Für jedes der Ereignisse wird ein eigenes Ereignis erstellt und an das Programm auf dem Chart gesendet.

Um Ereignisse im Fenster der Marktübersicht zu unterscheiden, müssen wir die Hash-Summe aller Symbole der Marktübersicht berechnen. Seine Änderung zeigt an, dass ein Ereignis eingetreten ist. Das erste, was mir in den Sinn kommt, ist eine einfache Zählung der Anzahl der Symbole im Fenster. Das Hinzufügen oder Entfernen eines Symbols erhöht oder verringert jedoch die Größe der Liste, während das Sortieren von Symbolen mit der Maus die Anzahl der Symbole nicht verändert. Das bedeutet, dass die Anzahl der Symbole im Fenster der Marktübersicht nicht für die Berechnung der Hash-Summe geeignet ist.
Gehen wir wie folgt vor: Ein Name jedes in der Liste gespeicherten Symbols kann als Zahl (Symbolcode) dargestellt werden, die aus einer Summe von uchar-Werten von Symbol-(Zeichen-)Codes besteht, aus denen der Symbolname besteht, wobei ein Index eines Symbols im Fenster der Marktübersicht hinzugefügt wird. Die Summe aller dieser Symbolcodes bildet die Hash-Summe.

  • Das Hinzufügen eines Symbols zur Liste ändert die Hash-Summe (der neue Code des hinzugefügten Symbols wird hinzugefügt).
  • Auch das Entfernen eines Symbols aus der Liste ändert die Hash-Summe (der Code des entfernten Symbols wird von der Hash-Summe abgezogen).
  • Das Sortieren der Symbolliste ändert die Hash-Summe (Codes sortierter Symbole werden geändert, da ihre Indizes geändert werden).

Implementierung der Methode der Arbeit mit den Ereignissen des Fensters der Marktübersicht:

//+------------------------------------------------------------------+
//| Working with market watch window events                          |
//+------------------------------------------------------------------+
void CSymbolsCollection::MarketWatchEventsControl(const bool send_events=true)
  {
   ::ResetLastError();
//--- If no current prices are received, exit
   if(!::SymbolInfoTick(::Symbol(),this.m_tick))
     {
      this.m_global_error=::GetLastError();
      return;
     }
   uchar array[];
   int sum=0;
   this.m_hash_sum=0;
//--- Calculate the hash sum of all visible symbols in the Market Watch window
   this.m_total_symbols=this.SymbolsTotalVisible();
   //--- In the loop by all Market Watch window symbols
   int total_symbols=::SymbolsTotal(true);
   for(int i=0;i<total_symbols;i++)
     {
      //--- get a symbol name by index
      string name=::SymbolName(i,true);
      //--- skip if invisible
      if(!::SymbolInfoInteger(name,SYMBOL_VISIBLE))
         continue;
      //--- write symbol name (characters) codes to the uchar array
      ::StringToCharArray(name,array);
      //--- in a loop by the resulting array, sum up the values of all array cells creating the symbol code
      for(int j=::ArraySize(array)-1;j>WRONG_VALUE;j--)
         sum+=array[j];
      //--- add the symbol code and the loop index specifying the symbol index in the market watch list to the hash sum
      m_hash_sum+=i+sum;
     }
//--- If sending events is disabled, create the collection list and exit saving the current hash some as the previous one
   if(!send_events)
     {
      //--- Clear the list
      this.m_list_all_symbols.Clear();
      //--- Clear the collection list
      this.CreateSymbolsList(true);
      //--- Clear the market watch window snapshot
      this.CopySymbolsNames();
      //--- save the current hash some as the previous one
      this.m_hash_sum_prev=this.m_hash_sum;
      //--- save the current number of visible symbols as the previous one
      this.m_total_symbol_prev=this.m_total_symbols;
      return;
     }
   
//--- If the hash sum of symbols in the Market Watch window has changed
   if(this.m_hash_sum!=this.m_hash_sum_prev)
     {
      //--- Define the Market Watch window event
      this.m_delta_symbol=this.m_total_symbols-this.m_total_symbol_prev;
      ENUM_SYMBOL_EVENT event_id=
        (
         this.m_total_symbols>this.m_total_symbol_prev ? SYMBOL_EVENT_MW_ADD :
         this.m_total_symbols<this.m_total_symbol_prev ? SYMBOL_EVENT_MW_DEL :
         SYMBOL_EVENT_MW_SORT
        );
      //--- Adding a symbol to the Market Watch window
      if(event_id==SYMBOL_EVENT_MW_ADD)
        {
         string name="";
         //--- In the loop by all Market Watch window symbols
         int total=::SymbolsTotal(true), index=WRONG_VALUE;
         for(int i=0;i<total;i++)
           {
            //--- get the symbol name and check its "visibility". Skip it if invisible
            name=::SymbolName(i,true);
            if(!::SymbolInfoInteger(name,SYMBOL_VISIBLE))
               continue;
            //--- If there is no symbol in the collection symbol list yet
            if(!this.IsPresentSymbolInList(name))
              {
               //--- clear the collection list
               this.m_list_all_symbols.Clear();
               //--- recreate the collection list
               this.CreateSymbolsList(true);
               //--- create the symbol collection snapshot
               this.CopySymbolsNames();
               //--- get a new symbol index in the Market Watch window
               index=this.GetSymbolIndexByName(name);
               //--- If the "Adding a new symbol" event is successfully added to the event list 
               if(this.EventAdd(event_id,this.TickTime(),index,name))
                 {
                  //--- send the event to the chart:
                  //--- long value = event time in milliseconds, double value = symbol index, string value = added symbol name
                  ::EventChartCustom(this.m_chart_id,(ushort)event_id,this.TickTime(),index,name);
                 }
              }
           }
         //--- Save the new number of visible symbols in the market watch window
         this.m_total_symbols=this.SymbolsTotalVisible();
        }
      //--- Remove a symbol from the Market Watch window
      else if(event_id==SYMBOL_EVENT_MW_DEL)
        {
         //--- clear the collection list 
         this.m_list_all_symbols.Clear();
         //--- recreate the collection list
         this.CreateSymbolsList(true);
         //--- In a loop by the market watch window snapshot
         int total=this.m_list_names.Total();
         for(int i=0; i<total;i++)
           {
            //--- get a symbol name 
            string name=this.m_list_names.At(i);
            if(name==NULL)
               continue;
            //--- if no symbol with such a name exists in the collection symbol list
            if(!this.IsPresentSymbolInList(name))
              {
               //--- If the "Removing a symbol" event is successfully added to the event list
               if(this.EventAdd(event_id,this.TickTime(),WRONG_VALUE,name))
                 {
                  //--- send the event to the chart:
                  //--- long value = event tine in milliseconds, double value = -1 for an absent symbol, string value = a removed symbol name
                  ::EventChartCustom(this.m_chart_id,(ushort)event_id,this.TickTime(),WRONG_VALUE,name);
                 }
              }
           }
         //--- Recreate the market watch snapshot
         this.CopySymbolsNames();
         //--- Save the new number of visible symbols in the market watch window
         this.m_total_symbols=this.SymbolsTotalVisible();
        }
      //--- Sorting symbols in the Market Watch window
      else if(event_id==SYMBOL_EVENT_MW_SORT)
        {
         //--- clear the collection list 
         this.m_list_all_symbols.Clear();
         //--- set sorting of the collection list as sorting by index
         this.m_list_all_symbols.Sort(SORT_BY_SYMBOL_INDEX_MW);
         //--- recreate the collection list
         this.CreateSymbolsList(true);
         //--- get the current symbol index in the Market Watch window
         int index=this.GetSymbolIndexByName(Symbol());
         //--- send the event to the chart:
         //--- long value = event time in milliseconds, double value = current symbol index, string value = current symbol name
         ::EventChartCustom(this.m_chart_id,(ushort)event_id,this.TickTime(),index,::Symbol());
        }
      //--- save the current number of visible symbols as the previous one
      this.m_total_symbol_prev=this.m_total_symbols;
      //--- save the current hash some as the previous one
      this.m_hash_sum_prev=this.m_hash_sum;
     }
  }
//+------------------------------------------------------------------+


Um nicht alle Zweige im Methodencode zu beschreiben, habe ich den Code blockweise in die Auflistung eingefügt. Jeder der Blöcke wird von detaillierten Kommentaren begleitet. Ich hoffe, dort ist alles klar. Wenn du irgendwelche Fragen hast, stelle sie in den Kommentaren zum Artikel.

Wenn Sie mit der Marktübersicht arbeiten, um die darin auftretenden Ereignisse zu verfolgen, ist die Arbeit mit der reinen Hash-Summe unzureichend. Wenn wir wissen wollen, was vor einem Event passiert ist, benötigen wir eine Kopie der Market Watch Symbolliste (Market Watch Snapshot). Mit dieser Kopie können wir zum Beispiel herausfinden, welches Symbol entfernt wurde. Ohne die Momentaufnahme der Marktbeobachtung können wir den Namen des entfernten Symbols nicht kennen.

Die Methode zum Erstellen des Snapshot der Marktübersicht:

//+------------------------------------------------------------------+
//| Save names of used Market Watch symbols                          |
//+------------------------------------------------------------------+
void CSymbolsCollection::CopySymbolsNames(void)
  {
   this.m_list_names.Clear();
   int total=this.m_list_all_symbols.Total();
   for(int i=0;i<total;i++)
     {
      CSymbol *symbol=this.m_list_all_symbols.At(i);
      if(symbol==NULL)
         continue;
      this.m_list_names.Add(symbol.Name());
     }
  }
//+------------------------------------------------------------------+


Hier löschen wir die Liste der Symbolnamen. In einer Schleife durch die Liste der Symbolkollektion, erhalten Sie ein neues Symbol und fügen Sie es der Liste der Symbolnamen hinzu.
Nach Abschluss der Schleife haben wir die Namensliste aller Symbole der Symbolkollektion.

Die Methode gibt ein Symbolobjekt mit dem Namen zurück:

//+------------------------------------------------------------------+
//| Return an object symbol from the list by a name                  |
//+------------------------------------------------------------------+
CSymbol *CSymbolsCollection::GetSymbolByName(const string name)
  {
   CArrayObj *list=this.GetList(SYMBOL_PROP_NAME,name,EQUAL);
   if(list==NULL || list.Total()==0)
      return NULL;
   CSymbol *symbol=list.At(0);
   return(symbol!=NULL ? symbol : NULL);
  }
//+------------------------------------------------------------------+


Ein Symbolname wird an die Methode übergeben. Als Nächstes erstellen Sie mit der Methode zum Empfangen der Liste der Objekte GetList() über die Eigenschaft "Symbolname" eine neue Liste mit dem einzigen Objektsymbol dessen Name gleich dem, das der Methode übergebenen wurde.
Liefert das Symbolobjekt aus der Liste und gibt es zurück, wenn die Suche erfolgreich war oder NULL, wenn es kein Symbol mit einem solchen Namen in der Symbolkollektion gibt.

Die Methode, die einen Symbolindex in der Symbolkollektion zurückgibt:

//+------------------------------------------------------------------+
//| Return the symbol object index from the list by a name           |
//+------------------------------------------------------------------+
int CSymbolsCollection::GetSymbolIndexByName(const string name)
  {
   int total=this.m_list_all_symbols.Total();
   for(int i=0;i<total;i++)
     {
      CSymbol *symbol=this.m_list_all_symbols.At(i);
      if(symbol==NULL)
         continue;
      if(symbol.Name()==name)
         return i;
     }
   return WRONG_VALUE;
  }
//+------------------------------------------------------------------+


Hier wird der notwendige Symbolname an die Methode übergeben. Dann, in einer Schleife durch alle Symbole in der Kollektion Symbolliste, erhalten wir ein weiteres Symbolobjekt aus der Liste. Wenn sein Name mit dem benötigten übereinstimmt, geben Sie den Schleifenindex zurück, andernfalls, -1. Die Methode, die eine Beschreibung eines Ereignisses aus dem Fenster der Marktübersicht zurückgibt:

Die Methode, die eine Beschreibung eines Ereignisses aus dem Fenster der Marktübersicht zurückgibt:

//+------------------------------------------------------------------+
//| Return the Market Watch window event description                 |
//+------------------------------------------------------------------+
string CSymbolsCollection::EventDescription(const ENUM_SYMBOL_EVENT event)
  {
   return
     (
      event==SYMBOL_EVENT_MW_ADD    ?  TextByLanguage("В окно \"Обзор рынка\" добавлен символ","Added symbol to \"Market Watch\" window")                                     :
      event==SYMBOL_EVENT_MW_DEL    ?  TextByLanguage("Из окна \"Обзор рынка\" удалён символ","Removed from \"Market Watch\" window")                                       :
      event==SYMBOL_EVENT_MW_SORT   ?  TextByLanguage("Изменено расположение символов в окне \"Обзор рынка\"","Changed arrangement of symbols in \"Market Watch\" window")  :
      EnumToString(event)
     );
  }
//+------------------------------------------------------------------+


Die Methode erhält ein Ereignis und gibt seine Textbeschreibung zurück, je nachdem, welches Ereignis übergeben wurde.

Die Methode gibt den Modus des Arbeitens mit Symbolen zurück:

//+------------------------------------------------------------------+
//| Return a description of the mode of working with symbols         |
//+------------------------------------------------------------------+
string CSymbolsCollection::ModeSymbolsListDescription(void)
  {
   return
     (
      this.m_mode_list==SYMBOLS_MODE_CURRENT       ? TextByLanguage("Работа только с текущим символом","Work only with current symbol")                                : 
      this.m_mode_list==SYMBOLS_MODE_DEFINES       ? TextByLanguage("Работа с предопределённым списком символов","Work with predefined list of symbols")                 :
      this.m_mode_list==SYMBOLS_MODE_MARKET_WATCH  ? TextByLanguage("Работа с символами из окна \"Обзор рынка\"","Working with symbols from \"Market Watch\" window")  :
      TextByLanguage("Работа с полным списком всех доступных символов","Work with full list of all available symbols")
     );
  }
//+------------------------------------------------------------------+


Hier wird das Vorhandensein der Variablen m_m_mode_list überprüft und die Textbeschreibung der Betriebsart entsprechend dem Variablenwert zurückgegeben.

Damit ist die Erstellung der Symbol-Ereignisklasse abgeschlossen.

Bevor wir die Symbol-Ereignisklasse in Betrieb nehmen, sollten wir bedenken, dass wir auch eine Ereignisverfolgung organisieren können. Die Klasse verfügt nun über das Basisobjekt CBaseObj und die Kontenklasse basiert nun auf CBaseObj, so dass beide Klassen die bereits vorbereitete Ereignissuchfunktionalität nutzen können. Alle nachfolgenden Objekte, die aus CBaseObj abgeleitet werden sollen, werden ebenfalls mit den Eigenschaften ausgestattet, mit denen Sie die Objektereignisse verfolgen können.

Verbesserung der Klasse der Kontoereignisse

Öffnen Sie die Kontoklassen-Datei Account.mqh und nehmen Sie die notwendigen Änderungen vor.
Ersetzen Sie das Einbinden von Object.mqh durch including BaseObj.mqh:

//+------------------------------------------------------------------+
//|                                                      Account.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/de/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/de/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include-Dateien                                                  |
//+------------------------------------------------------------------+
#include "..\BaseObj.mqh"
#include "..\..\Services\DELib.mqh"
//+------------------------------------------------------------------+
//| Account class                                                    |
//+------------------------------------------------------------------+
class CAccount : public CBaseObj
  {
private:


Setzen wir CBaseObj als Basisklasse anstelle von CObject.

Da wir nun in der Lage sind, einem von CBaseObj geerbten Objekt einen Namen zuzuweisen, verwenden Sie diese Funktion und setzen Sie den Namen für das Kontoobjekt.
Am Ende des Konstruktors der Klasse CAccount fügen Sie die Zeile hinzu, die den Namen des Kontoobjekts setzt:

//+------------------------------------------------------------------+
//| Konstruktor                                                      |
//+------------------------------------------------------------------+
CAccount::CAccount(void)
  {
//--- Sichern der ganzzahligen Eigenschaften
   this.m_long_prop[ACCOUNT_PROP_LOGIN]                              = ::AccountInfoInteger(ACCOUNT_LOGIN);
   this.m_long_prop[ACCOUNT_PROP_TRADE_MODE]                         = ::AccountInfoInteger(ACCOUNT_TRADE_MODE);
   this.m_long_prop[ACCOUNT_PROP_LEVERAGE]                           = ::AccountInfoInteger(ACCOUNT_LEVERAGE);
   this.m_long_prop[ACCOUNT_PROP_LIMIT_ORDERS]                       = ::AccountInfoInteger(ACCOUNT_LIMIT_ORDERS);
   this.m_long_prop[ACCOUNT_PROP_MARGIN_SO_MODE]                     = ::AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE);
   this.m_long_prop[ACCOUNT_PROP_TRADE_ALLOWED]                      = ::AccountInfoInteger(ACCOUNT_TRADE_ALLOWED);
   this.m_long_prop[ACCOUNT_PROP_TRADE_EXPERT]                       = ::AccountInfoInteger(ACCOUNT_TRADE_EXPERT);
   this.m_long_prop[ACCOUNT_PROP_MARGIN_MODE]                        = #ifdef __MQL5__::AccountInfoInteger(ACCOUNT_MARGIN_MODE) #else ACCOUNT_MARGIN_MODE_RETAIL_HEDGING #endif ;
   this.m_long_prop[ACCOUNT_PROP_CURRENCY_DIGITS]                    = #ifdef __MQL5__::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #else 2 #endif ;
   this.m_long_prop[ACCOUNT_PROP_SERVER_TYPE]                        = (::TerminalInfoString(TERMINAL_NAME)=="MetaTrader 5" ? 5 : 4);
   
//--- Sichern der Double-Eigenschaften
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_BALANCE)]          = ::AccountInfoDouble(ACCOUNT_BALANCE);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_CREDIT)]           = ::AccountInfoDouble(ACCOUNT_CREDIT);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_PROFIT)]           = ::AccountInfoDouble(ACCOUNT_PROFIT);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_EQUITY)]           = ::AccountInfoDouble(ACCOUNT_EQUITY);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN)]           = ::AccountInfoDouble(ACCOUNT_MARGIN);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_FREE)]      = ::AccountInfoDouble(ACCOUNT_MARGIN_FREE);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_LEVEL)]     = ::AccountInfoDouble(ACCOUNT_MARGIN_LEVEL);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_CALL)]   = ::AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_SO)]     = ::AccountInfoDouble(ACCOUNT_MARGIN_SO_SO);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_INITIAL)]   = ::AccountInfoDouble(ACCOUNT_MARGIN_INITIAL);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_MAINTENANCE)]=::AccountInfoDouble(ACCOUNT_MARGIN_MAINTENANCE);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_ASSETS)]           = ::AccountInfoDouble(ACCOUNT_ASSETS);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_LIABILITIES)]      = ::AccountInfoDouble(ACCOUNT_LIABILITIES);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_COMMISSION_BLOCKED)]=::AccountInfoDouble(ACCOUNT_COMMISSION_BLOCKED);
   
//--- Sichern der String-Eigenschaften
   this.m_string_prop[this.IndexProp(ACCOUNT_PROP_NAME)]             = ::AccountInfoString(ACCOUNT_NAME);
   this.m_string_prop[this.IndexProp(ACCOUNT_PROP_SERVER)]           = ::AccountInfoString(ACCOUNT_SERVER);
   this.m_string_prop[this.IndexProp(ACCOUNT_PROP_CURRENCY)]         = ::AccountInfoString(ACCOUNT_CURRENCY);
   this.m_string_prop[this.IndexProp(ACCOUNT_PROP_COMPANY)]          = ::AccountInfoString(ACCOUNT_COMPANY);

//--- Account object name
   this.m_name=TextByLanguage("Счёт ","Account ")+(string)this.Login()+": "+this.Name()+" ("+this.Company()+")";
  }
//+-------------------------------------------------------------------+


Wie wir sehen können, besteht der Objektname aus dem Account als Text, der Kontonummer, dem Kundennamen und dem Namen der Firma, bei der das Konto geführt wird.
Wenn Sie sich beispielsweise mit einem der Konten auf MetaQuotes-Demo unter meinem Namen verbinden, sieht der Objektname des Kontos wie folgt aus: "Account 8550475: Artyom Trishkin (MetaQuotes Software Corp.)"

Geben Sie den Variablenwert der Variable 'names' in die Methode zur Anzeige eines kurzen Kontonamens ein (vorher wurde die Variable auf die gleiche Weise gesetzt wie wir gerade das Objekt Konto gesetzt haben):

//+------------------------------------------------------------------+
//| Display a short account description in the journal               |
//+------------------------------------------------------------------+
void CAccount::PrintShort(void)
  {
   string mode=(this.MarginMode()==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING ? ", Hedge" : this.MarginMode()==ACCOUNT_MARGIN_MODE_EXCHANGE ? ", Exhange" : "");
   string names=this.m_name+" ";
   string values=::DoubleToString(this.Balance(),(int)this.CurrencyDigits())+" "+this.Currency()+", 1:"+(string)+this.Leverage()+mode+", "+this.TradeModeDescription()+" "+this.ServerTypeDescription();
   ::Print(names,values);
  }
//+------------------------------------------------------------------+


Damit ist die Verbesserung der Klasse CAccount abgeschlossen.

Lassen Sie uns nun die Klasse der Kollektion der Konten verbessern. Öffnen Sie die Datei AccountsCollection.mqh und fügen Sie die notwendigen Änderungen hinzu.
Weisen wir die Rolle der Klasse der Kontenkollektion Basisobjekt jetzt der Klasse CBaseObj zu:.

//+------------------------------------------------------------------+
//| Account collection                                               |
//+------------------------------------------------------------------+
class CAccountsCollection : public CBaseObj
  {
private:


Da die Klasse vom Basisobjekt mit der Funktionsweise zur Verfolgung von Objektereignissen vererbt wird, entfernen Sie die doppelten Variablen und Methoden aus der Klasse der Kollektion der Konten.
In der Struktur der Kontodaten Entfernen Sie das Hash-Summenfeld:

   struct MqlDataAccount
     {
      double         hash_sum;               // Account data hash sum
      //--- Account integer properties
      long           login;                  // ACCOUNT_LOGIN (Account number)
      long           leverage;               // ACCOUNT_LEVERAGE (Leverage)
      int            limit_orders;           // ACCOUNT_LIMIT_ORDERS (Maximum allowed number of active pending orders)
      bool           trade_allowed;          // ACCOUNT_TRADE_ALLOWED (Permission to trade for the current account from the server side)
      bool           trade_expert;           // ACCOUNT_TRADE_EXPERT (Permission to trade for an EA from the server side)
      //--- Account real properties
      double         balance;                // ACCOUNT_BALANCE (Account balance in a deposit currency)
      double         credit;                 // ACCOUNT_CREDIT (Credit in a deposit currency)
      double         profit;                 // ACCOUNT_PROFIT (Current profit on an account in the account currency)
      double         equity;                 // ACCOUNT_EQUITY (Equity on an account in the deposit currency)
      double         margin;                 // ACCOUNT_MARGIN (Reserved margin on an account in a deposit currency)
      double         margin_free;            // ACCOUNT_MARGIN_FREE (Free funds available for opening a position in a deposit currency)
      double         margin_level;           // ACCOUNT_MARGIN_LEVEL (Margin level on an account in %)
      double         margin_so_call;         // ACCOUNT_MARGIN_SO_CALL (MarginCall)
      double         margin_so_so;           // ACCOUNT_MARGIN_SO_SO (StopOut)
      double         margin_initial;         // ACCOUNT_MARGIN_INITIAL (Funds reserved on an account to ensure a guarantee amount for all pending orders)
      double         margin_maintenance;     // ACCOUNT_MARGIN_MAINTENANCE (Funds reserved on an account to ensure a minimum amount for all open positions)
      double         assets;                 // ACCOUNT_ASSETS (Current assets on an account)
      double         liabilities;            // ACCOUNT_LIABILITIES (Current liabilities on an account)
      double         comission_blocked;      // ACCOUNT_COMMISSION_BLOCKED (Current sum of blocked commissions on an account)
     };


Entfernen Sie die 'private' Variablen aus der Klasse:

   MqlTick           m_tick;                             // Tick structure
   string            m_symbol;                           // Current symbol
   long              m_chart_id;                         // Control program chart ID
   CListObj          m_list_accounts;                    // Account object list
   CArrayInt         m_list_changes;                     // Account change list
   string            m_folder_name;                      // Name of a folder account objects are stored
   int               m_index_current;                    // Index of an account object featuring the current account data
//--- Tracking account changes
   bool              m_is_account_event;                 // Account data event flag
   int               m_change_code;                      // Account change code


Benennen Sie die Methode SetChangeCode() in SetEventCode() um, so dass die Namen von Methoden gleichen Typs in verschiedenen Klassen gleich bleiben.
Die Methode SetTypeEvent() sollte virtuell gemacht werden, da sie bereits in der Klasse CBaseObj deklariert wurde und in den Nachkommen implementiert werden sollte.
Entfernen Sie die Methode IsPresentEventFlag() aus der Klasse, da sie bereits in CBaseObj implementiert wurde.

Entfernen Sie die doppelten Methoden in der Klasse aus den 'public' Abschnitt.
Entfernen Sie die Methoden GetEventCode(), GetListChanges() und SetChartID(), während die Methode ENUM_ACCOUNT_EVENT GetEvent(const int shift=WRONG_VALUE) wie folgt aussehen sollte:

ENUM_ACCOUNT_EVENT GetEventID(const int shift=WRONG_VALUE,const bool check_out=true);

Wenden wir uns gleich der Implementierung außerhalb des Klassenkörpers zu:

//+------------------------------------------------------------------+
//| Return the account event by its number in the list               |
//+------------------------------------------------------------------+
ENUM_ACCOUNT_EVENT CAccountsCollection::GetEventID(const int shift=WRONG_VALUE,const bool check_out=true)
  {
   CEventBaseObj *event=this.GetEvent(shift,check_out);
   if(event==NULL)
      return ACCOUNT_EVENT_NO_EVENT;
   return (ENUM_ACCOUNT_EVENT)event.ID();
  }
//+------------------------------------------------------------------+


Das Verfahren erhält den notwendigen Ereignisindex (-1 für das letzte) und das Flag zum Erfassen des Index, das über die Grenzen der Ereignisliste hinausgeht.
Gehen Sie das Ereignisobjekt mit der Methode des Basisobjekts CBaseObj GetEvent(), die wir am Anfang des Artikels besprochen haben. Wenn es kein Ereignis gibt, geben Sie "No event", andernfalls die Ereignis-ID zurück.

Entfernen Sie in der Initialisierungsliste des Klassenkonstruktors die Initialisierung aller Parameter mit Ausnahme der Symboleinstellung und setzen Sie den Namen des Unterordners zum Speichern der Kontoobjektdateien:

//+------------------------------------------------------------------+
//| Konstruktor                                                      |
//+------------------------------------------------------------------+
CAccountsCollection::CAccountsCollection(void) : m_symbol(::Symbol())
  {
   this.m_list_accounts.Clear();
   this.m_list_accounts.Sort(SORT_BY_ACCOUNT_LOGIN);
   this.m_list_accounts.Type(COLLECTION_ACCOUNT_ID);
   ::ZeroMemory(this.m_struct_prev_account);
   ::ZeroMemory(this.m_tick);
   this.InitChangesParams();
   this.InitControlsParams();
//--- Create the folder for storing account files
   this.SetSubFolderName("Accounts");
   ::ResetLastError();
   if(!::FolderCreate(this.m_folder_name,FILE_COMMON))
      ::Print(DFUN,TextByLanguage("Не удалось создать папку хранения файлов. Ошибка ","Could not create file storage folder. Error "),::GetLastError());
//--- Create the current account object and add it to the list
   CAccount* account=new CAccount();
   if(account!=NULL)
     {
      if(!this.AddToList(account))
        {
         ::Print(DFUN_ERR_LINE,TextByLanguage("Ошибка. Не удалось добавить текущий объект-аккаунт в список-коллекцию.","Error. Failed to add current account object to collection list."));
         delete account;
        }
      else
         account.PrintShort();
     }
   else
      ::Print(DFUN,TextByLanguage("Ошибка. Не удалось создать объект-аккаунт с данными текущего счёта.","Error. Failed to create an account object with current account data."));

//--- Download account objects from the files to the collection
   this.LoadObjects();
//--- Save the current account index
   this.m_index_current=this.Index();
  }
//+------------------------------------------------------------------+


Die Methode Refresh() zur Aktualisierung der Kontodaten sollte virtuell gemacht werden, da sie in der Klasse CBaseObj deklariert und in ihren Nachkommen implementiert ist.

Einige Änderungen wurden in der Methodenimplementierung vorgenommen:

//+------------------------------------------------------------------+
//| Update the current account data                                  |
//+------------------------------------------------------------------+
void CAccountsCollection::Refresh(void)
  {
   ::ResetLastError();
   if(!::SymbolInfoTick(::Symbol(),this.m_tick))
     {
      this.m_global_error=::GetLastError();
      return;
     }
   if(this.m_index_current==WRONG_VALUE)
      return;
   CAccount* account=this.m_list_accounts.At(this.m_index_current);
   if(account==NULL)
      return;
//--- Prepare event data
   this.m_is_event=false;
   ::ZeroMemory(this.m_struct_curr_account);
   this.m_hash_sum=0;
   this.SetAccountsParams(account);

//--- Erster Start
   if(!this.m_struct_prev_account.login)
     {
      this.m_struct_prev_account=this.m_struct_curr_account;
      this.m_hash_sum_prev=this.m_hash_sum;
      return;
     }
//--- If the account hash sum changed
   if(this.m_hash_sum!=this.m_hash_sum_prev)
     {
      this.m_list_events.Clear();
      this.m_event_code=this.SetEventCode();
      this.SetTypeEvent();
      int total=this.m_list_events.Total();
      if(total>0)
        {
         this.m_is_event=true;
         for(int i=0;i<total;i++)
           {
            CEventBaseObj *event=this.GetEvent(i,false);
            if(event==NULL)
               continue;
            ENUM_ACCOUNT_EVENT event_id=(ENUM_ACCOUNT_EVENT)event.ID();
            if(event_id==ACCOUNT_EVENT_NO_EVENT)
               continue;
            long lparam=event.LParam();
            double dparam=event.DParam();
            string sparam=event.SParam();
            ::EventChartCustom(this.m_chart_id,(ushort)event_id,lparam,dparam,sparam);
           }
        }
      this.m_hash_sum_prev=this.m_hash_sum;
     }
  }
//+------------------------------------------------------------------+


Lassen Sie uns die Änderungen berücksichtigen, die wir vorgenommen haben.
Erstens, Empfang der Kursdaten nach Symbolen (um eine Millisekundenzeit zu definieren). Wenn der Empfang fehlgeschlagen ist, beenden Sie die Methode.

Setzen Sie das Flag für das Kontoereignis und die aktuellen Hash-Summe zurück. Beim ersten Start speichern Sie die aktuelle Hash-Summe als die vorherige.

Wenn Sie die Hash-Summe ändern, löschen Sie die Liste der Kontoereignisse und führen Sie die Aktionen zum Empfangen von Ereignissen aus der Liste der Kontoereignisse ähnlich denen aus, die beim Empfangen der Liste der Symbolereignisse (siehe oben) ausgeführt wurden.

Nun, für alle Objekte, die von CBaseObj geerbt werden, sind die Aktionen, die ausgeführt werden, um ihre Ereignisse zu empfangen, ähnlich. Daher ist es besser, sich noch einmal mit dem Erhalt vertraut zu machen, damit in den folgenden Artikeln alles klar bleibt und man nicht zur Beschreibung der Aktionen zurückkehren muss, die zum Erhalten der Objekt-Ereignisliste durchgeführt wurden.

Ersetzen Sie bei der Methode zum Speichern von Kontoeigenschaften im Kontoobjekt und in der Kontodatenstruktur den Zugriff auf das Struktur-Feld der Hash-Summe durch die Variable der Hash-Summe der Klasse CBaseObj und speichern Sie den Objektnamen:

//+------------------------------------------------------------------+
//| Write the current account data to the account object properties  |
//+------------------------------------------------------------------+
void CAccountsCollection::SetAccountsParams(CAccount *account)
  {
   if(account==NULL)
      return;
//--- Name
   this.m_name=account.GetName();
//--- Account number
   this.m_struct_curr_account.login=account.Login();
//--- Leverage
   account.SetProperty(ACCOUNT_PROP_LEVERAGE,::AccountInfoInteger(ACCOUNT_LEVERAGE));
   this.m_struct_curr_account.leverage=account.Leverage();
   this.m_hash_sum+=(double)this.m_struct_curr_account.leverage;
//--- Maximum allowed number of active pending orders
   account.SetProperty(ACCOUNT_PROP_LIMIT_ORDERS,::AccountInfoInteger(ACCOUNT_LIMIT_ORDERS));
   this.m_struct_curr_account.limit_orders=(int)account.LimitOrders();
   this.m_hash_sum+=(double)this.m_struct_curr_account.limit_orders;
//--- Permission to trade for the current account from the server side
   account.SetProperty(ACCOUNT_PROP_TRADE_ALLOWED,::AccountInfoInteger(ACCOUNT_TRADE_ALLOWED));
   this.m_struct_curr_account.trade_allowed=account.TradeAllowed();
   this.m_hash_sum+=(double)this.m_struct_curr_account.trade_allowed;
//--- Permission to trade for an EA from the server side
   account.SetProperty(ACCOUNT_PROP_TRADE_EXPERT,::AccountInfoInteger(ACCOUNT_TRADE_EXPERT));
   this.m_struct_curr_account.trade_expert=account.TradeExpert();
   this.m_hash_sum+=(double)this.m_struct_curr_account.trade_expert;
//--- Account balance in a deposit currency
   account.SetProperty(ACCOUNT_PROP_BALANCE,::AccountInfoDouble(ACCOUNT_BALANCE));
   this.m_struct_curr_account.balance=account.Balance();
   this.m_hash_sum+=(double)this.m_struct_curr_account.balance;
//--- Credit in a deposit currency
   account.SetProperty(ACCOUNT_PROP_CREDIT,::AccountInfoDouble(ACCOUNT_CREDIT));
   this.m_struct_curr_account.credit=account.Credit();
   this.m_hash_sum+=(double)this.m_struct_curr_account.credit;
//--- Current profit on an account in the account currency
   account.SetProperty(ACCOUNT_PROP_PROFIT,::AccountInfoDouble(ACCOUNT_PROFIT));
   this.m_struct_curr_account.profit=account.Profit();
   this.m_hash_sum+=(double)this.m_struct_curr_account.profit;
//--- Equity on an account in the deposit currency
   account.SetProperty(ACCOUNT_PROP_EQUITY,::AccountInfoDouble(ACCOUNT_EQUITY));
   this.m_struct_curr_account.equity=account.Equity();
   this.m_hash_sum+=(double)this.m_struct_curr_account.equity;
//--- Reserved margin on an account in the deposit currency
   account.SetProperty(ACCOUNT_PROP_MARGIN,::AccountInfoDouble(ACCOUNT_MARGIN));
   this.m_struct_curr_account.margin=account.Margin();
   this.m_hash_sum+=(double)this.m_struct_curr_account.margin;
//--- Free funds available for opening a position on an account in the deposit currency
   account.SetProperty(ACCOUNT_PROP_MARGIN_FREE,::AccountInfoDouble(ACCOUNT_MARGIN_FREE));
   this.m_struct_curr_account.margin_free=account.MarginFree();
   this.m_hash_sum+=(double)this.m_struct_curr_account.margin_free;
//--- Margin level on an account in %
   account.SetProperty(ACCOUNT_PROP_MARGIN_LEVEL,::AccountInfoDouble(ACCOUNT_MARGIN_LEVEL));
   this.m_struct_curr_account.margin_level=account.MarginLevel();
   this.m_hash_sum+=(double)this.m_struct_curr_account.margin_level;
//--- Margin Call level
   account.SetProperty(ACCOUNT_PROP_MARGIN_SO_CALL,::AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL));
   this.m_struct_curr_account.margin_so_call=account.MarginSOCall();
   this.m_hash_sum+=(double)this.m_struct_curr_account.margin_so_call;
//--- Stop Out level
   account.SetProperty(ACCOUNT_PROP_MARGIN_SO_SO,::AccountInfoDouble(ACCOUNT_MARGIN_SO_SO));
   this.m_struct_curr_account.margin_so_so=account.MarginSOSO();
   this.m_hash_sum+=(double)this.m_struct_curr_account.margin_so_so;
//--- Funds reserved on an account to ensure a guarantee amount for all pending orders
   account.SetProperty(ACCOUNT_PROP_MARGIN_INITIAL,::AccountInfoDouble(ACCOUNT_MARGIN_INITIAL));
   this.m_struct_curr_account.margin_initial=account.MarginInitial();
   this.m_hash_sum+=(double)this.m_struct_curr_account.margin_initial;
//--- Funds reserved on an account to ensure a minimum amount for all open positions
   account.SetProperty(ACCOUNT_PROP_MARGIN_MAINTENANCE,::AccountInfoDouble(ACCOUNT_MARGIN_MAINTENANCE));
   this.m_struct_curr_account.margin_maintenance=account.MarginMaintenance();
   this.m_hash_sum+=(double)this.m_struct_curr_account.margin_maintenance;
//--- Current assets on an account
   account.SetProperty(ACCOUNT_PROP_ASSETS,::AccountInfoDouble(ACCOUNT_ASSETS));
   this.m_struct_curr_account.assets=account.Assets();
   this.m_hash_sum+=(double)this.m_struct_curr_account.assets;
//--- Current liabilities on an account
   account.SetProperty(ACCOUNT_PROP_LIABILITIES,::AccountInfoDouble(ACCOUNT_LIABILITIES));
   this.m_struct_curr_account.liabilities=account.Liabilities();
   this.m_hash_sum+=(double)this.m_struct_curr_account.liabilities;
//--- Current sum of blocked commissions on an account
   account.SetProperty(ACCOUNT_PROP_COMMISSION_BLOCKED,::AccountInfoDouble(ACCOUNT_COMMISSION_BLOCKED));
   this.m_struct_curr_account.comission_blocked=account.ComissionBlocked();
   this.m_hash_sum+=(double)this.m_struct_curr_account.comission_blocked;
  }
//+------------------------------------------------------------------+


Die Methode SetTypeEvent() der Klasse der Kollektion der Konten wurde ebenfalls verbessert und geändert, da Ereignisse eines beliebigen Objekts definiert werden können. Die Methode ist groß, obwohl alle Aktionen zur Definition von Kontoereignisarten vom gleichen Typ sind. Wir haben sie bereits bei der Analyse der Definition von Symbol-Ereignistypen berücksichtigt. Daher werde ich nur ein Beispiel für den Fall geben, dass der Handel auf einem Konto ermöglicht wird. Die vollständige Auflistung der Methode ist in den Dateien im Anhang des Artikels verfügbar:

//+------------------------------------------------------------------+
//| Set the account object event type                                |
//+------------------------------------------------------------------+
void CAccountsCollection::SetTypeEvent(void)
  {
   this.InitChangesParams();
   ENUM_ACCOUNT_EVENT event_id=ACCOUNT_EVENT_NO_EVENT;
//--- Changing permission to trade for the account
   if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_TRADE_ALLOWED))
     {
      if(!this.m_struct_curr_account.trade_allowed)
        {
         this.m_is_change_trade_allowed_off=true;
         event_id=ACCOUNT_EVENT_TRADE_ALLOWED_OFF;
         if(this.EventAdd(event_id,this.TickTime(),this.m_is_change_trade_allowed_off,this.m_name))
            this.m_struct_prev_account.trade_allowed=this.m_struct_curr_account.trade_allowed;
        }
      else
        {
         this.m_is_change_trade_allowed_on=true;
         event_id=ACCOUNT_EVENT_TRADE_ALLOWED_ON;
         if(this.EventAdd(event_id,this.TickTime(),this.m_is_change_trade_allowed_on,this.m_name))
            this.m_struct_prev_account.trade_allowed=this.m_struct_curr_account.trade_allowed;
        }
     }
//--- Changing permission for auto trading for the account


Damit sind die Änderungen und Verbesserungen der Klasse der Kollektion der Konten abgeschlossen. Jetzt ist es an der Zeit, die aktualisierten Symbol- und Kontoereignisklassen in Betrieb zu nehmen.

Wie Sie sich vielleicht erinnern, beginnt jede Steuerung mit der Klasse CEngine, und alle Daten werden ebenfalls an sie gesendet. Symbol- und Konto-Ereignisklassen bilden keine Ausnahme.

Umsetzung der Symbol-Ereignisklasse und der verbesserten Kontoklasse

Öffnen Sie die Datei Engine.mqh und nehmen Sie die notwendigen Änderungen vor.

Deklarieren Sie im 'private' Bereich der Klasse das Flag der Symbolereignisse und einen Wert des letzten Ereignisses eines Symbols:

//+------------------------------------------------------------------+
//| Bibliothek der Basisklasse                                       |
//+------------------------------------------------------------------+
class CEngine : public CObject
  {
private:
   CHistoryCollection   m_history;                       // Kollektion der historischen Aufträge und Deals
   CMarketCollection    m_market;                        // Kollektion der Marktorder und Deals
   CEventsCollection    m_events;                        // Event collection
   CAccountsCollection  m_accounts;                      // Account collection
   CSymbolsCollection   m_symbols;                       // Symbol collection
   CArrayObj            m_list_counters;                 // Liste der Timerzähler
   int                  m_global_error;                  // Global error code
   bool                 m_first_start;                   // Flag des Erststarts
   bool                 m_is_hedge;                      // Flag des Hedging-Kontos
   bool                 m_is_tester;                     // Flag of working in the tester
   bool                 m_is_market_trade_event;         // Flag eines Handelsereignisses des Kontos
   bool                 m_is_history_trade_event;        // Flag eines historischen Handelsereignisses auf dem Konto
   bool                 m_is_account_event;              // Account change event flag
   bool                 m_is_symbol_event;               // Symbol change event flag
   ENUM_TRADE_EVENT     m_last_trade_event;              // Last account trading event
   ENUM_ACCOUNT_EVENT   m_last_account_event;            // Last event in the account properties
   ENUM_SYMBOL_EVENT    m_last_symbol_event;             // Last event in the symbol properties
//--- Rückgabe des Zählerindex über die ID


In the public section of the class, declare the method returning the description of the last trading event:

//--- Return the list of historical (1) orders, (2) removed pending orders, (3) deals,
//--- (4) all market orders of a position by its ID, (5) description of the last trading event
   CArrayObj           *GetListHistoryOrders(void);
   CArrayObj           *GetListHistoryPendings(void);
   CArrayObj           *GetListDeals(void);
   CArrayObj           *GetListAllOrdersByPosID(const ulong position_id);
   string               GetLastTradeEventDescription(void);


und die neuen Methoden zum Arbeiten mit Symbolereignissen. Außerdem ändern Sie die Methode , die das Flag des Kontoereignisses zurückgibt:.

//--- Return the list of (1) used symbols, (2) symbol events, (3) the last symbol change event
//--- (4) the current symbol, (5) symbol event description, (6) Market Watch event description
   CArrayObj           *GetListAllUsedSymbols(void)                     { return this.m_symbols.GetList();                    }
   CArrayObj           *GetListSymbolsEvents(void)                      { return this.m_symbols.GetListEvents();              }
   ENUM_SYMBOL_EVENT    GetLastSymbolsEvent()                           { return this.m_symbols.GetLastEvent();               }
   CSymbol             *GetSymbolCurrent(void);
   string               GetSymbolEventDescription(ENUM_SYMBOL_EVENT event);
   string               GetMWEventDescription(ENUM_SYMBOL_EVENT event)  { return this.m_symbols.EventDescription(event);      }
   string               ModeSymbolsListDescription(void)                { return this.m_symbols.ModeSymbolsListDescription(); }
   
//--- Return the list of order, deal and position events
   CArrayObj           *GetListAllOrdersEvents(void)                    { return this.m_events.GetList();                     }
//--- Rücksetzen des letzten Handelsereignisses
   void                 ResetLastTradeEvent(void)                       { this.m_events.ResetLastTradeEvent(); }
//--- Return the (1) last trading event, (2) the last event in the account properties, (3) hedging account flag, (4) flag of working in the tester
   ENUM_TRADE_EVENT     LastTradeEvent(void)                      const { return this.m_last_trade_event;                     }
   ENUM_ACCOUNT_EVENT   LastAccountEvent(void)                    const { return this.m_last_account_event;                   }
   ENUM_SYMBOL_EVENT    LastSymbolsEvent(void)                    const { return this.m_last_symbol_event;                    }
//--- Return the (1) hedge account, (2) working in the tester, (3) account event and (4) symbol event flag
   bool                 IsHedge(void)                             const { return this.m_is_hedge;                             }
   bool                 IsTester(void)                            const { return this.m_is_tester;                            }
   bool                 IsAccountsEvent(void)                     const { return this.m_accounts.IsEvent();                   }
   bool                 IsSymbolsEvent(void)                      const { return this.m_symbols.IsEvent();                    }
//--- Return the (1) symbol object by name, as well as the code of the last event of (2) an account and (3) a symbol
   CSymbol             *GetSymbolObjByName(const string name)           { return this.m_symbols.GetSymbolByName(name);        }
   int                  GetAccountEventsCode(void)                const { return this.m_accounts.GetEventCode();              }
   int                  GetSymbolsEventsCode(void)                const { return this.m_symbols.GetLastEventsCode();          }
//--- Return the number of (1) symbols, (2) events in the symbol collection
   int                  GetSymbolsCollectionTotal(void)           const { return this.m_symbols.GetSymbolsCollectionTotal();  }
   int                  GetSymbolsCollectionEventsTotal(void)     const { return this.m_symbols.GetEventsTotal();             }


In der Initialisierungsliste des Klassenkonstruktors fügen Sie die Initialisierung des letzten Ereignisses in der Symbolkollektion hinzu:

//+------------------------------------------------------------------+
//| CEngine Konstruktor                                              |
//+------------------------------------------------------------------+
CEngine::CEngine() : m_first_start(true),
                     m_last_trade_event(TRADE_EVENT_NO_EVENT),
                     m_last_account_event(ACCOUNT_EVENT_NO_EVENT),
                     m_last_symbol_event(SYMBOL_EVENT_NO_EVENT),
                     m_global_error(ERR_SUCCESS)
  {
   this.m_is_hedge=#ifdef __MQL4__ true #else bool(::AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) #endif;
   this.m_is_tester=::MQLInfoInteger(MQL_TESTER);
   
   this.m_list_counters.Sort();
   this.m_list_counters.Clear();
   this.CreateCounter(COLLECTION_ORD_COUNTER_ID,COLLECTION_ORD_COUNTER_STEP,COLLECTION_ORD_PAUSE);
   this.CreateCounter(COLLECTION_ACC_COUNTER_ID,COLLECTION_ACC_COUNTER_STEP,COLLECTION_ACC_PAUSE);
   
   this.CreateCounter(COLLECTION_SYM_COUNTER_ID1,COLLECTION_SYM_COUNTER_STEP1,COLLECTION_SYM_PAUSE1);
   this.CreateCounter(COLLECTION_SYM_COUNTER_ID2,COLLECTION_SYM_COUNTER_STEP2,COLLECTION_SYM_PAUSE2);
   
   ::ResetLastError();
   #ifdef __MQL5__
      if(!::EventSetMillisecondTimer(TIMER_FREQUENCY))
        {
         ::Print(DFUN_ERR_LINE,"Не удалось создать таймер. Ошибка: ","Could not create timer. Error: ",(string)::GetLastError());
         this.m_global_error=::GetLastError();
        }
   //---__MQL4__
   #else 
      if(!this.IsTester() && !::EventSetMillisecondTimer(TIMER_FREQUENCY))
        {
         ::Print(DFUN_ERR_LINE,"Не удалось создать таймер. Ошибка: ","Could not create timer. Error: ",(string)::GetLastError());
         this.m_global_error=::GetLastError();
        }
   #endif 
  }
//+------------------------------------------------------------------+


Fügen Sie in den Timern der Klassen Änderungen an den Timer 1 und Timer 2 Behandlungsblöcken der Symbolkollektion hinzu:

//+------------------------------------------------------------------+
//| CEngine Timer                                                    |
//+------------------------------------------------------------------+
void CEngine::OnTimer(void)
  {
//--- Timer der Kollektion der historischen Aufträge und Deals, und aus der Marktorders und Positionen
   int index=this.CounterIndex(COLLECTION_ORD_COUNTER_ID);
   if(index>WRONG_VALUE)
     {
      CTimerCounter* counter=this.m_list_counters.At(index);
      if(counter!=NULL)
        {
         //--- If this is not a tester
         if(!this.IsTester())
           {
            //--- If unpaused, work with the order, deal and position collections events
            if(counter.IsTimeDone())
               this.TradeEventsControl();
           }
         //--- If this is a tester, work with collection events by tick
         else
            this.TradeEventsControl();
        }
     }
//--- Account collection timer
   index=this.CounterIndex(COLLECTION_ACC_COUNTER_ID);
   if(index>WRONG_VALUE)
     {
      CTimerCounter* counter=this.m_list_counters.At(index);
      if(counter!=NULL)
        {
         //--- If this is not a tester
         if(!this.IsTester())
           {
            //--- If unpaused, work with the account collection events
            if(counter.IsTimeDone())
               this.AccountEventsControl();
           }
         //--- If this is a tester, work with collection events by tick
         else
            this.AccountEventsControl();
        }
     }
     
//--- Timer 1 of the symbol collection (updating symbol quote data in the collection)
   index=this.CounterIndex(COLLECTION_SYM_COUNTER_ID1);
   if(index>WRONG_VALUE)
     {
      CTimerCounter* counter=this.m_list_counters.At(index);
      if(counter!=NULL)
        {
         //--- If this is not a tester
         if(!this.IsTester())
           {
            //--- If the pause is over, update quote data of all symbols in the collection
            if(counter.IsTimeDone())
               this.m_symbols.RefreshRates();
           }
         //--- In case of a tester, update quote data of all collection symbols by tick
         else
            this.m_symbols.RefreshRates();
        }
     }
//--- Timer 2 of the symbol collection (updating all data of all symbols in the collection and tracking symbl and symbol search events in the market watch window)
   index=this.CounterIndex(COLLECTION_SYM_COUNTER_ID2);
   if(index>WRONG_VALUE)
     {
      CTimerCounter* counter=this.m_list_counters.At(index);
      if(counter!=NULL)
        {
         //--- If this is not a tester
         if(!this.IsTester())
           {
            //--- If the pause is over
            if(counter.IsTimeDone())
              {
               //--- update data and work with events of all symbols in the collection
               this.SymbolEventsControl();
               //--- When working with the market watch list, check the market watch window events
               if(this.m_symbols.ModeSymbolsList()==SYMBOLS_MODE_MARKET_WATCH)
                  this.MarketWatchEventsControl();
              }
           }
         //--- If this is a tester, work with events of all symbols in the collection by tick
         else
            this.SymbolEventsControl();
        }
     }
  }
//+------------------------------------------------------------------+


Hier, nachdem der Zähler des Timer 1 seine Arbeit beendet hat, müssen wir einfach die Kursdaten aller Kollektionssymbole aktualisieren, daher rufen wir die RefreshRates() Methode der Symbolkollektion auf.
Nach Abschluss der Zähleroperation in Timer 2 müssen wir alle Kollektionssymbole vollständig aktualisieren und die aufgetretenen Ereignisse sowohl der Symbolkollektion als auch der Liste der Marktübersicht verfolgen, daher rufen wir die Methoden der Klasse CEngine SymbolEventsControl() auf und, wenn wir nicht im Tester arbeiten, MarketWatchEventsControl().

Implementierung der Methode zum Arbeiten mit Ereignissen der Symbolkollektion:

//+------------------------------------------------------------------+
//| Working with symbol collection events                            |
//+------------------------------------------------------------------+
void CEngine::SymbolEventsControl(void)
  {
   this.m_symbols.SymbolsEventsControl();
   this.m_is_symbol_event=this.m_symbols.IsEvent();
//--- If there are changes in symbol properties
   if(this.m_is_symbol_event)
     {
      //--- Get the last event of the symbol property change
      this.m_last_symbol_event=this.m_symbols.GetLastEvent();
     }
  }
//+------------------------------------------------------------------+


Hier rufen wir die Methode der Symbolkollektion SymbolsEventsControl() auf, die wir oben bei der Diskussion der Klasse der Ereignisse der Symbolkollektion besprochen haben. Nachdem die Methode ihre Arbeit beendet hat, wird das Ereignis-Flag in der Klasse der Symbolkollektion aktiviert, sofern an einem beliebigen Sammelsymbol ein Ereignis erkannt wurde. Der Flagstatus wird über die Methode IsEvent() der Basisobjektklasse CBaseObj auf die Ereignisvariable der Symbolkollektion m_is_symbol_event gesetzt, deren Wert im aufrufenden Programm verfolgt werden kann. Wenn ein Ereignis in der Symbolkollektion registriert wurde, wird das letzte Ereignis in die Variable m_last_symbol_event geschrieben. Sein Wert kann auch im aufrufenden Programm verfolgt werden.

Implementierung der Methode zur Arbeit mit den Ereignissen der Marktübersicht:

//+------------------------------------------------------------------+
//| Working with symbol list events in the market watch window       |
//+------------------------------------------------------------------+
void CEngine::MarketWatchEventsControl(void)
  {
   if(this.IsTester())
      return;
   this.m_symbols.MarketWatchEventsControl();
  }
//+------------------------------------------------------------------+


Hier, wenn dies der Tester ist, exit, andernfalls rufen Sie die Methode MarketWatchEventsControl() der Klasse der Symbolkollektion zur Behandlung der Ereignisse der Marktübersicht. Wir haben die obige Methode bereits besprochen, als wir die Verfolgung der Ereignisse der Symbolkollektion diskutierten.

Implementierung der Methode, die die Beschreibung des letzten Handelsgeschehens zurückgibt:

//+------------------------------------------------------------------+
//| Return the description of the last trading event                 |
//+------------------------------------------------------------------+
string CEngine::GetLastTradeEventDescription(void)
  {
   CArrayObj *list=this.m_events.GetList();
   if(list!=NULL)
     {
      if(list.Total()==0)
         return TextByLanguage("С момента последнего запуска ЕА торговых событий не было","There have been no trade events since the last launch of EA");
      CEvent *event=list.At(list.Total()-1);
      if(event!=NULL)
         return event.TypeEventDescription();
     }
   return DFUN_ERR_LINE+TextByLanguage("Не удалось получить описание последнего торгового события","Failed to get the description of the last trading event");
  }
//+------------------------------------------------------------------+


Hier, wir erhalten die vollständige Liste der Handelsereignisse des Kontos. Wenn die Liste erhalten wird, aber ihre Größe Null ist, geben Sie die Nachricht 'no trading events yet' zurück andernfalls holen Sie sich das letzte Ereignis der Liste und geben dessen Beschreibung zurück. Im gegenteiligen Fall geben Sie die Meldung über den erfolglosen Erhalt eines Handelsereignisses zurück.

Die Methode, die die Beschreibung des letzten Ereignisses in der Symbolkollektion zurückgibt:

//+------------------------------------------------------------------+
//| Return the symbol event description                              |
//+------------------------------------------------------------------+
string CEngine::GetSymbolEventDescription(ENUM_SYMBOL_EVENT event)
  {
   CArrayObj *list=this.m_symbols.GetList();
   if(list!=NULL)
     {
      if(list.Total()==0)
         return TextByLanguage("С момента последнего запуска ЕА не было никаких событий символов","There have been no events of symbols since the last launch of EA");
      CSymbol *symbol=list.At(list.Total()-1);
      if(symbol!=NULL)
         return symbol.EventDescription(event);
     }
   return DFUN_ERR_LINE+TextByLanguage("Не удалось получить описание события символа","Failed to get symbol's event description");
  }
//+------------------------------------------------------------------+


Die Methode funktioniert ähnlich wie die Methode zur Rückgabe des letzten Handelsgeschehens, das wir gerade betrachtet haben.

Die Verbesserung der Klasse CEngine ist abgeschlossen. Alles ist bereit zum Testen der Symbolereignisse sowie der aktualisierten Kontoklasse und der Kontoereignisse.

Einige zusätzliche Änderungen wurden an den Klassen vorgenommen. Sie wurden hier nicht berücksichtigt, da sie meist mit den Namen einiger Methoden zusammenhängen. Sie wurden eingeführt, um sicherzustellen, dass die gleichartigen Methoden verschiedener Klassen bei Bedarf den gleichen Namen tragen. Ich glaube, es hat keinen Sinn, all diese kleinen Verbesserungen im Artikel zu beschreiben, da sich der Bibliothekscode ständig weiterentwickelt. Sie können sie wie immer in den Dateien finden, die den Artikeln beigefügt sind.

Testen von Symbol- und Kontoereignissen

Zum Testen verwenden wir den Test EA vom vorherigen Artikel, speichern ihn in \MQL5\Experts\TestDoEasy\ unter dem Namen Part16\TestDoEasyPart16.mq5 und fügen alle notwendigen Änderungen hinzu.

Fügen Sie in der Liste der globalen Variablen fügen Sie Variable zum Speichern der Arbeitsweise mit den Symbollisten hinzu:

//--- Globale Variablen
CEngine        engine;
#ifdef __MQL5__
CTrade         trade;
#endif 
SDataButt      butt_data[TOTAL_BUTT];
string         prefix;
double         lot;
double         withdrawal=(InpWithdrawal<0.1 ? 0.1 : InpWithdrawal);
ulong          magic_number;
uint           stoploss;
uint           takeprofit;
uint           distance_pending;
uint           distance_stoplimit;
uint           slippage;
bool           trailing_on;
double         trailing_stop;
double         trailing_step;
uint           trailing_start;
uint           stoploss_to_modify;
uint           takeprofit_to_modify;
int            used_symbols_mode;
string         used_symbols;
string         array_used_symbols[];


Bei der Auswahl des Modus "Working with the full list of symbols on the server" (Arbeiten mit der vollständigen Liste der Symbole auf dem Server) für die Arbeit mit Symbolen kann der erste Start recht lange dauern, da die Symbolkollektion alle Daten über alle vorhandenen Symbole sammeln muss. Deshalb müssen wir die Nutzer davor warnen. Es macht keinen Sinn, das in der Bibliothek selbst zu tun, da sie nur das tut, was die Nutzer von ihr verlangen. Daher sollte die Warnung in OnInit() des Programms erfolgen.

Lasst es uns wie folgt machen. Wenn in den EA-Einstellungen die vollständige Liste der auf dem Server verfügbaren Symbole ausgewählt ist, zeigt das Programm die Standardfunktion MessageBox() mit der Warnung an.


Aufforderung zur Auswahl von Ja für den Download der vollständigen Liste der Symbole und Nein für die Arbeit nur mit dem aktuellen Symbol. Ein Nutzer muss nur eine Wahl treffen: Klicken Sie auf Ja und warten Sie, bis die Kollektion aus allen verfügbaren Symbolen erstellt wurde, oder klicken Sie auf Nein und arbeiten Sie mit dem aktuellen Symbol.

Lassen Sie uns den Check mit der Möglichkeit vorbereiten, die Frage in OnInit() des EA zu senden:

//--- Check if working with the full list is selected
   used_symbols_mode=InpModeUsedSymbols;
   if((ENUM_SYMBOLS_MODE)used_symbols_mode==SYMBOLS_MODE_ALL)
     {
      int total=SymbolsTotal(false);
      string ru_n="\nКоличество символов на сервере "+(string)total+".\nМаксимальное количество: "+(string)SYMBOLS_COMMON_TOTAL+" символов.";
      string en_n="\nThe number of symbols on server "+(string)total+".\nMaximal number: "+(string)SYMBOLS_COMMON_TOTAL+" symbols.";
      string caption=TextByLanguage("Внимание!","Attention!");
      string ru="Выбран режим работы с полным списком.\nВ этом режиме первичная подготовка списка коллекции символов может занять длительное время."+ru_n+"\nПродолжить?\n\"Нет\" - работа с текущим символом \""+Symbol()+"\"";
      string en="Full list mode selected.\nIn this mode, the initial preparation of the collection symbols list may take a long time."+en_n+"\nContinue?\n\"No\" - working with the current symbol \""+Symbol()+"\"";
      string message=TextByLanguage(ru,en);
      int flags=(MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2);
      int mb_res=MessageBox(message,caption,flags);
      switch(mb_res)
        {
         case IDNO : 
           used_symbols_mode=SYMBOLS_MODE_CURRENT; 
           break;
         default:
           break;
        }
     }


Hier wird die Arbeitsweise mit den von einem Benutzer in den EA-Einstellungen ausgewählten Symbolen dem used_symbols_mode globale Variable zugeordnet.
Wenn die Arbeit mit der Gesamtliste ausgewählt ist
, erzeugen Sie den Text des Warnhinweises und zeigen Sie dies im Fenster auf dem Bildschirm. Als Nächstes überprüfen Sie, welche Schaltfläche vom Nutzer angeklickt wurde. Wenn nein, wird die Arbeitsweise mit dem aktuellen Symbol der Variablen used_symbols_mode zugewiesen.
In den übrigen Fällen (Ja-Taste oder Esc) belassen Sie den Arbeitsmodus mit der vollständigen Liste der verfügbaren Symbole.

Als Nächstes erstellen Sie das Array der verwendeten Symbole (senden Sie die Variable used_symbols_mode an die Array-Erzeugungsfunktion):

//--- Fill in the array of used symbols
   used_symbols=InpUsedSymbols;
   CreateUsedSymbolsArray((ENUM_SYMBOLS_MODE)used_symbols_mode,used_symbols,array_used_symbols);


Setzen Sie den Typ der verwendeten Liste (Modus der Arbeit mit Symbolen) in der Bibliothek und Senden Sie die Nachricht über den angewandten Modus der Arbeit mit Symbolen an das Journal:

//--- Set the type of the used symbol list in the symbol collection
   engine.SetUsedSymbols(array_used_symbols);
//--- Displaying the selected mode of working with the symbol object collection
   Print(engine.ModeSymbolsListDescription(),TextByLanguage(". Количество используемых символов: ",". Number of symbols used: "),engine.GetSymbolsCollectionTotal());


Der Codeblock für die Schnellprüfung einer Symbolkollektion wird aus OnInit() entfernt, da er in diesem Test EA nicht benötigt wird:

//--- Fast check of the symbol object collection
   CArrayObj *list=engine.GetListAllUsedSymbols();
   CSymbol *symbol=NULL;
   if(list!=NULL)
     {
      int total=list.Total();
      for(int i=0;i<total;i++)
        {
         symbol=list.At(i);
         if(symbol==NULL)
            continue;
         symbol.Refresh();
         symbol.RefreshRates();
         symbol.PrintShort();
         if(InpModeUsedSymbols<SYMBOLS_MODE_MARKET_WATCH)
            symbol.Print();
        }
     }


Fügen Sie die Variable zum Speichern des letzten Ereignisses in der Symbolkollektion zu OnTick() und schreiben (oder Ändern im Falle von Kontoereignissen) Sie die Ereigniskollektionen des Kontos und der Symbole:

//+------------------------------------------------------------------+
//| Experten Funktion OnTick                                         |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Initializing the last events
   static ENUM_TRADE_EVENT last_trade_event=WRONG_VALUE;
   static ENUM_ACCOUNT_EVENT last_account_event=WRONG_VALUE;
   static ENUM_SYMBOL_EVENT last_symbol_event=WRONG_VALUE;
//--- If working in the tester
   if(MQLInfoInteger(MQL_TESTER))
     {
      engine.OnTimer();
      PressButtonsControl();
     }
//--- If the last trading event changed
   if(engine.LastTradeEvent()!=last_trade_event)
     {
      last_trade_event=engine.LastTradeEvent();
      Comment("\nLast trade event: ",engine.GetLastTradeEventDescription());
      engine.ResetLastTradeEvent();
     }
//--- If there is an account event
   if(engine.IsAccountsEvent())
     {
      //--- the last account event
      last_account_event=engine.LastAccountEvent();
      //--- If this is a tester
      if(MQLInfoInteger(MQL_TESTER))
        {
         //--- Get the list of all account events occurred simultaneously
         CArrayObj* list=engine.GetListAccountEvents();
         if(list!=NULL)
           {
            //--- Get the next event in a loop
            int total=list.Total();
            for(int i=0;i<total;i++)
              {
               //--- take an event from the list
               CEventBaseObj *event=list.At(i);
               if(event==NULL)
                  continue;
               //--- Send an event to the event handler
               long lparam=event.LParam();
               double dparam=event.DParam();
               string sparam=event.SParam();
               OnDoEasyEvent(CHARTEVENT_CUSTOM+event.ID(),lparam,dparam,sparam);
              }
           }
        }
     }
//--- If there is a symbol collection event
   if(engine.IsSymbolsEvent())
     {
      //--- the last event in the symbol collection
      last_symbol_event=engine.LastSymbolsEvent();
      //--- If this is a tester
      if(MQLInfoInteger(MQL_TESTER))
        {
         //--- Get the list of all symbol events occurred simultaneously
         CArrayObj* list=engine.GetListSymbolsEvents();
         if(list!=NULL)
           {
            //--- Get the next event in a loop
            int total=list.Total();
            for(int i=0;i<total;i++)
              {
               //--- take an event from the list
               CEventBaseObj *event=list.At(i);
               if(event==NULL)
                  continue;
               //--- Send an event to the event handler
               long lparam=event.LParam();
               double dparam=event.DParam();
               string sparam=event.SParam();
               OnDoEasyEvent(CHARTEVENT_CUSTOM+event.ID(),lparam,dparam,sparam);
              }
           }
        }
     }
//--- If the trailing flag is set
   if(trailing_on)
     {
      TrailingPositions();
      TrailingOrders();
     }
  }
//+------------------------------------------------------------------+


Hier ist alles einfach. Alle notwendigen Aktionen zur Behandlung der Ereigniskollektionen des Kontos und der Symbole Ereignissen werden in der Liste kommentiert.

Wie Sie sehen können, ist die Ereignisbehandlung nun für alle Objekte ähnlich — sowohl für ein Konto als auch für eine Symbolkollektion. Es läuft alles darauf hinaus, die Liste der Ereignisse zu empfangen und jedes neue Ereignis aus der Liste an OnDoEasyEvent() des EA zu senden, der die Ereignisbibliotheken verarbeitet. Dies wurde durch Änderungen bei der Vererbung der Bibliotheksobjekte des Basisobjekts CBaseObj ermöglicht, in dem die Behandlung von Ereignissen in den abgeleiteten Objekten implementiert wurde.

Fügen Sie in OnDoEasyEvent() den Code zur Behandlung der Ereignisse der Symbolkollektion hinzu:

//+------------------------------------------------------------------+
//| Handling DoEasy library events                                   |
//+------------------------------------------------------------------+
void OnDoEasyEvent(const int id,
                   const long &lparam,
                   const double &dparam,
                   const string &sparam)
  {
   int idx=id-CHARTEVENT_CUSTOM;
   string event="::"+string(idx);
   int digits=Digits();
//--- Handling trading events
   if(idx>TRADE_EVENT_NO_EVENT && idx<TRADE_EVENTS_NEXT_CODE)
     {
      event=EnumToString((ENUM_TRADE_EVENT)ushort(idx));
      digits=(int)SymbolInfoInteger(sparam,SYMBOL_DIGITS);
     }
//--- Handling account events
   else if(idx>ACCOUNT_EVENT_NO_EVENT && idx<ACCOUNT_EVENTS_NEXT_CODE)
     {
      Print(TimeMSCtoString(lparam)," ",sparam,": ",engine.GetAccountEventDescription((ENUM_ACCOUNT_EVENT)idx));
      
      //--- if this is an equity increase
      if((ENUM_ACCOUNT_EVENT)idx==ACCOUNT_EVENT_EQUITY_INC)
        {
         //--- Close a position with the highest profit exceeding zero when the equity exceeds the value,
         //--- specified in the CAccountsCollection::InitControlsParams() method for
         //--- the m_control_equity_inc variable tracking the equity growth by 15 units (by default)
         //--- AccountCollection file, InitControlsParams() method, string 1199
         
         //--- Abrufen der Liste aller offenen Positionen
         CArrayObj* list_positions=engine.GetListMarketPosition();
         //--- Select positions with the profit exceeding zero
         list_positions=CSelect::ByOrderProperty(list_positions,ORDER_PROP_PROFIT_FULL,0,MORE);
         if(list_positions!=NULL)
           {
            //--- Sortieren der Liste nach Gewinn unter Berücksichtigung von Kommission und Swap
            list_positions.Sort(SORT_BY_ORDER_PROFIT_FULL);
            //--- Get the position index with the highest profit
            int index=CSelect::FindOrderMax(list_positions,ORDER_PROP_PROFIT_FULL);
            if(index>WRONG_VALUE)
              {
               COrder* position=list_positions.At(index);
               if(position!=NULL)
                 {
                  //--- Get a ticket of a position with the highest profit and close the position by a ticket
                  #ifdef __MQL5__
                     trade.PositionClose(position.Ticket());
                  #else 
                     PositionClose(position.Ticket(),position.Volume());
                  #endif 
                 }
              }
           }
        }
     }
     
//--- Handling symbol events
   else if(idx>SYMBOL_EVENT_NO_EVENT && idx<SYMBOL_EVENTS_NEXT_CODE)
     {
      string name="";
      //--- Market Watch window event
      if(idx<SYMBOL_EVENT_TRADE_DISABLE)
        {
         string descr=engine.GetMWEventDescription((ENUM_SYMBOL_EVENT)idx);
         name=(idx==SYMBOL_EVENT_MW_SORT ? "" : ": "+sparam);
         Print(TimeMSCtoString(lparam)," ",descr,name);
        }
      //--- Symbol event
      else
        {
         CSymbol *symbol=engine.GetSymbolObjByName(sparam);
         if(symbol!=NULL)
           {
            string descr=": "+symbol.EventDescription((ENUM_SYMBOL_EVENT)ushort(idx));
            Print(TimeMSCtoString(lparam)," ",sparam,descr);
           }
        }
     }
  }
//+------------------------------------------------------------------+


Hier haben wir nur zwei Möglichkeiten: die Ereignisbehandlung von der Marktübersicht und die der Symbolkollektion.

Für die Ereignisse der Marktübersicht,
Erstellen Sie die notwendige Nachricht
und senden Sie sie an das Journal,
während für Symbolereignisse,
ein Symbol aus der Liste mit seinem Namen
aus dem 'sparam' string-Parameter übernommen, die string-Beschreibung eines Ereignisses aus einem Symbolobjekt holen, es zum erzeugten Text hinzufügen und den Text an das Journal senden.
Wir werden keine weiteren zusätzlichen Maßnahmen für die Tests durchführen.

Dies schließt die Änderungen des Tests EA ab.
Die vollständige EA-Liste finden Sie in den angehängten Dateien.

Wenn Sie den EA über ein Demo-Konto starten, sehen Sie Einträge zu den Symbol-Eigenschaften, die sich nach einiger Zeit ändern. Wenn Sie beispielsweise den EA am Vorabend der Eröffnung einer Handelssitzung am Montag starten, erscheinen im Journal mehrere Einträge über einen veränderten Spread verschiedener Symbole.
Im folgenden Beispiel erscheinen die folgenden Meldungen über Änderungen des Spreads des Symbols im Journal innerhalb einer Stunde für nur vier Symbole in der Marktübersicht:

2019.07.15 04:02:24.167 TestDoEasyPart16 (EURUSD,H4)    Working with symbols from the "Market Watch" window. The number of symbols used: 4
2019.07.15 04:02:25.762 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:02:27.316 GBPUSD: Spread value in points decreased by -7 (351)
2019.07.15 04:02:31.259 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:02:32.676 USDCHF: Spread value in points increased by 4 (287)
2019.07.15 04:02:33.761 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:02:35.218 USDCHF: Spread value in points decreased by -4 (283)
2019.07.15 04:02:46.261 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:02:47.680 USDCHF: Spread value in points increased by 4 (287)
2019.07.15 04:02:48.761 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:02:50.222 USDCHF: Spread value in points decreased by -4 (283)
2019.07.15 04:02:53.760 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:02:55.305 USDCHF: Spread value in points increased by 4 (287)
2019.07.15 04:02:56.760 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:02:58.221 USDCHF: Spread value in points decreased by -4 (283)
2019.07.15 04:03:01.261 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:03:02.683 USDCHF: Spread value in points increased by 4 (287)
2019.07.15 04:03:03.760 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:03:05.226 USDCHF: Spread value in points decreased by -4 (283)
2019.07.15 04:03:16.260 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:03:17.673 USDCHF: Spread value in points increased by 4 (287)
2019.07.15 04:03:18.789 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:03:20.219 USDCHF: Spread value in points decreased by -4 (283)
2019.07.15 04:03:30.832 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:03:32.686 USDCHF: Spread value in points increased by 4 (287)
2019.07.15 04:03:33.819 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:03:35.219 USDCHF: Spread value in points decreased by -4 (283)
2019.07.15 04:03:38.820 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:03:39.926 USDCHF: Spread value in points increased by 4 (287)
2019.07.15 04:03:41.821 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:03:43.221 USDCHF: Spread value in points decreased by -4 (283)
2019.07.15 04:03:45.820 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:03:47.673 USDCHF: Spread value in points increased by 4 (287)
2019.07.15 04:03:48.836 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:03:50.234 USDCHF: Spread value in points decreased by -4 (283)
2019.07.15 04:03:50.865 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:03:52.598 USDCHF: Spread value in points increased by 51 (334)
2019.07.15 04:03:58.867 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:04:00.450 EURUSD: Spread value in points decreased by -42 (50)
2019.07.15 04:03:58.868 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:04:00.430 USDCHF: Spread value in points decreased by -96 (238)
2019.07.15 04:03:59.417 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:04:00.934 USDCHF: Spread value in points increased by 22 (260)
2019.07.15 04:03:59.912 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:04:01.431 USDCHF: Spread value in points decreased by -5 (255)
2019.07.15 04:04:35.445 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:04:36.984 GBPUSD: Spread value in points decreased by -112 (239)
2019.07.15 04:04:35.445 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:04:36.985 EURUSD: Spread value in points decreased by -7 (43)
2019.07.15 04:04:35.445 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:04:36.984 USDCHF: Spread value in points decreased by -127 (128)
2019.07.15 04:04:58.460 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:05:00.102 GBPUSD: Spread value in points decreased by -207 (32)
2019.07.15 04:04:58.959 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:05:00.696 EURUSD: Spread value in points decreased by -4 (39)
2019.07.15 04:05:01.006 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:05:02.697 EURUSD: Spread value in points increased by 3 (42)
2019.07.15 04:05:02.037 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:05:03.686 EURUSD: Spread value in points decreased by -32 (10)


... ohne Wiederholungen ...

2019.07.15 04:55:09.780 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:55:11.578 GBPUSD: Spread value in points decreased by -3 (29)
2019.07.15 04:55:09.780 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:55:11.478 USDCHF: Spread value in points increased by 4 (32)
2019.07.15 04:55:10.482 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:55:11.681 USDCHF: Spread value in points decreased by -3 (29)
2019.07.15 04:55:11.623 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:55:13.477 USDCHF: Spread value in points increased by 3 (32)
2019.07.15 04:55:12.111 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:55:13.884 USDCHF: Spread value in points decreased by -5 (27)
2019.07.15 04:55:13.626 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:55:15.275 USDCHF: Spread value in points increased by 4 (31)
2019.07.15 04:55:19.628 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:55:21.381 USDCHF: Spread value in points decreased by -3 (28)
2019.07.15 04:55:20.126 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:55:21.882 USDCHF: Spread value in points increased by 3 (31)
2019.07.15 04:55:28.659 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:55:30.292 EURUSD: Spread value in points increased by 3 (20)
2019.07.15 04:55:33.690 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:55:35.298 EURUSD: Spread value in points decreased by -3 (17)
2019.07.15 04:55:53.298 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:55:55.137 EURUSD: Spread value in points increased by 3 (20)
2019.07.15 04:55:53.826 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:55:55.643 EURUSD: Spread value in points decreased by -3 (17)
2019.07.15 04:55:54.906 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:55:56.632 USDCHF: Spread value in points decreased by -3 (28)
2019.07.15 04:55:55.912 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:55:57.536 USDCHF: Spread value in points increased by 4 (32)
2019.07.15 04:55:56.907 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:55:58.636 USDCHF: Spread value in points decreased by -4 (28)
2019.07.15 04:55:57.434 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:55:58.832 USDCHF: Spread value in points increased by 4 (32)
2019.07.15 04:55:59.949 TestDoEasyPart16 (EURUSD,H4)    2019.07.15 00:56:01.538 USDCHF: Spread value in points decreased by -3 (29)


Starten wir nun den EA im Tester mit zwei Symbolen und sehen wir, welche Einträge er anzeigt.

Wählen Sie in den Einstellungen des Testers für den Eingabeparameter Modus der Liste der verwendeten Symbole EA "Working with the specified symbol list" aus der Dropdown-Liste, während Sie in der Parameter Liste der verwendeten Symbole (Komma - Trennzeichen) zwei kommagetrennte Symbole eingeben: EURUSD,GBPUSD und starten Sie den visuellen EA-Test:


Die Einträge über die Ereignisse beider Symbole (insbesondere die, die sich auf Spreadänderungen der verwendeten Symbole beziehen) werden an das Journal gesendet. Bei der Änderung der Kontoeigenschaften (in unserem Fall handelt es sich um eine Erhöhung des laufenden Gewinns) werden die entsprechenden Einträge an das Journal gesendet und profitable Positionen geschlossen.

Was kommt als Nächstes?

Im nächsten Artikel werden wir einen komfortablen Zugriff auf die Änderung der Werte von kontrollierten und verfolgten Objekteigenschaften aus dem Programm auf der Grundlage der Basisobjektklasse CBaseObj implementieren.

Alle Dateien der aktuellen Version der Bibliothek sind unten zusammen mit den Dateien der Test-EAs angehängt, die Sie testen und herunterladen können.
Stellen Sie Ihre Fragen, Kommentare und Vorschläge in den Kommentaren.

Zurück zum Inhalt

Frühere Artikel dieser Serie:

Teil 1. Konzept, Datenverwaltung.
Teil 2. Erhebung (Collection) historischer Aufträge und Deals.
Teil 3. Erhebung (Collection) von Marktorders und Positionen, Organisieren der Suche
Teil 4. Handelsereignisse. Konzept
Teil 5. Klassen und Kollektionen von Handelsereignissen. Senden von Ereignissen an das Programm
Teil 6. Ereignisse auf Netting-Konten
Teil 7. Ereignis der Aktivierung einer StopLimit-Order, Vorbereiten der Funktionsweise bei Änderungen von Orders und Positionen
Teil 8. Ereignisse von Änderungen von Orders und Positionen
Teil 9. Kompatibilität mit MQL4 - Datenvorbereitung
Teil 10. Kompatibilität mit MQL4 - Ereignisse der Positionseröffnung und Aktivierung von Pending-Orders
Teil 11. Kompatibilität mit MQL4 - Ereignisse des Schließens von Positionen
Teil 12. Objektklasse "Account" und die Kollektion von Konto-Objekten
Teil 13. Das Objekt der Kontoereignisse
Teil 14. Das Symbolobjekt
Teil 15. Die Kollektion der Symbolobjekte


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

Beigefügte Dateien |
MQL4.zip (224.58 KB)
MQL5.zip (224.58 KB)
Das MQL5-Kochbuch: Stresstests von Handelsstrategien unter Verwendung nutzerdefinierter Symbole Das MQL5-Kochbuch: Stresstests von Handelsstrategien unter Verwendung nutzerdefinierter Symbole

Der Artikel betrachtet einen Ansatz für einen Stresstest einer Handelsstrategie unter Verwendung nutzerdefinierter Symbole. Zu diesem Zweck wird eine eigene Symbolklasse angelegt. Diese Klasse wird verwendet, um Tickdaten von Drittanbietern zu empfangen und die Symboleigenschaften zu ändern. Basierend auf den Ergebnissen der Arbeit werden wir mehrere Optionen für sich ändernde Handelsbedingungen in Betracht ziehen, unter denen eine Handelsstrategie getestet wird.

Parsen von HTML mit curl Parsen von HTML mit curl

Der Artikel enthält die Beschreibung einer einfachen HTML-Code Parsing-Bibliothek mit Komponenten von Drittanbietern. Insbesondere werden die Möglichkeiten des Zugriffs auf Daten behandelt, die nicht über GET- und POST-Anfragen abgerufen werden können. Wir werden eine nicht zu umfangreiche Webseite auswählen und versuchen, interessante Daten von dieser Webseite zu laden.

Entwicklung eines plattformübergreifenden Grid-EAs (Letzter Teil): Diversifikation als Mittel zur Steigerung der Profitabilität Entwicklung eines plattformübergreifenden Grid-EAs (Letzter Teil): Diversifikation als Mittel zur Steigerung der Profitabilität

In früheren Artikeln dieser Serie haben wir verschiedene Methoden ausprobiert, um einen mehr oder weniger profitablen Grid-Expertenberater zu erstellen. Jetzt werden wir versuchen, die EA-Profitabilität durch Diversifikation zu steigern. Unser oberstes Ziel ist es, einen Jahresgewinn von 100% zu erreichen, wobei der maximale Drawdown des Saldos nicht mehr als 20% beträgt.

Strategieentwickler auf Basis der Merill-Muster Strategieentwickler auf Basis der Merill-Muster

Im vorherigen Artikel haben wir die Anwendung der Merill-Muster auf verschiedene Daten erwogen, wie z.B. auf einen Preiswert auf dem Chart eines Währungssymbols und auf Werte von Standard-MetaTrader-5-Indikatoren: ATR, WPR, CCI, RSI, unter anderem. Nun, lassen Sie uns versuchen, einen Strategiebaukasten zu erstellen, der auf Merill-Mustern basiert.