English Русский 中文 Español 日本語 Português
Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil XVII): Interaktivität von Bibliotheksobjekten

Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil XVII): Interaktivität von Bibliotheksobjekten

MetaTrader 5Beispiele | 18 November 2019, 07:20
500 0
Artyom Trishkin
Artyom Trishkin

Inhalt


Im vorherigen Artikel haben wir das Basisobjekt aller Bibliotheksobjekte erstellt. Nun erhält jedes Objekt, das von der Basis geerbt wird, die Ereignisfunktionalität, die es uns ermöglicht, Ereignisse, die in den Eigenschaften der abgeleiteten Klasse des Basisobjekts auftreten, einfach zu verfolgen.
Heute gehen wir ein wenig weiter und statten das Objekt (und damit alle anderen Bibliotheksobjekte) mit der Möglichkeit aus, einzustellen, welche Eigenschaften in Bezug auf ihre Änderungen, Änderungsgröße und Wertebene der Objekteigenschaften extern gesteuert werden sollen. Somit erhalten alle Bibliotheksobjekte die Funktionen, die es den Benutzern ermöglicht, mit Bibliotheksobjekten zu interagieren.
Nehmen wir zum Beispiel an, dass wir einen Spread und ein Preisniveau überprüfen wollen, um eine Position zu eröffnen. Wir können die kontrollierte Spreadgröße einfach einstellen, den Preis bis zum vorgegebenen Niveau verfolgen und eine Position eröffnen. Alles, was wir tun müssen, ist, die Spreadgröße, unterhalb derer der Handel möglich ist, und ein Preisniveau programmgesteuert einzustellen, bei dessen Erreichen ein Ereignis von einem Symbolobjekt an das Programm gesendet wird, das den Handel nach Spread und Preisniveau ermöglicht.

Eine weitere wichtige Sache ist, dass wir uns von der Notwendigkeit befreien, Ereignisflags zu verwenden (was die Verfolgung von Ereignissen einschränkt und das Speichern der Liste von Enumerationen aller möglichen Ereignistypen für jedes Objekt erfordert). Nun entspricht die Anzahl der möglichen Ereignisse der Anzahl der Objekteigenschaften — Integer und Real. Die Eigenschaften, die nicht verfolgt werden sollen, werden mit dem Wert LONG_MAX initialisiert und nehmen nicht an der Suche nach Objektereignissen teil.

Da Bibliotheksobjekte in ihren Kollektionen gespeichert sind, erfolgt die Aktualisierung der Objekteigenschaften im Timer der Bibliothek mit den Methoden Refresh() für die Kollektion mit dem Aufruf der Refresh()-Methoden der Objekte, die in der Kollektionsliste gespeichert sind. Wenn wir Änderungen des abgeleiteten Objekts in der Refresh()-Methode des Basisobjekts verfolgen, können wir für jedes der Bibliotheksobjekte ein einfaches Ereignismodell erstellen. Jedes der Objekte sendet die Liste seiner Ereignisse an das Hauptobjekt der Bibliothek CEngine.
So ist das bibliotheksbasierte Programm immer über alle Ereignisse informiert, die in einem Objekt einer Kollektion aufgetreten sind. Außerdem sind wir immer in der Lage, die Größe eines kontrollierten Wertes einer Eigenschaft für jedes Objekt einer Kollektion programmgesteuert einzustellen und zu ändern.
All dies wird durch die einfache Klasse, des Basisobjekts aller Bibliotheksobjekte, erreicht.

Steuerungsmethoden für die Ereignisse des Basisobjekts der Bibliothek

Das Arbeiten mit Ereignissen der Bibliothek Basisobjekte ist wie folgt zu organisieren: Bisher haben wir zur Definition von Ereignissen einer bestimmten Klasse separate Ereignissteuerungsmethoden dafür implementiert, Ereignisflags erstellt und mögliche Objektereignisse aufgezählt. Da nun die Kontrolle über Ereignisse der abgeleiteten Klasse in ihrer einzigen Basisklasse angeordnet werden soll, müssen wir eine universelle Ereignissteuerung implementieren, unabhängig davon, ob es sich um ein Symbolereignis, ein Kontoereignis oder ein Ereignis einer anderen Klasse handelt, das später erstellt wird. Daher ist dies ein geeigneter Ort, um Änderungen in den Zuständen der Objekteigenschaften (ganzzahlig und real) zu steuern. Ihre Liste für jede abgeleitete Klasse ist eindeutig und repräsentiert eine Ereignis-ID. Außerdem müssen wir eine Eigenschaft ändern Richtung — Erhöhung oder Verringerung der Eigentumswerte (nennen wir dies einen Ereignisgrund), sowie die Objekteigenschaft ändern Wert. Ereignis-ID, Grund und Änderungswert sollen in eine einfache Klasse des Objekt-Basisereignisses geschrieben und in der Liste der gleichzeitig aufgetretenen Ereignisse gespeichert werden.
Wir haben bereits vereinbart, dass ein Ereignis mit streng spezifizierten Parametern (Event-ID, 'long', 'double' und 'string' Werte) verwendet wird, um Ereignisse an das Programm zu senden. Im Parameter 'long' haben wir eine Ereigniszeit in Millisekunden gesendet. Jetzt müssen wir das Ereignis durch einige seiner Parameter aufgrund von Änderungen in der Definition von Ereignissen genau definieren:

  1. Ereignis-ID — geänderte Eigenschaft eines Objekts. Jedes Objekt verfügt über seine einzigartigen Eigenschaften. Das Programm weiß nichts über ein Objekt, in dem die Eigenschaft geändert wurde, sowie über den Status der geänderten Eigenschaft (ob integer oder real), daher ist es unmöglich, sie durch eine Ereignis-ID genau zu definieren.
  2. Ereignisgrund — Erhöhen oder Verringern eines Eigenschaftswertes oder Überschreiten eines kontrollierten Niveaus. Dieser Wert erlaubt es uns auch nicht, ein Ereignis genau zu bestimmen. Aber die Ereignis-ID und der Grund erlauben es uns zu definieren, dass eine bestimmte Objekteigenschaft erhöht oder verringert wurde oder einen bestimmten Kontrollwert überschritten hat. Daher müssen wir die ID der Klasse angeben, in deren Objekt das Ereignis aufgetreten ist, um das Ereignis genau zu identifizieren.
    Die Kollektionsliste ist dafür ideal geeignet, da sie die Klasse, zu der das Objekt gehört — Symbol, Konto oder ein anderes in der Zukunft zu erstellendes Kollektionsobjekt — genau definiert. Daher sollten zusätzlich die folgenden Daten an das Ereignis gesendet werden:
  3. Kollektions-ID — so dass wir mit drei oben genannten IDs das Ereignis genau definieren können.
  4. String-Eigenschaft des Ereignisses — Name eines Objekts, in dem das Ereignis aufgetreten ist.

Um ein Ereignis zu definieren, müssen wir also drei ganzzahlige Parameter erhalten und den Ereignisnamen erhalten, der auch vom 'long'-Wert übergeben wird. Wir haben nur eine 'long'-Eigenschaft. Was können wir tun? Die Lösung ist einfach: Wir werden drei ganzzahlige Ereignisse vom Typ 'ushort' in einem einzigen 'long'-Parameter packen. Der Typ 'long' hat acht Bytes, während 'ushort' nur zwei Bytes hat. Der 'long'-Container erlaubt es uns also, drei 'ushort'-Nummern zu speichern, die in den Bytes 0,1, 2,3, 4,5 der 'long'-Nummer geschrieben sind, und wir haben noch zwei weitere Bytes 6 und 7, um bei Bedarf später noch einen weiteren 'ushort'-Wert einzutragen.
Um eine Ereigniszeit zu definieren, müssen wir nur die Zeit Millisekunden in den Bytes 0 und 1 des 'long'-Parameters übergeben.

  • Das Datum und die Uhrzeit des Ereignisses können aus TimeCurrent() entnommen werden, wenn man ein Ereignis erhält, und die Anzahl der Millisekunden, die in den Bytes 0 und 1 des Wertes 'long' des Ereignisses übergeben werden, hinzufügen.
  • Der Ereignisgrund wird in den Bytes 2 und 3 des Parameters 'long' des Ereignisses gesetzt, während
  • die Klassen-ID wird in den Bytes 4 und 5 des 'long'-Ereignisses des Parameters gesetzt.

Wenn wir also ein Ereignis empfangen, rufen wir drei 'ushort'-Werte aus dem 'long'-Parameter ab, um eine Ereigniszeit zu definieren und zusätzliche Daten für die genaue Ereignisidentifikation durch die Ereignis-ID zu erhalten, die als 'ushort'-Parameter custom_event_id an EventChartCustom() übergeben wird, sowie eine korrekte ID des aufgetretenen Ereignisses unter Verwendung der Ereignis-ID und zweier Werte, die zusätzlich von lparam abgerufen werden.

Überprüfen Sie im übergeordneten Objekt-Timer den aktuellen Zustand jeder der Objekteigenschaften und vergleichen Sie ihn mit dem vorherigen Zustand, um Ereignisse in den nachfolgenden Objekteigenschaften zu definieren. Überprüfen Sie zunächst, ob der zu vergleichende Wert mit der Eigenschaftsänderung eingestellt ist. Wenn der geprüfte Wert nicht gesetzt ist (LONG_MAX ist dafür gesetzt), wird diese Eigenschaft ignoriert.

Da wir die Listen der Objekteigenschaften von 'long' und 'double' Typen überprüfen, ist es sinnvoller, zweidimensionale Arrays anstelle der Struktur zu verwenden, um den aktuellen und vorherigen Zustand der Objekteigenschaften zu speichern. Die erste Dimension des Arrays ist das Speichern von Objekt-Eigenschaftsindizes, während die zweite die Speicherung der Werte der Eigenschaft ist, deren Index in der ersten Dimension gesetzt wurde, des Eigenschaftsänderungswerts sowie der Kontrollwerte und Flags der Eigenschaftsereignisse.

Lassen Sie mich erklären, warum es bequemer ist, Arrays als Strukturen zu verwenden:
Wir wissen nicht im Voraus, welche Art von Eigenschaft wir prüfen werden. Seinen Typ sehen wir jedoch im Eigenschafts-Index ('double' Objekteigenschaften stehen immer hinter 'long'). Das bedeutet, dass wir keine Felder in der Struktur für 'long'- und 'double'-Werte desselben Objekt-Eigenschaftswerts duplizieren müssen. Wir schreiben einfach die notwendigen Daten zur Steuerung der Zustände der Objekteigenschaften mit ihren korrekten Typen in das Array des notwendigen Typs (entsprechend dem aus dem Eigenschaftenindex definierten Eigenschaftstyp). Es ist also nicht erforderlich, das Strukturfeld auszuwählen, in das der übergebene Wert gesetzt werden soll ('long' oder 'double').
Sobald eine Änderung einer der Objekteigenschaften definiert ist, fügen Sie diese der Liste der Basisobjektereignisse hinzu (da die Suche im Basisobjekt durchgeführt wird, ist das Ereignis grundlegend, es sollte nicht mit dem Ereignis der Nachkommenklasse verwechselt werden, das durch die Liste der Basisereignisse definiert und aus Basisereignissen erstellt werden soll, deren Zeiger in der Liste gespeichert sind).

Die Listen der Eigenschaftsänderungen (Basisereignislisten) werden im Timer in den Refresh()-Methoden der abgeleiteten Klasse jedes Basisobjekts überprüft. Wenn die Objektlisten diese Ereignisse enthalten, wird jedes Ereignis in das Bibliotheksereignis umgewandelt und an das Steuerungsprogramm gesendet.

Um das Bild vollständig zu machen, müssen wir die Methoden erstellen, die es uns ermöglichen, programmgesteuert kontrollierte Änderungswerte für jede Eigenschaft eines beliebigen Bibliotheksobjekts basierend auf dem Basisobjekt festzulegen. So können wir die wesentlichen Bedingungen für die Erzeugung von Ereignissen aus den notwendigen Objekten jederzeit schnell ändern.

Die Menge aller hier getroffenen Maßnahmen zur Verbesserung des Basisobjekts der Bibliothek erlaubt es uns, nicht darüber nachzudenken, eine Ereignissteuerung für alle nachfolgend erstellten Objekte zu erstellen. Stattdessen verwenden wir die vorgefertigte Funktionalität.

Beginnen wir.

Da wir mit Ereignissen im Basisobjekt aller Bibliotheksobjekte arbeiten sollen, müssen wir die Ereignisgrund-Aufzählung erstellen, um Ereignisse zu identifizieren.
In der \MQL5\Include\DoEasy\ Defines.mqh Datei, nach einiger Zeit Optionen, hinzufügen der Aufzählung der möglichen Gründe für das Basisobjekt-Ereignis:

//+------------------------------------------------------------------+
//| Possible options of selecting by time                            |
//+------------------------------------------------------------------+
enum ENUM_SELECT_BY_TIME
  {
   SELECT_BY_TIME_OPEN,                                     // By open time (in milliseconds)
   SELECT_BY_TIME_CLOSE,                                    // By close time (in milliseconds)
  };
//+------------------------------------------------------------------+
//| Possible event reasons of the object library base object         |
//+------------------------------------------------------------------+
enum ENUM_BASE_EVENT_REASON
  {
   BASE_EVENT_REASON_INC,                                   // Increase in the object property value
   BASE_EVENT_REASON_DEC,                                   // Decrease in the object property value
   BASE_EVENT_REASON_MORE_THEN,                             // Object property value exceeds the control value
   BASE_EVENT_REASON_LESS_THEN,                             // Object property value is less than the control value
   BASE_EVENT_REASON_EQUALS                                 // Object property value is equal to the control value
  };
//+------------------------------------------------------------------+


Da wir keine Ereignisflags mehr benötigen, ersetzen Sie die Liste der Symbol-Ereignis-Flags durch die Liste der möglichen Symbol-Ereignisse im Fenster der Marktübersicht:

//+------------------------------------------------------------------+
//| Data for working with symbols                                    |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| List of possible symbol events in the Market Watch window        |
//+------------------------------------------------------------------+
enum ENUM_MW_EVENT
  {
   MARKET_WATCH_EVENT_NO_EVENT = ACCOUNT_EVENTS_NEXT_CODE,  // No event
   MARKET_WATCH_EVENT_SYMBOL_ADD,                           // Adding a symbol to the Market Watch window
   MARKET_WATCH_EVENT_SYMBOL_DEL,                           // Removing a symbol from the Market Watch window
   MARKET_WATCH_EVENT_SYMBOL_SORT,                          // Sorting symbols in the Market Watch window
  };
#define SYMBOL_EVENTS_NEXT_CODE  (MARKET_WATCH_EVENT_SYMBOL_SORT+1)  // The code of the next event after the last symbol event code
//+------------------------------------------------------------------+

Entfernen Sie die Liste der möglichen Symbolereignisse, da sie nicht mehr benötigt wird:

//+------------------------------------------------------------------+
//| 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
//+------------------------------------------------------------------+


Der Code des nächsten Ereignisses wurde durch den Wert ersetzt, der auf die Konstante MARKET_WATCH_EVENT_SYMBOL_SORT aus der Enumeration ENUM_MW_EVENT folgt.

Lassen Sie uns nun die geplante Funktionsweise implementieren.

Fügen Sie in der Basisobjektdatei \MQL5\Include\DoEasy\Objects\BaseObj.mqh die neue Klasse des Basisereignisses hinzu:

//+------------------------------------------------------------------+
//| Library object's base event class                                |
//+------------------------------------------------------------------+
class CBaseEvent : public CObject
  {
private:
   ENUM_BASE_EVENT_REASON  m_reason;  
   int                     m_event_id;
   double                  m_value;   
public:
   ENUM_BASE_EVENT_REASON  Reason(void)   const { return this.m_reason;    }
   int                     ID(void)       const { return this.m_event_id;  }
   double                  Value(void)    const { return this.m_value;     }
//--- Konstructor
                           CBaseEvent(const int event_id,const ENUM_BASE_EVENT_REASON reason,const double value) : m_reason(reason),
                                                                                                                   m_event_id(event_id),
                                                                                                                   m_value(value){}
//--- Comparison method to search for identical event objects
   virtual int             Compare(const CObject *node,const int mode=0) const 
                             {   
                              const CBaseEvent *compared=node;
                              return
                                (
                                 this.Reason()>compared.Reason()  ?  1  :
                                 this.Reason()<compared.Reason()  ? -1  :
                                 this.ID()>compared.ID()          ?  1  :
                                 this.ID()<compared.ID()          ? -1  : 0
                                );
                             } 
  };
//+------------------------------------------------------------------+


Der Abschnitt der 'private' Klasse enthält die Variablen zum Speichern von Ereignisgründen, Ereignis-ID (entspricht dem Index der geänderten Objekteigenschaft) und Ereignisänderungswert.
Der 'public' Abschnitt der Klasse enthält die Methoden zur Rückgabe der oben aufgeführten Variablen der Klassenmitglieder.
Die Formalparameter des Klassenkonstruktors erhalten die Eigenschaftswerte. Die übergebenen Werte werden in der Initialisierungsliste sofort den entsprechenden Variablen der Klassenvariablen zugewiesen.
Außerdem bietet die Klasse die Methode des Vergleichs zweier Klassenobjekte für die Suche in der Liste der dynamischen Zeiger auf Objekte, die wir mehr als einmal diskutiert haben.

Da wir die Liste der kontrollierten Objekteigenschaften in zweidimensionalen Arrays speichern sollen, fügen wir die Makroersetzung hinzu, die auf die Größe der zweiten Array-Dimension zeigt. Deklarieren Sie im privaten Teil der Klasse die beiden Variablen, in denen wir die Anzahl der ganzen Zahl und reale Eigenschaften des Objekts speichern sollen, die von der Klasse geerbt werden sollen (da die Basisklasse nichts über die Nummern der Eigenschaften weiß, die ihre Nachkommen haben, und diese Nummern explizit angezeigt werden sollten). Deklarieren Sie die Methode zum Ausfüllen der Eigenschaftsarrays und zum Suchen nach Änderungen in den nachfolgenden Objekteigenschaften.

//+------------------------------------------------------------------+
//| Base object class for all library objects                        |
//+------------------------------------------------------------------+
#define  CONTROLS_TOTAL    (10)
class CBaseObj : public CObject
  {
private:
   int               m_long_prop_total;  
   int               m_double_prop_total;
   //--- Fill in the object property array
   template<typename T> bool  FillPropertySettings(const int index,T &array[][CONTROLS_TOTAL],T &array_prev[][CONTROLS_TOTAL],int &event_id);
protected:


Deklarieren Sie im 'protected' Abschnitt der Klasse die Liste zum Speichern der Zeiger auf Instanzen der Objektbasisereignisse, die Variable zum Speichern der Ereignis-ID, das erste Startflag und die Variable zum Speichern des nachfolgenden Objekttyps.
Wir haben auch vier zweidimensionale Arrays hinzugefügt, um die Eigenschaften zu speichern und ihre Änderungen zu steuern (die aktuellen und vorherigen ganzzahligen und realen Nachkommen-Objekteigenschaften), sowie die Methode, die nur Millisekunden zurückgibt, die in der Ereigniszeit gespeichert sind (zurückgegeben wird bei MQL4, 0, bei MQL5 der durch 1000 geteilte Rest der Division des 'long'-Wert der Zeit).
Da die Basisklasse nichts über die Anzahl der nachkommenden Objekteigenschaften weiß, während die Größe aus den nachkommenden Klassen (wo sie bekannt sind) eingestellt werden sollte, deklarieren Sie die Methoden zum Setzen und Prüfen der Arraygröße:

protected:
   CArrayObj         m_list_events_base;                       // Object base event list
   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
   int               m_event_id;                               // Event ID (equal to the object property value)
   string            m_name;                                   // Object name
   string            m_folder_name;                            // Name of the folder storing CBaseObj descendant objects 
   bool              m_first_start;                            // First launch flag
   int               m_type;                                   // Object type (corresponds to the collection IDs)
//--- Data in the array cells
//--- Data for storing, controlling and returning tracked properties:
//--- [Property index][0] Controlled property increase value
//--- [Property index][1] Controlled property decrease value
//--- [Property index][2] Controlled property value level
//--- [Property index][3] Property value
//--- [Property index][4] Property value change
//--- [Property index][5] Flag of a property change exceeding the increase value
//--- [Property index][6] Flag of a property change exceeding the decrease value
//--- [Property index][7] Flag of a property increase exceeding the control level
//--- [Property index][8] Flag of a property decrease being less than the control level
//--- [Property index][9] Flag of a property value being equal to the control level
   long              m_long_prop_event[][CONTROLS_TOTAL];         // The array for storing object's integer properties values and controlled property change values
   double            m_double_prop_event[][CONTROLS_TOTAL];       // The array for storing object's real properties values and controlled property change values
   long              m_long_prop_event_prev[][CONTROLS_TOTAL];    // The array for storing object's controlled integer properties values during the previous check
   double            m_double_prop_event_prev[][CONTROLS_TOTAL];  // The array for storing object's controlled real properties values during the previous check

//--- Return (1) time in milliseconds, (2) milliseconds from the MqlTick time value
   long              TickTime(void)                            const { return #ifdef __MQL5__ this.m_tick.time_msc #else this.m_tick.time*1000 #endif ;  }
   ushort            MSCfromTime(const long time_msc)          const { return #ifdef __MQL5__ ushort(this.TickTime()%1000) #else 0 #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;

//--- Set the size of the array of controlled (1) integer and (2) real object properties
   bool              SetControlDataArraySizeLong(const int size);    
   bool              SetControlDataArraySizeDouble(const int size);
//--- Check the array size of object properties
   bool              CheckControlDataArraySize(bool check_long=true);

//--- Set the (1) controlled value and (2) object property change value
   template<typename T> void  SetControlledValue(const int property,const T value);
   template<typename T> void  SetControlledChangedValue(const int property,const T value);

//--- Set the value of the pbject property controlled (1) increase, (2) decrease, (3) control level
   template<typename T> void  SetControlledValueINC(const int property,const T value);
   template<typename T> void  SetControlledValueDEC(const int property,const T value);
   template<typename T> void  SetControlledValueLEVEL(const int property,const T value);

//--- Set the flag of a property change exceeding the (1) increase and (2) decrease values
   template<typename T> void  SetControlledFlagINC(const int property,const T value);
   template<typename T> void  SetControlledFlagDEC(const int property,const T value);
//--- Set the flag of a property change (1) exceeding, (2) being less than the control level, (3) being equal to the level
   template<typename T> void  SetControlledFlagMORE(const int property,const T value);
   template<typename T> void  SetControlledFlagLESS(const int property,const T value);
   template<typename T> void  SetControlledFlagEQUAL(const int property,const T value);

//--- Return the set value of the controlled (1) integer and (2) real object properties increase
   long              GetControlledValueLongINC(const int property)         const { return this.m_long_prop_event[property][0];                           }
   double            GetControlledValueDoubleINC(const int property)       const { return this.m_double_prop_event[property-this.m_long_prop_total][0];  }
//--- Return the set value of the controlled (1) integer and (2) real object properties decrease
   long              GetControlledValueLongDEC(const int property)         const { return this.m_long_prop_event[property][1];                           }
   double            GetControlledValueDoubleDEC(const int property)       const { return this.m_double_prop_event[property-this.m_long_prop_total][1];  }
//--- Return the control level of object's (1) integer and (2) real properties
   long              GetControlledValueLongLEVEL(const int property)       const { return this.m_long_prop_event[property][2];                           }
   double            GetControlledValueDoubleLEVEL(const int property)     const { return this.m_double_prop_event[property-this.m_long_prop_total][2];  }
//--- Return the value of the object (1) integer and (2) real property
   long              GetControlledValueLong(const int property)            const { return this.m_long_prop_event[property][3];                           }
   double            GetControlledValueDouble(const int property)          const { return this.m_double_prop_event[property-this.m_long_prop_total][3];  }
//--- Return the change value of the controlled (1) integer and (2) real object property
   long              GetControlledChangedValueLong(const int property)     const { return this.m_long_prop_event[property][4];                           }
   double            GetControlledChangedValueDouble(const int property)   const { return this.m_double_prop_event[property-this.m_long_prop_total][4];  }

//--- Return the flag of an (1) integer and (2) real property value change exceeding the increase value
   long              GetControlledFlagLongINC(const int property)          const { return this.m_long_prop_event[property][5];                           }
   double            GetControlledFlagDoubleINC(const int property)        const { return this.m_double_prop_event[property-this.m_long_prop_total][5];  }
//--- Return the flag of an (1) integer and (2) real property value change exceeding the decrease value
   long              GetControlledFlagLongDEC(const int property)          const { return this.m_long_prop_event[property][6];                           }
   double            GetControlledFlagDoubleDEC(const int property)        const { return this.m_double_prop_event[property-this.m_long_prop_total][6];  }
//--- Return the flag of an (1) integer and (2) real property value increase exceeding the control level
   long              GetControlledFlagLongMORE(const int property)         const { return this.m_long_prop_event[property][7];                           }
   double            GetControlledFlagDoubleMORE(const int property)       const { return this.m_double_prop_event[property-this.m_long_prop_total][7];  }
//--- Return the flag of an (1) integer and (2) real property value decrease being less than the control level
   long              GetControlledFlagLongLESS(const int property)         const { return this.m_long_prop_event[property][8];                           }
   double            GetControlledFlagDoubleLESS(const int property)       const { return this.m_double_prop_event[property-this.m_long_prop_total][8];  }
//--- Return the flag of an (1) integer and (2) real property being equal to the control level
   long              GetControlledFlagLongEQUAL(const int property)        const { return this.m_long_prop_event[property][9];                           }
   double            GetControlledFlagDoubleEQUAL(const int property)      const { return this.m_double_prop_event[property-this.m_long_prop_total][9];  }
   
//--- (1) Pack a 'ushort' number to a passed 'long' number
//--- (2) convert a 'ushort' value to a specified 'long' number byte
   long              UshortToLong(const ushort ushort_value,const uchar index,long &long_value);
   long              UshortToByte(const ushort value,const uchar index) const;
public:


Die Methoden für das Setzen und die Rückgabe der kontrollierten Eigenschaften und deren Werten, und die Methoden zum Packen einer 'ushort'-Nummer in spezifizierte 'long'-Containerbytes durch einen Index werden auch im privaten Abschnitt der Klasse deklariert. (Index 0 => bytes 0-1, Index 1 => bytes 2-3, Index 2 => bytes 4-5)

Im 'public' Teil der Klasse deklarieren Sie die Methoden zum Zurücksetzen der Werte von geänderten Eigenschaften und die Werte von kontrollierten Objekteigenschaften, die Methode zum Hinzufügen eines Basisereignisses zur Liste, das Verfahren zum Empfangen des Basisobjekts von der Liste durch einen Index, das Verfahren zum Rückgeben der Anzahl der Basisobjekte in der Liste, das virtuelle Verfahren zum Rückgeben eines Objekttyps und das Verfahren zum Rückgeben einer Zeichenkettenbeschreibung eines Basisereignisses:

public:
//--- Reset the variables of (1) tracked and (2) controlled object data (can be reset in the descendants)
   void              ResetChangesParams(void); 
   virtual void      ResetControlsParams(void);
//--- Add the (1) object event and (2) the object event reason to the list
   bool              EventAdd(const ushort event_id,const long lparam,const double dparam,const string sparam);
   bool              EventBaseAdd(const int event_id,const ENUM_BASE_EVENT_REASON reason,const double value);
//--- 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 (1) an event object and (2) a base event by its number in the list
   CEventBaseObj    *GetEvent(const int shift=WRONG_VALUE,const bool check_out=true);
   CBaseEvent       *GetEventBase(const int index);
//--- Return the number of (1) 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 to search for changes (Calling from the descendants: CBaseObj::Refresh())
   virtual void      Refresh(void);
//--- Return an object type
   virtual int       Type(void)                                const { return this.m_type;                     }
//--- Return an object event description
   string            EventDescription(const int property,
                                      const ENUM_BASE_EVENT_REASON reason,
                                      const int source,
                                      const string value,
                                      const string property_descr,
                                      const int digits);
//--- Konstructor
                     CBaseObj();
  };
//+------------------------------------------------------------------+


Lassen Sie uns nun kurz alle oben deklarierten Methoden durchgehen.

Der Klassenkonstruktor:

//+------------------------------------------------------------------+
//| Konstruktor                                                      |
//+------------------------------------------------------------------+
CBaseObj::CBaseObj() : m_global_error(ERR_SUCCESS),
                       m_hash_sum(0),m_hash_sum_prev(0),
                       m_is_event(false),m_event_code(WRONG_VALUE),
                       m_chart_id(::ChartID()),
                       m_folder_name(DIRECTORY),
                       m_name(__FUNCTION__),
                       m_long_prop_total(0),
                       m_double_prop_total(0),
                       m_first_start(true)
  {
   ::ArrayResize(this.m_long_prop_event,0,100);       
   ::ArrayResize(this.m_double_prop_event,0,100);     
   ::ArrayResize(this.m_long_prop_event_prev,0,100);  
   ::ArrayResize(this.m_double_prop_event_prev,0,100);
   ::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();
   this.m_list_events_base.Clear();
   this.m_list_events_base.Sort();
  }
//+------------------------------------------------------------------+


Da wir keine Ereigniscodes mehr haben, die wir zuvor aus Flags gesammelt haben, bei denen der Wert Null das Fehlen eines Ereignisses anzeigt, müssen wir die Ereigniscode-Initialisierung durch eine Initialisierung ungleich Null in der Klasseninitialisierungsliste ersetzen (da Null für die allererste Eigenschaft in der Aufzählung der ganzzahligen Eigenschaften des Objekts steht, während positive Werte die nächsten Ereignisse in der Liste der Objekteigenschaften anzeigen, aber wir können ihre Anzahl nicht in der übergeordneten Klasse definieren). Setzen wird den Ereigniscode auf -1.
Der Objektname wird durch einen Klassennamen initialisiert (der Name wird in den Nachkommen neu vergeben). Initialisieren Sie die Anzahl der ganzzahligen und reale Eigenschaften des abgeleiteten Objekts mit Null und setzen Sie das Flag des ersten Starts.
Setzen Sie im Klassenkörper die Größe von Arrays mit ganzzahligen und realen Eigenschaften auf den Wert Null, löschen Sie die Liste der Basisereignisse und setzen Sie das Sortierlisten-Flag.

Bisher wurde die virtuelle Methode Refresh() der Klasse einfach deklariert, und ihre Implementierung sollte von den abgeleiteten Klassen durchgeführt werden. Lassen Sie uns nun die Methode für die Basisobjektklasse erstellen und implementieren, um Änderungen der abgeleiteten Objekteigenschaften zu verfolgen. Wenn ein Ereignis definiert ist, werden die Basisereignisse erstellt und der Liste der Basisereignisse hinzugefügt, um sie anschließend zu behandeln und Objektereignisse zu erzeugen, die an das Programm gesendet werden sollen:

//+------------------------------------------------------------------+
//| Update the object data to search changes in them                 |
//| Call from descendants: CBaseObj::Refresh()                       |
//+------------------------------------------------------------------+
void CBaseObj::Refresh(void)
  {
//--- Check the size of the arrays, Exit if it is zero
   if(!this.CheckControlDataArraySize() || !this.CheckControlDataArraySize(false))
      return;
//--- Reset the event flag and clear all lists
   this.m_is_event=false;
   this.m_list_events.Clear();
   this.m_list_events.Sort();
   this.m_list_events_base.Clear();
   this.m_list_events_base.Sort();
//--- Fill in the array of integer properties and control their changes
   for(int i=0;i<this.m_long_prop_total;i++)
      if(!this.FillPropertySettings(i,this.m_long_prop_event,this.m_long_prop_event_prev,this.m_event_id))
         continue;
//--- Fill in the array of real properties and control their changes
   for(int i=0;i<this.m_double_prop_total;i++)
      if(!this.FillPropertySettings(i,this.m_double_prop_event,this.m_double_prop_event_prev,this.m_event_id))
         continue;
//--- Erster Start
   if(this.m_first_start)
     {
      ::ArrayCopy(this.m_long_prop_event_prev,this.m_long_prop_event);
      ::ArrayCopy(this.m_double_prop_event_prev,this.m_double_prop_event);
      this.m_hash_sum_prev=this.m_hash_sum;
      this.m_first_start=false;
      this.m_is_event=false;
      this.m_list_events_base.Clear();
      this.m_list_events_base.Sort();
      return;
     }
  }
//+------------------------------------------------------------------+


Hier werden alle Aktionen in den Codekommentaren beschrieben, einschließlich derjenigen, die in der Methode ausgeführt werden, wie das vorläufige Löschen von Ereignislisten und der Aufruf der Methoden zum Ausfüllen der Arrays von ganzzahligen und realen Eigenschaften der abgeleiteten Objekte und die Überprüfung ihrer Änderungen.
Wenn dies der erste Start ist, wird der aktuelle Status der Eigenschaftenarrays in den vorherigen Status kopiert (um zu vermeiden, dass die Differenz zwischen ihnen zur Registrierung von Ereignissen führt), das erste Startflag zurückgesetzt und die Liste der Basisereignisse, die möglicherweise beim Aufruf der Methoden FillPropertySettings() erstellt wurden, wird gelöscht.

Implementierung der Methode zum Ausfüllen der Arrays der nachkommenden Objekteigenschaften und Kontrolle ihrer Änderungen:

//+------------------------------------------------------------------+
//| Fill in the object property array                                |
//+------------------------------------------------------------------+
template<typename T> bool CBaseObj::FillPropertySettings(const int index,T &array[][CONTROLS_TOTAL],T &array_prev[][CONTROLS_TOTAL],int &event_id)
  {
   //--- Data in the array cells
   //--- [Property index][0] Controlled property increase value
   //--- [Property index][1] Controlled property decrease value
   //--- [Property index][2] Controlled property value level
   //--- [Property index][3] Property value
   //--- [Property index][4] Property value change
   //--- [Property index][5] Flag of a property change exceeding the increase value
   //--- [Property index][6] Flag of a property change exceeding the decrease value
   //--- [Property index][7] Flag of a property increase exceeding the control level
   //--- [Property index][8] Flag of a property decrease being less than the control level
   //--- [Property index][9] Flag of a property value being equal to the control level
   
   //--- If controlled values are not set, exit with 'false'
   if(this.m_first_start)
      return false;
   //--- Set the shift of the 'double' property index and the event ID
   event_id=index+(typename(T)=="double" ? this.m_long_prop_total : 0);
   //--- Reset all event flags
   for(int j=5;j<CONTROLS_TOTAL;j++)
      array[index][j]=false;
   //--- Property change value
   T value=array[index][3]-array_prev[index][3];
   array[index][4]=value;
   //--- If the controlled property increase value is set
   if(array[index][0]<LONG_MAX)
     {
      //--- If the property change value exceeds the controlled increase value - there is an event,
      //--- add the event to the list, set the flag and save the new property value size
      if(value>0 && value>array[index][0])
        {
         if(this.EventBaseAdd(event_id,BASE_EVENT_REASON_INC,value))
           {
            array[index][5]=true;
            array_prev[index][4]=value;
           }
        }
     }
   //--- If the controlled property decrease value is set
   if(array[index][1]<LONG_MAX)
     {
      //--- If the property change value exceeds the controlled decrease value - there is an event,
      //--- add the event to the list, set the flag and save the new property value size
      if(value<0 && fabs(value)>array[index][1])
        {
         if(this.EventBaseAdd(event_id,BASE_EVENT_REASON_DEC,value))
           {
            array[index][6]=true;
            array_prev[index][4]=value;
           }
        }
     }
   //--- If the controlled level value is set
   if(array[index][2]<LONG_MAX)
     {
      value=array[index][3]-array[index][2];
      //--- If a property value exceeds the control level, there is an event
      //--- add the event to the list and set the flag
      if(value>0 && array_prev[index][3]<=array[index][2])
        {
         if(this.EventBaseAdd(event_id,BASE_EVENT_REASON_MORE_THEN,array[index][2]))
            array[index][7]=true;
        }
      //--- If a property value is less than the control level, there is an event,
      //--- add the event to the list and set the flag
      else if(value<0 && array_prev[index][3]>=array[index][2])
        {
         if(this.EventBaseAdd(event_id,BASE_EVENT_REASON_LESS_THEN,array[index][2]))
            array[index][8]=true;
        }
      //--- If a property value is equal to the control level, there is an event,
      //--- add the event to the list and set the flag
      else if(value==0 && array_prev[index][3]!=array[index][2])
        {
         if(this.EventBaseAdd(event_id,BASE_EVENT_REASON_EQUALS,array[index][2]))
            array[index][9]=true;
        }
     }
   //--- Save the current property value as a previous one
   array_prev[index][3]=array[index][3];
   return true;
  }
//+------------------------------------------------------------------+


Hier werden alle Aktionen in den Codekommentaren beschrieben. Das Einzige, was ich klarstellen möchte, ist das Bestimmen des Index der 'double'-Eigenschaft eines Objekts für die Positionierung einer Ereignis-ID. Da sich die reellen Eigenschaften aller Objekte hinter den ganzzahligen Eigenschaften befinden, ist der Anfang der ersten reellen Eigenschaft gleich der Anzahl der ganzzahligen Eigenschaften (wenn die Anzahl der 'long'-Eigenschaften gleich drei ist, hat die erste reale Eigenschaft den Index 3 (0,1,2,  3)). Bei Arrays beginnt die Zählung bei Null. Daher müssen wir bei der Arbeit mit 'double'-Eigenschaften die Anzahl der Integer-Eigenschaften des Objektes zu dem Array-Index hinzufügen.

Die Verfahren zum Festlegen einer Größe von Arrays mit ganzzahligen und realen Eigenschaften des abgeleiteten Objekts:

//+------------------------------------------------------------------+
//| Set the size of the arrays of the object integer properties      |
//+------------------------------------------------------------------+
bool CBaseObj::SetControlDataArraySizeLong(const int size)
  {
   int x=(#ifdef __MQL4__ CONTROLS_TOTAL #else 1 #endif );
   this.m_long_prop_total=::ArrayResize(this.m_long_prop_event,size,100)/x;
   return((::ArrayResize(this.m_long_prop_event_prev,size,100)/x)==size && this.m_long_prop_total==size ? true : false);
  }
//+------------------------------------------------------------------+
//| Set the size of the arrays of the object real properties         |
//+------------------------------------------------------------------+
bool CBaseObj::SetControlDataArraySizeDouble(const int size)
  {
   int x=(#ifdef __MQL4__ CONTROLS_TOTAL #else 1 #endif );
   this.m_double_prop_total=::ArrayResize(this.m_double_prop_event,size,100)/x;
   return((::ArrayResize(this.m_double_prop_event_prev,size,100)/x)==size && this.m_double_prop_total==size ? true : false);
  }
//+------------------------------------------------------------------+


Die Methoden geben das Ergebnis der Größenänderung von Arrays um den an die Methode übergebenen Wert zurück.

Ich sollte eine Funktion zum Ändern einer multidimensionalen Arraygröße in MQL4 hervorheben. Die Funktion ArrayResize() in MQL4 liefert die Gesamtgröße aller Array-Dimensionen. In MQL5 gibt es die Größe der ersten Dimension zurück, die geändert werden kann. Wenn beispielsweise die Größe der zweiten Dimension zwei ist, gibt die Funktion 20 zurück, wenn die erste Dimension ihre Größe auf 10 ändert, was nicht logisch ist (da wir nur die Größe der ersten Dimension ändern). In MQL5 gibt die Funktion den korrekten Wert zurück. Für das obige Beispiel gibt es wie erwartet 10 zurück.

Aus diesem Grund wurde in den Methoden ein Divisor erstellt, der in MQL4 den von der Funktion zurückgegebene Wert durch die Größe der zweiten Dimension teilt.

Das Verfahren zum Überprüfen der Größe des Arrays der ganzzahligen und realen abgeleiteten Objekteigenschaften:

//+------------------------------------------------------------------+
//| Check the array size of object properties                        |
//+------------------------------------------------------------------+
bool CBaseObj::CheckControlDataArraySize(bool check_long=true)
  {
   string txt1="";
   string txt2="";
   string txt3="";
   string txt4="";
   bool res=true;
   if(check_long)
     {
      if(this.m_long_prop_total==0)
        {
         txt1=TextByLanguage("Массив данных контролируемых integer-свойств имеет нулевой размер","Controlled integer properties data array has zero size");
         txt2=TextByLanguage("Необходимо сначала установить размер массива равным количеству integer-свойств объекта","You should first set size of array equal to number of object integer properties");
         txt3=TextByLanguage("Для этого используйте метод CBaseObj::SetControlDataArraySizeLong()","To do this, use CBaseObj::SetControlDataArraySizeLong() method");
         txt4=TextByLanguage("со значением количества integer-свойств объекта в параметре \"size\"","with value of number of integer properties of object in \"size\" parameter");
         res=false;
        }
     }
   else
     {
      if(this.m_double_prop_total==0)
        {
         txt1=TextByLanguage("Массив данных контролируемых double-свойств имеет нулевой размер","Controlled double properties data array has zero size");
         txt2=TextByLanguage("Необходимо сначала установить размер массива равным количеству double-свойств объекта","You should first set size of array equal to number of object double properties");
         txt3=TextByLanguage("Для этого используйте метод CBaseObj::SetControlDataArraySizeDouble()","To do this, use CBaseObj::SetControlDataArraySizeDouble() method");
         txt4=TextByLanguage("со значением количества double-свойств объекта в параметре \"size\"","with value of number of double properties of object in \"size\" parameter");
         res=false;
        }
     }
   if(res)
      return true;
   #ifdef __MQL5__ 
      ::Print(DFUN,"\n",txt1,"\n",txt2,"\n",txt3,"\n",txt4);
   #else 
      ::Print(DFUN);
      ::Print(txt1);
      ::Print(txt2);
      ::Print(txt3);
      ::Print(txt4);
   #endif 
   this.m_global_error=ERR_ZEROSIZE_ARRAY;
   return false;
  }
//+------------------------------------------------------------------+


Das Verfahren empfängt das Flag, das die Größe des überprüften Arrays anzeigt.
Ist es true, wird das Array der 'long'-Eigenschaften überprüft. Ist es false, wird stattdessen das Array der 'double' Eigenschaften überprüft.

Wenn eine Größe des markierten Arrays nicht gesetzt ist, wird der Nachrichtentext generiert, die Nachricht wird im Journal angezeigt und false wird zurückgegeben. Wenn die Arraygröße bereits eingestellt wurde, wird true zurückgegeben.

Die Methoden des Rücksetzens von kontrollierten Werten und Änderungswerte von verfolgten Daten von Objekteigenschaften:

//+------------------------------------------------------------------+
//| Reset the variables of controlled object data values             |
//+------------------------------------------------------------------+
void CBaseObj::ResetControlsParams(void)
  {
   if(!this.CheckControlDataArraySize(true) || !this.CheckControlDataArraySize(false))
      return;
//--- Data in the array cells
//--- [Property index][0] Controlled property increase value
//--- [Property index][1] Controlled property decrease value
//--- [Property index][2] Controlled property value level
   for(int i=this.m_long_prop_total-1;i>WRONG_VALUE;i--)
      for(int j=0; j<3; j++)
         this.m_long_prop_event[i][j]=LONG_MAX;
   for(int i=this.m_double_prop_total-1;i>WRONG_VALUE;i--)
      for(int j=0; j<3; j++)
         this.m_double_prop_event[i][j]=(double)LONG_MAX;
  }
//+------------------------------------------------------------------+
//| Reset the variables of tracked object data                       |
//+------------------------------------------------------------------+
void CBaseObj::ResetChangesParams(void)
  {
   if(!this.CheckControlDataArraySize(true) || !this.CheckControlDataArraySize(false))
      return;
   this.m_list_events.Clear();
   this.m_list_events.Sort();
   this.m_list_events_base.Clear();
   this.m_list_events_base.Sort();
//--- Data in the array cells
//--- [Property index][3] Property value
//--- [Property index][4] Property value change
//--- [Property index][5] Flag of a property change exceeding the increase value
//--- [Property index][6] Flag of a property change exceeding the decrease value
//--- [Property index][7] Flag of a property increase exceeding the control level
//--- [Property index][8] Flag of a property decrease being less than the control level
//--- [Property index][9] Flag of a property value being equal to the controlled value
   for(int i=this.m_long_prop_total-1;i>WRONG_VALUE;i--)
      for(int j=3; j<CONTROLS_TOTAL; j++)
         this.m_long_prop_event[i][j]=(j<5 ? LONG_MAX : 0);
   for(int i=this.m_double_prop_total-1;i>WRONG_VALUE;i--)
      for(int j=3; j<CONTROLS_TOTAL; j++)
         this.m_double_prop_event[i][j]=(j<5 ? (double)LONG_MAX : 0);
  }
//+------------------------------------------------------------------+


Die Initialisierungswerte werden in den notwendigen Zellen der zweiten Dimensionen der Arrays in den Methoden in zwei Schleifen durch Arrays der nachfolgenden Objektganzzahl und der realen Eigenschaften gesetzt. Die initialisierten Zellen werden in den Codekommentaren gesetzt.

Das Verfahren, das das Basisereignis zur Liste der Objekt-Basisereignisse hinzufügt:

//+------------------------------------------------------------------+
//| Add the object base event to the list                            |
//+------------------------------------------------------------------+
bool CBaseObj::EventBaseAdd(const int event_id,const ENUM_BASE_EVENT_REASON reason,const double value)
  {
   CBaseEvent* event=new CBaseEvent(event_id,reason,value);
   if(event==NULL)
      return false;
   this.m_list_events_base.Sort();
   if(this.m_list_events_base.Search(event)>WRONG_VALUE)
     {
      delete event;
      return false;
     }
   return this.m_list_events_base.Add(event);
  }
//+------------------------------------------------------------------+


Das Verfahren empfängt die Ereignis-ID, den Ereignisgrund und den Änderungswert der abgeleiteten Objekteigenschaft.

Als Nächstes wird ein neues Basisereignis erstellt, und wenn das gleiche Ereignis bereits in der Liste der Basisereignisse vorhanden ist, wird es entfernt und, false wird zurückgegeben — das Ereignis wird nicht hinzugefügt. Andernfalls wird das Ergebnis des Hinzufügens eines neuen Ereignisses zur Liste der Basisobjektereignisse zurückgegeben.

Die Methode, die das Basisereignis über seinen Index in der Liste der Basisobjektereignisse zurückgibt:

//+------------------------------------------------------------------+
//| Return a base event by its index in the list                     |
//+------------------------------------------------------------------+
CBaseEvent *CBaseObj::GetEventBase(const int index)
  {
   int total=this.m_list_events_base.Total();
   if(total==0 || index<0 || index>total-1)
      return NULL;
   CBaseEvent *event=this.m_list_events_base.At(index);
   return(event!=NULL ? event : NULL);
  }
//+------------------------------------------------------------------+


Die Methode empfängt den Index des gewünschten Ereignisses. Wenn die Liste die Größe Null hat oder der Index über die Basisereignisliste hinausgeht, wird NULL zurückgegeben. Andernfalls empfängt das Ereignis von der Liste durch einen Index und gibt den Zeiger auf das erhaltene Objekt zurück.

Wir müssen die Methoden für die Objekt-Basisklasse erstellen, um schnell die notwendigen Eigenschaftsänderungen vorzunehmen. Das Überschreiten der Änderungen führt zur Ereigniserzeugung. Wir benötigen auch die Methoden zum Setzen neuer Werte für nachkommende Objekteigenschaften und zum Zurückgeben von Flags über aufgetretene "kontrollierte" Objektereignisse. Da die Basisklasse nichts über die Eigenschaften ihrer Nachkommen weiß, müssen wir die universellen Methoden erstellen, die es uns ermöglichen, Änderungen an der notwendigen Nachkommenschaft vorzunehmen. Da wir die Anzahl der ganzzahligen und realen Eigenschaften für jede der nachfolgenden Klassen angeben werden, ist es einfach, die Eigenschaft zu definieren, für die wir den Wert festlegen. Wir sollten einfach den geänderten Eigenschaftsindex überprüfen. Wenn der Index kleiner als die Anzahl der ganzzahligen Eigenschaften ist, werden die Änderungen an der Objektganzzahleigenschaft vorgenommen, andernfalls werden die Eigenschaften geändert.

Implementierung der Methoden zum Setzen von abgeleiteten, objektgesteuerten Eigenschaften:

//+------------------------------------------------------------------+
//| Methods of setting controlled parameters                         |
//+------------------------------------------------------------------+
//--- Data for storing, controlling and returning tracked properties:
//--- [Property index][0] Controlled property increase value
//--- [Property index][1] Controlled property decrease value
//--- [Property index][2] Controlled property value level
//--- [Property index][3] Property value
//--- [Property index][4] Property value change
//--- [Property index][5] Flag of a property change exceeding the increase value
//--- [Property index][6] Flag of a property change exceeding the decrease value
//--- [Property index][7] Flag of a property increase exceeding the control level
//--- [Property index][8] Flag of a property decrease being less than the control level
//--- [Property index][9] Flag of a property value being equal to the control level
//+------------------------------------------------------------------+
//| Set the value of the controlled increase of object properties    |
//+------------------------------------------------------------------+
template<typename T> void CBaseObj::SetControlledValueINC(const int property,const T value)
  {
   if(property<this.m_long_prop_total)
      this.m_long_prop_event[property][0]=(long)value;
   else
      this.m_double_prop_event[property-this.m_long_prop_total][0]=(double)value;
  }  
//+------------------------------------------------------------------+
//| Set the value of the controlled decrease of object properties    |
//+------------------------------------------------------------------+
template<typename T> void CBaseObj::SetControlledValueDEC(const int property,const T value)
  {
   if(property<this.m_long_prop_total)
      this.m_long_prop_event[property][1]=(long)value;
   else
      this.m_double_prop_event[property-this.m_long_prop_total][1]=(double)value;
  }  
//+------------------------------------------------------------------+
//| Set the control level of object properties                       |
//+------------------------------------------------------------------+
template<typename T> void CBaseObj::SetControlledValueLEVEL(const int property,const T value)
  {
   if(property<this.m_long_prop_total)
      this.m_long_prop_event[property][2]=(long)value;
   else
      this.m_double_prop_event[property-this.m_long_prop_total][2]=(double)value;
  }  
//+------------------------------------------------------------------+
//| Set the object property value                                    |
//+------------------------------------------------------------------+
template<typename T> void CBaseObj::SetControlledValue(const int property,const T value)
  {
   if(property<this.m_long_prop_total)
      this.m_long_prop_event[property][3]=(long)value;
   else
      this.m_double_prop_event[property-this.m_long_prop_total][3]=(double)value;
  }
//+------------------------------------------------------------------+
//| Set the object property change value			     |
//+------------------------------------------------------------------+
template<typename T> void CBaseObj::SetControlledChangedValue(const int property,const T value)
  {
   if(property<this.m_long_prop_total)
      this.m_long_prop_event[property][4]=(long)value;
   else
      this.m_double_prop_event[property-this.m_long_prop_total][4]=(double)value;
  }
//+------------------------------------------------------------------+
//| Set the flag of the property value change                        |
//| exceeding the increase value                                     |
//+------------------------------------------------------------------+
template<typename T> void CBaseObj::SetControlledFlagINC(const int property,const T value)
  {
   if(property<this.m_long_prop_total)
      this.m_long_prop_event[property][5]=(long)value;
   else
      this.m_double_prop_event[property-this.m_long_prop_total][5]=(double)value;
  }
//+------------------------------------------------------------------+
//| Set the flag of the property value change                        |
//| exceeding the decrease value                                     |
//+------------------------------------------------------------------+
template<typename T> void CBaseObj::SetControlledFlagDEC(const int property,const T value)
  {
   if(property<this.m_long_prop_total)
      this.m_long_prop_event[property][6]=(long)value;
   else
      this.m_double_prop_event[property-this.m_long_prop_total][6]=(double)value;
  }
//+------------------------------------------------------------------+
//| Set the flag of the property value increase                      |
//| exceeding the control level                                      |
//+------------------------------------------------------------------+
template<typename T> void CBaseObj::SetControlledFlagMORE(const int property,const T value)
  {
   if(property<this.m_long_prop_total)
      this.m_long_prop_event[property][7]=(long)value;
   else
      this.m_double_prop_event[property-this.m_long_prop_total][7]=(double)value;
  }
//+------------------------------------------------------------------+
//| Set the flag of the property value decrease                      |
//| being less than the control level                                |
//+------------------------------------------------------------------+
template<typename T> void CBaseObj::SetControlledFlagLESS(const int property,const T value)
  {
   if(property<this.m_long_prop_total)
      this.m_long_prop_event[property][8]=(long)value;
   else
      this.m_double_prop_event[property-this.m_long_prop_total][8]=(double)value;
  }
//+------------------------------------------------------------------+
//| Set the flag of the property value being equal to the            |
//| control level                                                    |
//+------------------------------------------------------------------+
template<typename T> void CBaseObj::SetControlledFlagEQUAL(const int property,const T value)
  {
   if(property<this.m_long_prop_total)
      this.m_long_prop_event[property][9]=(long)value;
   else
      this.m_double_prop_event[property-this.m_long_prop_total][9]=(double)value;
  }
//+------------------------------------------------------------------+


Betrachten Sie die letzte Methode: Eine Eigenschaft wird an die Methode übergeben, in deren Wert der Vorlagenwert T value eingegeben werden muss. Wenn der Eigenschaftsindex kleiner als ist die Anzahl der Integer-Eigenschaften des abgeleiteten Objektes, wird T value zur notwendigen Zelle des Arrays der Objekt-Integer-Eigenschaften hinzugefügt, andernfalls wird der Index berechnet, um den die Eigenschaft in dem Array der realen Eigenschaften gespeichert wird (der 'double'-Index der Eigenschaft übersteigt immer den Index der gleichen Eigenschaft um die Anzahl der ganzzahligen Eigenschaften des Objektes) und den T value zur benötigten Zelle des Arrays der realen Objekteigenschaften hinzufügen. Die benötigten Zellen der zweiten Dimension des Arrays für jede der Methoden werden vor der Methodenliste aufgelistet.

Das Verfahren konvertiert einen 'ushort'-Wert in einen 'long'-Wert, der um die notwendige Anzahl von Bytes verschoben wird, um ihn anschließend in einen 'long'-Container zu packen:

//+------------------------------------------------------------------+
//| Convert a 'ushort' value to a specified 'long' number byte       |
//+------------------------------------------------------------------+
long CBaseObj::UshortToByte(const ushort value,const uchar index) const
  {
   if(index>3)
     {
      ::Print(DFUN,TextByLanguage("Ошибка. Значение \"index\" должно быть в пределах 0 - 3","Error. \"index\" value should be between 0 - 3"));
      return 0;
     }
   return(long)value<<(16*index);
  }
//+------------------------------------------------------------------+


Angenommen, wir haben einen 8-Byte langen Wert, der in Zellen mit jeweils zwei Bytes unterteilt ist (jeder Zelle dieser Art ist ein eindeutiger Index zugeordnet):

Bytes 6-7 (Index 3)
 Bytes 4-5 (Index 2) Bytes 2-3 (Index 1) 
Bytes 0-1 (Index 0) 
ushort 4
ushort 3
ushort 2
ushort 1

Wir können ihm vier 'ushort'-Zahlen zuordnen. Jede weitere Zahl sollte um 16 Bit * Index (1 Byte = 8 Bit) nach links verschoben werden. Anschließend wird der erhaltene Wert zur 'long'-Zahl hinzugefügt. So erhalten wir einige 'ushort'-Werte, die in den 'long'-Container verpackt sind.

Das Verfahren erhält eine 'ushort'-Nummer und den Index, mit dem ein 'ushort'-Wert im 'long'-Container gespeichert werden soll.
Der Index wird überprüft, und wenn er 3
überschreitet, wird die falsche Indexmeldung angezeigt und 0 zurückgegeben.
Wenn der Index korrekt ist, wird eine 'ushort'-Nummer, und zwar um 16 Bits * Index (ein Byte enthält 8 Bit, und wir müssen die 'ushort'-Nummer mit zwei Bytes verschieben) und das Verschiebungsergebnis wird von der Methode zurückgegeben.

Die Methode, die den Wert 'ushort' packt, verschiebt sich um die erforderliche Anzahl von Bytes in einen 'long'-Container:

//+------------------------------------------------------------------+
//| Pack a 'ushort' number to a passed 'long' number                 |
//+------------------------------------------------------------------+
long CBaseObj::UshortToLong(const ushort ushort_value,const uchar index,long &long_value)
  {
   if(index>3)
     {
      ::Print(DFUN,TextByLanguage("Ошибка. Значение \"index\" должно быть в пределах 0 - 3","Error. \"index\" value should be between 0 - 3"));
      return 0;
     }
   return(long_value |= UshortToByte(ushort_value,index));
  }
//+------------------------------------------------------------------+


Die Methode erhält eine 'ushort'-Nummer, die in einen 'long'-Container gepackt werden soll, der über den Link an die Methode übergeben wird, und der Index der Bytes, der 'ushort'-Wert im 'long'-Container sollte auf gesetzt werden.
Wie bei der vorstehend beschriebenen Methode wird der Index geprüft, und wenn die Prüfung erfolgreich ist, wird der 'ushort'-Wert, der mit der UshortToByte()-Methode um die erforderliche Anzahl von Bytes verschoben wurde, zur 'long'-Zahl addiert, indem bitweise 'OR' verwendet wird, und das Ergebnis wird an das aufrufende Programm zurückgegeben.

Die Methode gibt die Zeichenkettenbeschreibung des Ereignisses des nachkommenden Objekts zurück:

//+------------------------------------------------------------------+
//| Return an object event description                               |
//+------------------------------------------------------------------+
string CBaseObj::EventDescription(const int property,
                                  const ENUM_BASE_EVENT_REASON reason,
                                  const int source,
                                  const string value,
                                  const string property_descr,
                                  const int digits)
  {
//--- Depending on the collection ID, create th object type description
   string type=
     (
      this.Type()==COLLECTION_SYMBOLS_ID ? TextByLanguage("символа: ","symbol property: ")   :
      this.Type()==COLLECTION_ACCOUNT_ID ? TextByLanguage("аккаунта: ","account property: ")   :
      ""
     );
//--- Depending on the property type, create the property change value description
   string level=
     (
      property<this.m_long_prop_total ? 
      ::DoubleToString(this.GetControlledValueLongLEVEL(property),digits) : 
      ::DoubleToString(this.GetControlledValueDoubleLEVEL(property),digits)
     );
//--- Depending on the event reason, create the event description text
   string res=
     (
      reason==BASE_EVENT_REASON_INC       ?  TextByLanguage("Значение свойства ","Value of the ")+type+property_descr+TextByLanguage(" увеличено на "," increased by ")+value       :
      reason==BASE_EVENT_REASON_DEC       ?  TextByLanguage("Значение свойства ","Value of the ")+type+property_descr+TextByLanguage(" уменьшено на "," decreased by ")+value       :
      reason==BASE_EVENT_REASON_MORE_THEN ?  TextByLanguage("Значение свойства ","Value of the ")+type+property_descr+TextByLanguage(" стало больше "," became more than ")+level   :
      reason==BASE_EVENT_REASON_LESS_THEN ?  TextByLanguage("Значение свойства ","Value of the ")+type+property_descr+TextByLanguage(" стало меньше "," became less than ")+level   :
      reason==BASE_EVENT_REASON_EQUALS    ?  TextByLanguage("Значение свойства ","Value of the ")+type+property_descr+TextByLanguage(" равно "," is equal to ")+level               :
      TextByLanguage("Неизвестное событие ","Unknown ")+type
     );
//--- Return the object name+created event description text
   return this.m_name+": "+res;
  }
//+------------------------------------------------------------------+


Da die Basisobjektklasse nichts über ihre abgeleiteten Klassen weiß, müssen wir die angeben, bei denen das Ereignis aufgetreten ist, um ein Ereignis in der abgeleiteten Klasse zu beschreiben.
Um dies zu erreichen, erhält das Verfahren

  • eine Eigenschaft des Objekts, dass das Ereignis erkannt wurde, 
  • ein Ereignisgrund — Erhöhen/Verringern eines Eigenschaftswertes um einen bestimmten Wert/Überschreiten eines bestimmten Niveaus durch den Eigenschaftswert,
  • Ereignisquelle — ID der Kollektion, in deren Objekt ein Ereignis aufgetreten ist,
  • der Wert, um den die Objekteigenschaft geändert wurde
  • die Textbeschreibung der Eigenschaft des abgeleiteten Objekts (verfügbar im Nachkommen) und
  • die Anzahl der Dezimalstellen in der numerischen Darstellung der geänderten Eigenschaft (auch im Nachkommen verfügbar).

Alle Schritte zur Erstellung eines abgeleiteten Objekts sind in den Codekommentaren beschrieben. Ich glaube, sie sind umfassend genug.

Wir haben alle notwendigen Änderungen in der Basisobjektklasse vorgenommen (bei der Weiterentwicklung der Bibliothek und dem Anlegen neuer Kollektionen sollen der letzten Methode neue Kollektions-IDs hinzugefügt werden, um eine korrekte Ereignisbeschreibung zu erstellen).

Überarbeitung der Symbolklasse und der Symbolkollektion

An dieser Stelle werden wir die Symbolklasse und die Symbolkollektion unter Berücksichtigung der neuen Ereignisse des Basisobjekts überarbeiten. Lassen Sie uns einige Änderungen an den Klassen Symbol und Symbolkollektion vornehmen.
Öffnen Sie \MQL5\Include\DoEasy\Objects\Symbols\Symbol.mqh und fügen Sie die Änderungen hinzu.

Da nun alle nachkommenden Objektereignisse des Basisobjekts in der übergeordneten Klasse definiert sind, ist es nicht notwendig, die Änderungen der Objekteigenschaften in der nachkommenden Klasse zu steuern. Daher ist die Datenstruktur der verfolgten Objekteigenschaften jetzt überflüssig.
Lassen Sie uns die Struktur und zwei Objekte mit dem Strukturtyp aus der Symbolobjektklasse entfernen:

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


Alle Klassenvariablen zum Speichern von kontrollierten und geänderten Symbolobjekteigenschaften entfernen — jetzt werden alle diese Daten in den Arrays der Basisobjektklasse gespeichert:

   //--- 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 increase 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 increase value
   bool              m_is_change_session_buy_ord_dec;          // Flag of a change in the number of Buy orders being less than the increase value
   //--- Sell orders of the current session
   long              m_control_session_sell_ord_inc;           // Controlled value of the increase 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 increase 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 increase 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 increase value
   bool              m_is_change_volume_dec;                   // Flag of the volume change in the last deal being less than the increase value
   //--- Maximum volume within a day
   long              m_control_volume_high_day_inc;            // Controlled value of the maximum volume increase 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 increase 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 increase 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 increase 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 increase 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 increase 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 increase 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 increase 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 increase 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 increase 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 increase
   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 increase 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 increase 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 increase 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 increase 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 increase 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 increase
   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 increase 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 increase 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 increase 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 increase 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 increase 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 increase 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 increase 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 increase 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 increase 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 increase 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 increase 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 increase
   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 increase 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 increase 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 increase 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 increase 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 increase 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 increase 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 increase 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 increase
   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 increase 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 increase
   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 increase 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 increase
   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 increase 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 increase
   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 increase 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 increase
   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 increase value
   bool              m_is_change_session_aw_dec;               // Flag of the average weighted session price change value exceeding the decrease value


Entfernen Sie die hervorgehobenen Methoden aufgrund ihrer Redundanz:

//--- 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);

//--- Return description of symbol events
   string            EventDescription(const ENUM_SYMBOL_EVENT event);


Anstelle der virtuellen Methode zum Platzieren des Codes zum Ändern einer Symboleigenschaft deklarieren Sie die Methode zum Überprüfen der Änderungen in den Symboleigenschaften und zum Erzeugen eines Ereignisses:

//--- Initialize the variables of controlled symbol data
   virtual void      InitControlsParams(void);
//--- Check the list of symbol property changes and create an event
   void              CheckEvents(void);


Fügen Sie im öffentlichen Abschnitt der Klasse Deklarationen von Methoden hinzu, die verfolgte Werte setzen und kontrollierte Werte von verfolgten Eigenschaften, geänderte Werte von Eigenschaften und Flags zurückgeben:

public:
//--- Set the change value of the controlled symbol property
   template<typename T> void  SetControlChangedValue(const int property,const T value);
//--- Set the value of the controlled symbol property (1) increase, (2) decrease and (3) control level
   template<typename T> void  SetControlPropertyINC(const int property,const T value);
   template<typename T> void  SetControlPropertyDEC(const int property,const T value);
   template<typename T> void  SetControlPropertyLEVEL(const int property,const T value);
//--- Set the flag of a symbol property change exceeding the (1) increase and (2) decrease values
   template<typename T> void  SetControlFlagINC(const int property,const T value);
   template<typename T> void  SetControlFlagDEC(const int property,const T value);
   
//--- Return the set value of the (1) integer and (2) real symbol property controlled increase
   long              GetControlParameterINC(const ENUM_SYMBOL_PROP_INTEGER property)   const { return this.GetControlledValueLongINC(property);             }
   double            GetControlParameterINC(const ENUM_SYMBOL_PROP_DOUBLE property)    const { return this.GetControlledValueDoubleINC(property);           }
//--- Return the set value of the (1) integer and (2) real symbol property controlled decrease
   long              GetControlParameterDEC(const ENUM_SYMBOL_PROP_INTEGER property)   const { return this.GetControlledValueLongDEC(property);             }
   double            GetControlParameterDEC(const ENUM_SYMBOL_PROP_DOUBLE property)    const { return this.GetControlledValueDoubleDEC(property);           }
//--- Return the flag of an (1) integer and (2) real symbol property value change exceeding the increase value
   long              GetControlFlagINC(const ENUM_SYMBOL_PROP_INTEGER property)        const { return this.GetControlledFlagLongINC(property);              }
   double            GetControlFlagINC(const ENUM_SYMBOL_PROP_DOUBLE property)         const { return this.GetControlledFlagDoubleINC(property);            }
//--- Return the flag of an (1) integer and (2) real symbol property value change exceeding the decrease value
   bool              GetControlFlagDEC(const ENUM_SYMBOL_PROP_INTEGER property)        const { return (bool)this.GetControlledFlagLongDEC(property);        }
   bool              GetControlFlagDEC(const ENUM_SYMBOL_PROP_DOUBLE property)         const { return (bool)this.GetControlledFlagDoubleDEC(property);      }
//--- Return the change value of the controlled (1) integer and (2) real object property
   long              GetControlChangedValue(const ENUM_SYMBOL_PROP_INTEGER property)   const { return this.GetControlledChangedValueLong(property);         }
   double            GetControlChangedValue(const ENUM_SYMBOL_PROP_DOUBLE property)    const { return this.GetControlledChangedValueDouble(property);       }
   
//+------------------------------------------------------------------+


Jede Methode wird in Form von zwei überladenen Methoden ausgeführt, die die Methoden des Basisobjekts aufrufen, die dem Typ zum Setzen/Prüfen der Objekteigenschaft des Symbols entsprechen.

Zuvor haben wir bereits die Methoden für einen vereinfachten Zugriff auf einige Symbolobjekteigenschaften entwickelt. Fügen wir die Methoden zum Platzieren der Werte der kontrollierten Ebenen der Eigenschaften hinzu und deklarieren wir die Methoden zum Einstellen/Empfangen von Daten für Bid/Last und zugehörige Parameter (vorher wurde Bid oder Last automatisch ausgewählt, abhängig von den Preisen, auf denen das Diagramm basiert. Nun müssen wir die Methoden für die Arbeit mit diesen Daten erstellen):

//+------------------------------------------------------------------+
//| Get and set the parameters of tracked property 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 and (3) control level of 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) increase, (5) decrease value
   void              SetControlSessionDealsInc(const long value)                 { this.SetControlPropertyINC(SYMBOL_PROP_SESSION_DEALS,(long)::fabs(value));        }
   void              SetControlSessionDealsDec(const long value)                 { this.SetControlPropertyDEC(SYMBOL_PROP_SESSION_DEALS,(long)::fabs(value));        }
   void              SetControlSessionDealsLevel(const long value)               { this.SetControlPropertyLEVEL(SYMBOL_PROP_SESSION_DEALS,(long)::fabs(value));      }
   long              GetValueChangedSessionDeals(void)                     const { return this.GetControlChangedValue(SYMBOL_PROP_SESSION_DEALS);                    }
   bool              IsIncreasedSessionDeals(void)                         const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_SESSION_DEALS);                   }
   bool              IsDecreasedSessionDeals(void)                         const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_SESSION_DEALS);                   }
   //--- Buy orders of the current session
   //--- setting the controlled value of (1) growth, (2) decrease and (3) control level of the current number of Buy orders
   //--- getting (4) the current number of Buy orders change value,
   //--- getting the flag of the current Buy orders' number change exceeding the (5) growth, (6) decrease value
   void              SetControlSessionBuyOrdInc(const long value)                { this.SetControlPropertyINC(SYMBOL_PROP_SESSION_BUY_ORDERS,(long)::fabs(value));   }
   void              SetControlSessionBuyOrdDec(const long value)                { this.SetControlPropertyDEC(SYMBOL_PROP_SESSION_BUY_ORDERS,(long)::fabs(value));   }
   void              SetControlSessionBuyOrdLevel(const long value)              { this.SetControlPropertyLEVEL(SYMBOL_PROP_SESSION_BUY_ORDERS,(long)::fabs(value)); }
   long              GetValueChangedSessionBuyOrders(void)                 const { return this.GetControlChangedValue(SYMBOL_PROP_SESSION_BUY_ORDERS);               }
   bool              IsIncreasedSessionBuyOrders(void)                     const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_SESSION_BUY_ORDERS);              }
   bool              IsDecreasedSessionBuyOrders(void)                     const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_SESSION_BUY_ORDERS);              }
   //--- Sell orders of the current session
   //--- setting the controlled value of (1) growth, (2) decrease and (3) control level of the current number of Sell orders
   //--- getting (4) the current number of Sell orders change value,
   //--- getting the flag of the current Sell orders' number change exceeding the (5) growth, (6) decrease value
   void              SetControlSessionSellOrdInc(const long value)               { this.SetControlPropertyINC(SYMBOL_PROP_SESSION_SELL_ORDERS,(long)::fabs(value));  }
   void              SetControlSessionSellOrdDec(const long value)               { this.SetControlPropertyDEC(SYMBOL_PROP_SESSION_SELL_ORDERS,(long)::fabs(value));  }
   void              SetControlSessionSellOrdLevel(const long value)             { this.SetControlPropertyLEVEL(SYMBOL_PROP_SESSION_SELL_ORDERS,(long)::fabs(value));}
   long              GetValueChangedSessionSellOrders(void)                const { return this.GetControlChangedValue(SYMBOL_PROP_SESSION_SELL_ORDERS);              }
   bool              IsIncreasedSessionSellOrders(void)                    const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_SESSION_SELL_ORDERS);             }
   bool              IsDecreasedSessionSellOrders(void)                    const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_SESSION_SELL_ORDERS);             }
   //--- Volume of the last deal
   //--- setting the last deal volume controlled (1) increase, (2) decrease and (3) control level
   //--- getting (4) volume change values in the last deal,
   //--- getting the flag of the volume change in the last deal exceeding the (5) growth, (6) decrease value
   void              SetControlVolumeInc(const long value)                       { this.SetControlPropertyINC(SYMBOL_PROP_VOLUME,(long)::fabs(value));               }
   void              SetControlVolumeDec(const long value)                       { this.SetControlPropertyDEC(SYMBOL_PROP_VOLUME,(long)::fabs(value));               }
   void              SetControlVolumeLevel(const long value)                     { this.SetControlPropertyLEVEL(SYMBOL_PROP_VOLUME,(long)::fabs(value));             }
   long              GetValueChangedVolume(void)                           const { return this.GetControlChangedValue(SYMBOL_PROP_VOLUME);                           }
   bool              IsIncreasedVolume(void)                               const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_VOLUME);                          }
   bool              IsDecreasedVolume(void)                               const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_VOLUME);                          }
   //--- Maximum volume within a day
   //--- setting the maximum day volume controlled (1) increase, (2) decrease and (3) control level
   //--- getting (4) the maximum volume change value within a day,
   //--- getting the flag of the maximum day volume change exceeding the (5) growth, (6) decrease value
   void              SetControlVolumeHighInc(const long value)                   { this.SetControlPropertyINC(SYMBOL_PROP_VOLUMEHIGH,(long)::fabs(value));           }
   void              SetControlVolumeHighDec(const long value)                   { this.SetControlPropertyDEC(SYMBOL_PROP_VOLUMEHIGH,(long)::fabs(value));           }
   void              SetControlVolumeHighLevel(const long value)                 { this.SetControlPropertyLEVEL(SYMBOL_PROP_VOLUMEHIGH,(long)::fabs(value));         }
   long              GetValueChangedVolumeHigh(void)                       const { return this.GetControlChangedValue(SYMBOL_PROP_VOLUMEHIGH);                       }
   bool              IsIncreasedVolumeHigh(void)                           const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_VOLUMEHIGH);                      }
   bool              IsDecreasedVolumeHigh(void)                           const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_VOLUMEHIGH);                      }
   //--- Minimum volume within a day
   //--- setting the minimum day volume controlled (1) increase, (2) decrease and (3) control level
   //--- getting (4) the minimum volume change value within a day,
   //--- getting the flag of the minimum day volume change exceeding the (5) growth, (6) decrease value
   void              SetControlVolumeLowInc(const long value)                    { this.SetControlPropertyINC(SYMBOL_PROP_VOLUMELOW,(long)::fabs(value));            }
   void              SetControlVolumeLowDec(const long value)                    { this.SetControlPropertyDEC(SYMBOL_PROP_VOLUMELOW,(long)::fabs(value));            }
   void              SetControlVolumeLowLevel(const long value)                  { this.SetControlPropertyLEVEL(SYMBOL_PROP_VOLUMELOW,(long)::fabs(value));          }
   long              GetValueChangedVolumeLow(void)                        const { return this.GetControlChangedValue(SYMBOL_PROP_VOLUMELOW);                        }
   bool              IsIncreasedVolumeLow(void)                            const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_VOLUMELOW);                       }
   bool              IsDecreasedVolumeLow(void)                            const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_VOLUMELOW);                       }
   //--- Spread
   //--- setting the controlled spread (1) increase, (2) decrease value and (3) control level in points
   //--- getting (4) spread change value in points,
   //--- getting the flag of the spread change in points exceeding the (5) growth, (6) decrease value
   void              SetControlSpreadInc(const int value)                        { this.SetControlPropertyINC(SYMBOL_PROP_SPREAD,(long)::fabs(value));               }
   void              SetControlSpreadDec(const int value)                        { this.SetControlPropertyDEC(SYMBOL_PROP_SPREAD,(long)::fabs(value));               }
   void              SetControlSpreadLevel(const int value)                      { this.SetControlPropertyLEVEL(SYMBOL_PROP_SPREAD,(long)::fabs(value));             }
   int               GetValueChangedSpread(void)                           const { return (int)this.GetControlChangedValue(SYMBOL_PROP_SPREAD);                      }
   bool              IsIncreasedSpread(void)                               const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_SPREAD);                          }
   bool              IsDecreasedSpread(void)                               const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_SPREAD);                          }
   //--- StopLevel
   //--- setting the controlled StopLevel (1) increase, (2) decrease value and (3) control level in points
   //--- getting (4) StopLevel change value in points,
   //--- getting the flag of StopLevel change in points exceeding the (5) growth, (6) decrease value
   void              SetControlStopLevelInc(const int value)                     { this.SetControlPropertyINC(SYMBOL_PROP_TRADE_STOPS_LEVEL,(long)::fabs(value));    }
   void              SetControlStopLevelDec(const int value)                     { this.SetControlPropertyDEC(SYMBOL_PROP_TRADE_STOPS_LEVEL,(long)::fabs(value));    }
   void              SetControlStopLevelLevel(const int value)                   { this.SetControlPropertyLEVEL(SYMBOL_PROP_TRADE_STOPS_LEVEL,(long)::fabs(value));  }
   int               GetValueChangedStopLevel(void)                        const { return (int)this.GetControlChangedValue(SYMBOL_PROP_TRADE_STOPS_LEVEL);           }
   bool              IsIncreasedStopLevel(void)                            const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_TRADE_STOPS_LEVEL);               }
   bool              IsDecreasedStopLevel(void)                            const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_TRADE_STOPS_LEVEL);               }
   //--- Freeze distance
   //--- setting the controlled FreezeLevel (1) increase, (2) decrease value and (3) control level in points
   //--- getting (4) FreezeLevel change value in points,
   //--- getting the flag of FreezeLevel change in points exceeding the (5) growth, (6) decrease value
   void              SetControlFreezeLevelInc(const int value)                   { this.SetControlPropertyINC(SYMBOL_PROP_TRADE_FREEZE_LEVEL,(long)::fabs(value));   }
   void              SetControlFreezeLevelDec(const int value)                   { this.SetControlPropertyDEC(SYMBOL_PROP_TRADE_FREEZE_LEVEL,(long)::fabs(value));   }
   void              SetControlFreezeLevelLevel(const int value)                 { this.SetControlPropertyLEVEL(SYMBOL_PROP_TRADE_FREEZE_LEVEL,(long)::fabs(value)); }
   int               GetValueChangedFreezeLevel(void)                      const { return (int)this.GetControlChangedValue(SYMBOL_PROP_TRADE_FREEZE_LEVEL);          }
   bool              IsIncreasedFreezeLevel(void)                          const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_TRADE_FREEZE_LEVEL);              }
   bool              IsDecreasedFreezeLevel(void)                          const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_TRADE_FREEZE_LEVEL);              }
   
   //--- Bid
   //--- setting the controlled Bid price (1) increase, (2) decrease value and (3) control level in points
   //--- getting (4) Bid or Last price change value,
   //--- getting the flag of the Bid or Last price change exceeding the (5) growth, (6) decrease value
   void              SetControlBidInc(const double value)                        { this.SetControlPropertyINC(SYMBOL_PROP_BID,::fabs(value));                        }
   void              SetControlBidDec(const double value)                        { this.SetControlPropertyDEC(SYMBOL_PROP_BID,::fabs(value));                        }
   void              SetControlBidLevel(const double value)                      { this.SetControlPropertyLEVEL(SYMBOL_PROP_BID,::fabs(value));                      }
   double            GetValueChangedBid(void)                              const { return this.GetControlChangedValue(SYMBOL_PROP_BID);                              }
   bool              IsIncreasedBid(void)                                  const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_BID);                             }
   bool              IsDecreasedBid(void)                                  const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_BID);                             }
   //--- The highest Bid price of the day
   //--- setting the controlled maximum Bid price (1) increase, (2) decrease value and (3) control level in points
   //--- getting the (4) maximum Bid or Last price change value,
   //--- getting the flag of the maximum Bid or Last price change exceeding the (5) growth, (6) decrease value
   void              SetControlBidHighInc(const double value)                    { this.SetControlPropertyINC(SYMBOL_PROP_BIDHIGH,::fabs(value));                    }
   void              SetControlBidHighDec(const double value)                    { this.SetControlPropertyDEC(SYMBOL_PROP_BIDHIGH,::fabs(value));                    }
   void              SetControlBidHighLevel(const double value)                  { this.SetControlPropertyLEVEL(SYMBOL_PROP_BIDHIGH,::fabs(value));                  }
   double            GetValueChangedBidHigh(void)                          const { return this.GetControlChangedValue(SYMBOL_PROP_BIDHIGH);                          }
   bool              IsIncreasedBidHigh(void)                              const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_BIDHIGH);                         }
   bool              IsDecreasedBidHigh(void)                              const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_BIDHIGH);                         }
   //--- The lowest Bid price of the day
   //--- setting the controlled minimum Bid price (1) increase, (2) decrease value and (3) control level in points
   //--- getting the (4) minimum Bid or Last price change value,
   //--- getting the flag of the minimum Bid or Last price change exceeding the (5) growth, (6) decrease value
   void              SetControlBidLowInc(const double value)                     { this.SetControlPropertyINC(SYMBOL_PROP_BIDLOW,::fabs(value));                     }
   void              SetControlBidLowDec(const double value)                     { this.SetControlPropertyDEC(SYMBOL_PROP_BIDLOW,::fabs(value));                     }
   void              SetControlBidLowLevel(const double value)                   { this.SetControlPropertyLEVEL(SYMBOL_PROP_BIDLOW,::fabs(value));                   }
   double            GetValueChangedBidLow(void)                           const { return this.GetControlChangedValue(SYMBOL_PROP_BIDLOW);                           }
   bool              IsIncreasedBidLow(void)                               const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_BIDLOW);                          }
   bool              IsDecreasedBidLow(void)                               const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_BIDLOW);                          }
   
   //--- Last
   //--- setting the controlled Last price (1) increase, (2) decrease value and (3) control level in points
   //--- getting (4) Bid or Last price change value,
   //--- getting the flag of the Bid or Last price change exceeding the (5) growth, (6) decrease value
   void              SetControlLastInc(const double value)                       { this.SetControlPropertyINC(SYMBOL_PROP_LAST,::fabs(value));                       }
   void              SetControlLastDec(const double value)                       { this.SetControlPropertyDEC(SYMBOL_PROP_LAST,::fabs(value));                       }
   void              SetControlLastLevel(const double value)                     { this.SetControlPropertyLEVEL(SYMBOL_PROP_LAST,::fabs(value));                     }
   double            GetValueChangedLast(void)                             const { return this.GetControlChangedValue(SYMBOL_PROP_LAST);                             }
   bool              IsIncreasedLast(void)                                 const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_LAST);                            }
   bool              IsDecreasedLast(void)                                 const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_LAST);                            }
   //--- The highest Last price of the day
   //--- setting the controlled maximum Last price (1) increase, (2) decrease value and (3) control level in points
   //--- getting the (4) maximum Bid or Last price change value,
   //--- getting the flag of the maximum Bid or Last price change exceeding the (5) growth, (6) decrease value
   void              SetControlLastHighInc(const double value)                   { this.SetControlPropertyINC(SYMBOL_PROP_LASTHIGH,::fabs(value));                   }
   void              SetControlLastHighDec(const double value)                   { this.SetControlPropertyDEC(SYMBOL_PROP_LASTHIGH,::fabs(value));                   }
   void              SetControlLastHighLevel(const double value)                 { this.SetControlPropertyLEVEL(SYMBOL_PROP_LASTHIGH,::fabs(value));                 }
   double            GetValueChangedLastHigh(void)                         const { return this.GetControlChangedValue(SYMBOL_PROP_LASTHIGH);                         }
   bool              IsIncreasedLastHigh(void)                             const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_LASTHIGH);                        }
   bool              IsDecreasedLastHigh(void)                             const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_LASTHIGH);                        }
   //--- The lowest Last price of the day
   //--- setting the controlled minimum Last price (1) increase, (2) decrease value and (3) control level in points
   //--- getting the (4) minimum Bid or Last price change value,
   //--- getting the flag of the minimum Bid or Last price change exceeding the (5) growth, (6) decrease value
   void              SetControlLastLowInc(const double value)                    { this.SetControlPropertyINC(SYMBOL_PROP_LASTLOW,::fabs(value));                    }
   void              SetControlLastLowDec(const double value)                    { this.SetControlPropertyDEC(SYMBOL_PROP_LASTLOW,::fabs(value));                    }
   void              SetControlLastLowLevel(const double value)                  { this.SetControlPropertyLEVEL(SYMBOL_PROP_LASTLOW,::fabs(value));                  }
   double            GetValueChangedLastLow(void)                          const { return this.GetControlChangedValue(SYMBOL_PROP_LASTLOW);                          }
   bool              IsIncreasedLastLow(void)                              const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_LASTLOW);                         }
   bool              IsDecreasedLastLow(void)                              const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_LASTLOW);                         }
   
   //--- Bid/Last
   //--- setting the controlled Bid or Last price (1) increase, (2) decrease value and (3) control level in points
   //--- getting (4) Bid or Last price change value,
   //--- getting the flag of the Bid or Last price change exceeding the (5) growth, (6) decrease value
   void              SetControlBidLastInc(const double value);
   void              SetControlBidLastDec(const double value);
   void              SetControlBidLastLevel(const double value);
   double            GetValueChangedBidLast(void)                          const;
   bool              IsIncreasedBidLast(void)                              const;
   bool              IsDecreasedBidLast(void)                              const;
   //--- Maximum Bid/Last of the day
   //--- setting the controlled maximum Bid or Last price (1) increase, (2) decrease value and (3) control level in points
   //--- getting the (4) maximum Bid or Last price change value,
   //--- getting the flag of the maximum Bid or Last price change exceeding the (5) growth, (6) decrease value
   void              SetControlBidLastHighInc(const double value);
   void              SetControlBidLastHighDec(const double value);
   void              SetControlBidLastHighLevel(const double value);
   double            GetValueChangedBidLastHigh(void)                      const;
   bool              IsIncreasedBidLastHigh(void)                          const;
   bool              IsDecreasedBidLastHigh(void)                          const;
   //--- Minimum Bid/Last of the day
   //--- setting the controlled minimum Bid or Last price (1) increase, (2) decrease value and (3) control level in points
   //--- getting the (4) minimum Bid or Last price change value,
   //--- getting the flag of the minimum Bid or Last price change exceeding the (5) growth, (6) decrease value
   void              SetControlBidLastLowInc(const double value);
   void              SetControlBidLastLowDec(const double value);
   void              SetControlBidLastLowLevev(const double value);
   double            GetValueChangedBidLastLow(void)                       const;
   bool              IsIncreasedBidLastLow(void)                           const;
   bool              IsDecreasedBidLastLow(void)                           const;
   
   //--- Ask
   //--- setting the controlled Ask price (1) increase, (2) decrease value and (3) control level in points
   //--- getting (4) Ask price change value,
   //--- getting the flag of the Ask price change exceeding the (5) growth, (6) decrease value
   void              SetControlAskInc(const double value)                        { this.SetControlPropertyINC(SYMBOL_PROP_ASK,::fabs(value));                        }
   void              SetControlAskDec(const double value)                        { this.SetControlPropertyDEC(SYMBOL_PROP_ASK,::fabs(value));                        }
   void              SetControlAskLevel(const double value)                      { this.SetControlPropertyLEVEL(SYMBOL_PROP_ASK,::fabs(value));                      }
   double            GetValueChangedAsk(void)                              const { return this.GetControlChangedValue(SYMBOL_PROP_ASK);                              }
   bool              IsIncreasedAsk(void)                                  const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_ASK);                             }
   bool              IsDecreasedAsk(void)                                  const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_ASK);                             }
   //--- Maximum Ask price for the day
   //--- setting the maximum day Ask controlled (1) increase, (2) decrease and (3) control level
   //--- getting (4) the maximum Ask change value within a day,
   //--- getting the flag of the maximum day Ask change exceeding the (5) growth, (6) decrease value
   void              SetControlAskHighInc(const double value)                    { this.SetControlPropertyINC(SYMBOL_PROP_ASKHIGH,::fabs(value));                    }
   void              SetControlAskHighDec(const double value)                    { this.SetControlPropertyDEC(SYMBOL_PROP_ASKHIGH,::fabs(value));                    }
   void              SetControlAskHighLevel(const double value)                  { this.SetControlPropertyLEVEL(SYMBOL_PROP_ASKHIGH,::fabs(value));                  }
   double            GetValueChangedAskHigh(void)                          const { return this.GetControlChangedValue(SYMBOL_PROP_ASKHIGH);                          }
   bool              IsIncreasedAskHigh(void)                              const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_ASKHIGH);                         }
   bool              IsDecreasedAskHigh(void)                              const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_ASKHIGH);                         }
   //--- Minimum Ask price for the day
   //--- setting the minimum day Ask controlled (1) increase, (2) decrease and (3) control level
   //--- getting (4) the minimum Ask change value within a day,
   //--- getting the flag of the minimum day Ask change exceeding the (5) growth, (6) decrease value
   void              SetControlAskLowInc(const double value)                     { this.SetControlPropertyINC(SYMBOL_PROP_ASKLOW,::fabs(value));                     }
   void              SetControlAskLowDec(const double value)                     { this.SetControlPropertyDEC(SYMBOL_PROP_ASKLOW,::fabs(value));                     }
   void              SetControlAskLowLevel(const double value)                   { this.SetControlPropertyLEVEL(SYMBOL_PROP_ASKLOW,::fabs(value));                   }
   double            GetValueChangedAskLow(void)                           const { return this.GetControlChangedValue(SYMBOL_PROP_ASKLOW);                           }
   bool              IsIncreasedAskLow(void)                               const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_ASKLOW);                          }
   bool              IsDecreasedAskLow(void)                               const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_ASKLOW);                          }
   //--- Real Volume for the day
   //--- setting the real day volume controlled (1) increase, (2) decrease and (3) control level
   //--- getting (4) the change value of the real day volume,
   //--- getting the flag of the real day volume change exceeding the (5) growth, (6) decrease value
   void              SetControlVolumeRealInc(const double value)                 { this.SetControlPropertyINC(SYMBOL_PROP_VOLUME_REAL,::fabs(value));                }
   void              SetControlVolumeRealDec(const double value)                 { this.SetControlPropertyDEC(SYMBOL_PROP_VOLUME_REAL,::fabs(value));                }
   void              SetControlVolumeRealLevel(const double value)               { this.SetControlPropertyLEVEL(SYMBOL_PROP_VOLUME_REAL,::fabs(value));              }
   double            GetValueChangedVolumeReal(void)                       const { return this.GetControlChangedValue(SYMBOL_PROP_VOLUME_REAL);                      }
   bool              IsIncreasedVolumeReal(void)                           const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_VOLUME_REAL);                     }
   bool              IsDecreasedVolumeReal(void)                           const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_VOLUME_REAL);                     }
   //--- Maximum real volume for the day
   //--- setting the maximum real day volume controlled (1) increase, (2) decrease and (3) control level
   //--- getting (4) the change value of the maximum real day volume,
   //--- getting the flag of the maximum real day volume change exceeding the (5) growth, (6) decrease value
   void              SetControlVolumeHighRealInc(const double value)             { this.SetControlPropertyINC(SYMBOL_PROP_VOLUMEHIGH_REAL,::fabs(value));            }
   void              SetControlVolumeHighRealDec(const double value)             { this.SetControlPropertyDEC(SYMBOL_PROP_VOLUMEHIGH_REAL,::fabs(value));            }
   void              SetControlVolumeHighRealLevel(const double value)           { this.SetControlPropertyLEVEL(SYMBOL_PROP_VOLUMEHIGH_REAL,::fabs(value));          }
   double            GetValueChangedVolumeHighReal(void)                   const { return this.GetControlChangedValue(SYMBOL_PROP_VOLUMEHIGH_REAL);                  }
   bool              IsIncreasedVolumeHighReal(void)                       const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_VOLUMEHIGH_REAL);                 }
   bool              IsDecreasedVolumeHighReal(void)                       const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_VOLUMEHIGH_REAL);                 }
   //--- Minimum real volume for the day
   //--- setting the minimum real day volume controlled (1) increase, (2) decrease and (3) control level
   //--- getting (4) the change value of the minimum real day volume,
   //--- getting the flag of the minimum real day volume change exceeding the (5) growth, (6) decrease value
   void              SetControlVolumeLowRealInc(const double value)              { this.SetControlPropertyINC(SYMBOL_PROP_VOLUMELOW_REAL,::fabs(value));             }
   void              SetControlVolumeLowRealDec(const double value)              { this.SetControlPropertyDEC(SYMBOL_PROP_VOLUMELOW_REAL,::fabs(value));             }
   void              SetControlVolumeLowRealLevel(const double value)            { this.SetControlPropertyLEVEL(SYMBOL_PROP_VOLUMELOW_REAL,::fabs(value));           }
   double            GetValueChangedVolumeLowReal(void)                    const { return this.GetControlChangedValue(SYMBOL_PROP_VOLUMELOW_REAL);                   }
   bool              IsIncreasedVolumeLowReal(void)                        const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_VOLUMELOW_REAL);                  }
   bool              IsDecreasedVolumeLowReal(void)                        const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_VOLUMELOW_REAL);                  }
   //--- Strike price
   //--- setting the controlled strike price (1) increase, (2) decrease value and (3) control level in points
   //--- getting (4) the change value of the strike price,
   //--- getting the flag of the strike price change exceeding the (5) growth, (6) decrease value
   void              SetControlOptionStrikeInc(const double value)               { this.SetControlPropertyINC(SYMBOL_PROP_OPTION_STRIKE,::fabs(value));              }
   void              SetControlOptionStrikeDec(const double value)               { this.SetControlPropertyDEC(SYMBOL_PROP_OPTION_STRIKE,::fabs(value));              }
   void              SetControlOptionStrikeLevel(const double value)             { this.SetControlPropertyLEVEL(SYMBOL_PROP_OPTION_STRIKE,::fabs(value));            }
   double            GetValueChangedOptionStrike(void)                     const { return this.GetControlChangedValue(SYMBOL_PROP_OPTION_STRIKE);                    } 
   bool              IsIncreasedOptionStrike(void)                         const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_OPTION_STRIKE);                   }
   bool              IsDecreasedOptionStrike(void)                         const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_OPTION_STRIKE);                   }
   //--- Maximum allowed total volume of unidirectional positions and orders
   //--- (1) Setting the control level
   //--- (2) getting the change value of the maximum allowed total volume of unidirectional positions and orders,
   //--- getting the flag of (3) increasing, (4) decreasing the maximum allowed total volume of unidirectional positions and orders
   void              SetControlVolumeLimitLevel(const double value)              { this.SetControlPropertyLEVEL(SYMBOL_PROP_VOLUME_LIMIT,::fabs(value));             }
   double            GetValueChangedVolumeLimit(void)                      const { return this.GetControlChangedValue(SYMBOL_PROP_VOLUME_LIMIT);                     }
   bool              IsIncreasedVolumeLimit(void)                          const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_VOLUME_LIMIT);                    }
   bool              IsDecreasedVolumeLimit(void)                          const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_VOLUME_LIMIT);                    }
   //---  Swap long
   //--- (1) Setting the control level
   //--- (2) getting the swap long change value,
   //--- getting the flag of (3) increasing, (4) decreasing the swap long
   void              SetControlSwapLongLevel(const double value)                 { this.SetControlPropertyLEVEL(SYMBOL_PROP_SWAP_LONG,::fabs(value));                }
   double            GetValueChangedSwapLong(void)                         const { return this.GetControlChangedValue(SYMBOL_PROP_SWAP_LONG);                        }
   bool              IsIncreasedSwapLong(void)                             const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_SWAP_LONG);                       }
   bool              IsDecreasedSwapLong(void)                             const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_SWAP_LONG);                       }
   //---  Swap short
   //--- (1) Setting the control level
   //--- (2) getting the swap short change value,
   //--- getting the flag of (3) increasing, (4) decreasing the swap short
   void              SetControlSwapShortLevel(const double value)                { this.SetControlPropertyLEVEL(SYMBOL_PROP_SWAP_SHORT,::fabs(value));               }
   double            GetValueChangedSwapShort(void)                        const { return this.GetControlChangedValue(SYMBOL_PROP_SWAP_SHORT);                       }
   bool              IsIncreasedSwapShort(void)                            const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_SWAP_SHORT);                      }
   bool              IsDecreasedSwapShort(void)                            const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_SWAP_SHORT);                      }
   //--- The total volume of deals in the current session
   //--- setting the controlled value of (1) growth, (2) decrease and (3) control level of the total volume of deals during the current session
   //--- getting (4) 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 (5) growth, (6) decrease value
   void              SetControlSessionVolumeInc(const double value)              { this.SetControlPropertyINC(SYMBOL_PROP_SESSION_VOLUME,::fabs(value));             }
   void              SetControlSessionVolumeDec(const double value)              { this.SetControlPropertyDEC(SYMBOL_PROP_SESSION_VOLUME,::fabs(value));             }
   void              SetControlSessionVolumeLevel(const double value)            { this.SetControlPropertyLEVEL(SYMBOL_PROP_SESSION_VOLUME,::fabs(value));           }
   double            GetValueChangedSessionVolume(void)                    const { return this.GetControlChangedValue(SYMBOL_PROP_SESSION_VOLUME);                   }
   bool              IsIncreasedSessionVolume(void)                        const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_SESSION_VOLUME);                  }
   bool              IsDecreasedSessionVolume(void)                        const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_SESSION_VOLUME);                  }
   //--- The total turnover in the current session
   //--- setting the controlled value of (1) growth, (2) decrease and (3) control level of the total turnover during the current session
   //--- getting (4) the total turnover change value in the current session,
   //--- getting the flag of the total turnover change during the current session exceeding the (5) growth, (6) decrease value
   void              SetControlSessionTurnoverInc(const double value)            { this.SetControlPropertyINC(SYMBOL_PROP_SESSION_TURNOVER,::fabs(value));           }
   void              SetControlSessionTurnoverDec(const double value)            { this.SetControlPropertyDEC(SYMBOL_PROP_SESSION_TURNOVER,::fabs(value));           }
   void              SetControlSessionTurnoverLevel(const double value)          { this.SetControlPropertyLEVEL(SYMBOL_PROP_SESSION_TURNOVER,::fabs(value));         }
   double            GetValueChangedSessionTurnover(void)                  const { return this.GetControlChangedValue(SYMBOL_PROP_SESSION_TURNOVER);                 }
   bool              IsIncreasedSessionTurnover(void)                      const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_SESSION_TURNOVER);                }
   bool              IsDecreasedSessionTurnover(void)                      const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_SESSION_TURNOVER);                }
   //--- The total volume of open positions
   //--- setting the controlled value of (1) growth, (2) decrease and (3) control level of the total volume of open positions during the current session
   //--- getting (4) 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 (5) growth, (6) decrease value
   void              SetControlSessionInterestInc(const double value)            { this.SetControlPropertyINC(SYMBOL_PROP_SESSION_INTEREST,::fabs(value));           }
   void              SetControlSessionInterestDec(const double value)            { this.SetControlPropertyDEC(SYMBOL_PROP_SESSION_INTEREST,::fabs(value));           }
   void              SetControlSessionInterestLevel(const double value)          { this.SetControlPropertyLEVEL(SYMBOL_PROP_SESSION_INTEREST,::fabs(value));         }
   double            GetValueChangedSessionInterest(void)                  const { return this.GetControlChangedValue(SYMBOL_PROP_SESSION_INTEREST);                 }
   bool              IsIncreasedSessionInterest(void)                      const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_SESSION_INTEREST);                }
   bool              IsDecreasedSessionInterest(void)                      const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_SESSION_INTEREST);                }
   //--- The total volume of Buy orders at the moment
   //--- setting the controlled value of (1) growth, (2) decrease and (3) control level of the current total buy order volume
   //--- getting (4) the change value of the current total buy order volume,
   //--- getting the flag of the current total buy orders' volume change exceeding the (5) growth, (6) decrease value
   void              SetControlSessionBuyOrdVolumeInc(const double value)        { this.SetControlPropertyINC(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME,::fabs(value));  }
   void              SetControlSessionBuyOrdVolumeDec(const double value)        { this.SetControlPropertyDEC(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME,::fabs(value));  }
   void              SetControlSessionBuyOrdVolumeLevel(const double value)      { this.SetControlPropertyLEVEL(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME,::fabs(value));}
   double            GetValueChangedSessionBuyOrdVolume(void)              const { return this.GetControlChangedValue(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME);        }
   bool              IsIncreasedSessionBuyOrdVolume(void)                  const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME);       }
   bool              IsDecreasedSessionBuyOrdVolume(void)                  const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME);       }
   //--- The total volume of Sell orders at the moment
   //--- setting the controlled value of (1) growth, (2) decrease and (3) control level of the current total sell order volume
   //--- getting (4) the change value of the current total sell order volume,
   //--- getting the flag of the current total sell orders' volume change exceeding the (5) growth, (6) decrease value
   void              SetControlSessionSellOrdVolumeInc(const double value)       { this.SetControlPropertyINC(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME,::fabs(value)); }
   void              SetControlSessionSellOrdVolumeDec(const double value)       { this.SetControlPropertyDEC(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME,::fabs(value)); }
   void              SetControlSessionSellOrdVolumeLevel(const double value)     { this.SetControlPropertyLEVEL(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME,::fabs(value));}
   double            GetValueChangedSessionSellOrdVolume(void)             const { return this.GetControlChangedValue(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME);       }
   bool              IsIncreasedSessionSellOrdVolume(void)                 const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME);      }
   bool              IsDecreasedSessionSellOrdVolume(void)                 const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME);      }
   //--- Session open price
   //--- setting the controlled session open price (1) increase, (2) decrease and (3) control value
   //--- getting (4) the change value of the session open price,
   //--- getting the flag of the session open price change exceeding the (5) growth, (6) decrease value
   void              SetControlSessionPriceOpenInc(const double value)           { this.SetControlPropertyINC(SYMBOL_PROP_SESSION_OPEN,::fabs(value));               }
   void              SetControlSessionPriceOpenDec(const double value)           { this.SetControlPropertyDEC(SYMBOL_PROP_SESSION_OPEN,::fabs(value));               }
   void              SetControlSessionPriceOpenLevel(const double value)         { this.SetControlPropertyLEVEL(SYMBOL_PROP_SESSION_OPEN,::fabs(value));             }
   double            GetValueChangedSessionPriceOpen(void)                 const { return this.GetControlChangedValue(SYMBOL_PROP_SESSION_OPEN);                     }
   bool              IsIncreasedSessionPriceOpen(void)                     const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_SESSION_OPEN);                    }
   bool              IsDecreasedSessionPriceOpen(void)                     const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_SESSION_OPEN);                    }
   //--- Session close price
   //--- setting the controlled session close price (1) increase, (2) decrease and (3) control value
   //--- getting (4) the change value of the session close price,
   //--- getting the flag of the session close price change exceeding the (5) growth, (6) decrease value
   void              SetControlSessionPriceCloseInc(const double value)          { this.SetControlPropertyINC(SYMBOL_PROP_SESSION_CLOSE,::fabs(value));              }
   void              SetControlSessionPriceCloseDec(const double value)          { this.SetControlPropertyDEC(SYMBOL_PROP_SESSION_CLOSE,::fabs(value));              }
   void              SetControlSessionPriceCloseLevel(const double value)        { this.SetControlPropertyLEVEL(SYMBOL_PROP_SESSION_CLOSE,::fabs(value));            }
   double            GetValueChangedSessionPriceClose(void)                const { return this.GetControlChangedValue(SYMBOL_PROP_SESSION_CLOSE);                    }
   bool              IsIncreasedSessionPriceClose(void)                    const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_SESSION_CLOSE);                   }
   bool              IsDecreasedSessionPriceClose(void)                    const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_SESSION_CLOSE);                   }
   //--- The average weighted session price
   //--- setting the controlled session average weighted price (1) increase, (2) decrease and (3) control value
   //--- getting (4) the change value of the average weighted session price,
   //--- getting the flag of the average weighted session price change exceeding the (5) growth, (6) decrease value
   void              SetControlSessionPriceAWInc(const double value)             { this.SetControlPropertyINC(SYMBOL_PROP_SESSION_AW,::fabs(value));                 }
   void              SetControlSessionPriceAWDec(const double value)             { this.SetControlPropertyDEC(SYMBOL_PROP_SESSION_AW,::fabs(value));                 }
   void              SetControlSessionPriceAWLevel(const double value)           { this.SetControlPropertyLEVEL(SYMBOL_PROP_SESSION_AW,::fabs(value));               }
   double            GetValueChangedSessionPriceAW(void)                   const { return this.GetControlChangedValue(SYMBOL_PROP_SESSION_AW);                       }
   bool              IsIncreasedSessionPriceAW(void)                       const { return (bool)this.GetControlFlagINC(SYMBOL_PROP_SESSION_AW);                      }
   bool              IsDecreasedSessionPriceAW(void)                       const { return (bool)this.GetControlFlagDEC(SYMBOL_PROP_SESSION_AW);                      }
//---


Betrachten wir die Implementierung von deklarierten Methoden und Änderungen an den bereits bestehenden.

Nehmen Sie einige kleine Änderungen am Klassenkonstruktor vor:

//+------------------------------------------------------------------+
//| Closed parametric constructor                                    |
//+------------------------------------------------------------------+
CSymbol::CSymbol(ENUM_SYMBOL_STATUS symbol_status,const string name,const int index)
  {
   this.m_name=name;
   this.m_type=COLLECTION_SYMBOLS_ID;
   if(!this.Exist())
     {
      ::Print(DFUN_ERR_LINE,"\"",this.m_name,"\"",": ",TextByLanguage("Ошибка. Такого символа нет на сервере","Error. 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 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 control data
   this.SetControlDataArraySizeLong(SYMBOL_PROP_INTEGER_TOTAL); 
   this.SetControlDataArraySizeDouble(SYMBOL_PROP_DOUBLE_TOTAL);
   this.ResetChangesParams();                                   
   this.ResetControlsParams();                                  
   
//--- Initialize symbol data
   this.Reset();
   this.InitMarginRates();
#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();
  }
//+------------------------------------------------------------------------------------------------------------+
//|Compare CSymbol objects by all possible properties (for sorting lists by a specified symbol object property)|
//+------------------------------------------------------------------------------------------------------------+


Um Objektereignisse in der Basisobjektklasse genau zu definieren, ordnen Sie die Symbolkollektions-ID dem Symbolobjekttyp zu und setzen Sie die Größe von Arrays von Integer und Realdaten, um Ereignisse in Symbolobjekteigenschaften durch das Basisobjekt zu verfolgen. Als nächstes initialisieren Sie bearbeitbare und steuerbare Parameter in den Arrays von Ganzzahlen und realen Eigenschaften.

Die Methode Refresh() des Symbolobjekts wurde ebenfalls geändert:

//+------------------------------------------------------------------+
//| 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 
//--- Initialize event data
   this.m_is_event=false;

   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 symbol current data
   for(int i=0;i<SYMBOL_PROP_INTEGER_TOTAL;i++)
      this.m_long_prop_event[i][3]=this.m_long_prop[i];
   for(int i=0;i<SYMBOL_PROP_DOUBLE_TOTAL;i++)
      this.m_double_prop_event[i][3]=this.m_double_prop[i];
   
   CBaseObj::Refresh();
   this.CheckEvents();
  }
//+------------------------------------------------------------------+


Da wir keine Strukturen mehr für die Speicherung des aktuellen und vorherigen Symbol-Eigenschaftszustands anlegen müssen, wurde das Ausfüllen der Struktur der aktuellen Symbolstatusdaten entfernt. Stattdessen haben wir das Ausfüllen in den Arrays von Integer- und Real-Eigenschaften im Basisobjekt eingegliedert.
Nachdem die Arrays ausgefüllt sind, müssen wir die Refresh()-Methode des CBaseObj-Basisobjekts aufrufen, in der die Suche nach aufgetretenen Änderungen durchgeführt und die Liste der nachfolgenden Objekt-Basisereignisse erstellt wird.
Nachdem Sie die Liste der Basisereignisse in der übergeordneten Klasse erstellt haben (falls es Kriterien zur Ereigniserzeugung gibt), überprüfen Sie die Basisereignisse mit der Methode CheckEvents(). Wenn sie vorhanden sind, erstellen Sie die Liste der Symbolereignisse.

Implementierung der Methode zur Überprüfung von Ereignissen:

//+------------------------------------------------------------------+
//| Check the list of symbol property changes and create an event    |
//+------------------------------------------------------------------+
void CSymbol::CheckEvents(void)
  {
   int total=this.m_list_events_base.Total();
   if(total==0)
      return;
  for(int i=0;i<total;i++)
     {
      CBaseEvent *event=this.GetEventBase(i);
      if(event==NULL)
         continue;
      long lvalue=0;
      this.UshortToLong(this.MSCfromTime(this.TickTime()),0,lvalue);
      this.UshortToLong(event.Reason(),1,lvalue);
      this.UshortToLong(COLLECTION_SYMBOLS_ID,2,lvalue);
      if(this.EventAdd((ushort)event.ID(),lvalue,event.Value(),this.Name()))
         this.m_is_event=true;
     }
  }  
//+------------------------------------------------------------------+


Wenn die Liste der Basisereignisse leer ist, exit.
In der Schleife durch die Liste der Basisereignisse, erhalten wir das nächste Ereignis. Wenn das Ereignis empfangen wird, erstellen Sie ein Symbolereignis:

  • rufen Sie nur die Millisekunden von der aktuellen Zeit in Millisekunden ab und fügen Sie sie zu den ersten beiden Bytes des 'long' Parameter des Ereignisses hinzu.
  • Ereignisgrund (Steigen/Fallen/Oberes Niveau/Unteres Niveau) und fügen Sie ihn zur zweiten zwei Bytes des 'long' Parameter des Ereignisses hinzu.
  • Symbolkollektions-ID wird zu den dritten zwei Bytes des 'long' Parameter des Ereignisses hinzugefügt.
  • Hinzufügen des Symbolereignisses zur Liste der Symbolereignisse und Setzen des Flags, das eine Ereignispräsenz eines Symbols anzeigt.

Verfahren zum Initialisieren der Variablen von kontrollierten Symboldaten:

//+------------------------------------------------------------------+
//| Initialize the variables of controlled symbol data               |
//+------------------------------------------------------------------+
void CSymbol::InitControlsParams(void)
  {
   this.ResetControlsParams();
  }
//+------------------------------------------------------------------+


Rufen Sie einfach die oben genannte Methode zum Zurücksetzen der Variablen von kontrollierten Objektdatenwerten auf.

Verfahren zum Setzen von kontrollierten Werten und Flags von aufgetretenen Änderungen und die Verfahren zum Empfangen einer Größe von aufgetretenen Änderungen und Flags:

//+------------------------------------------------------------------+
//| Set the value of the controlled property increase                |
//+------------------------------------------------------------------+
template<typename T> void CSymbol::SetControlPropertyINC(const int property,const T value)
  {
   if(property<SYMBOL_PROP_INTEGER_TOTAL)
      this.SetControlledValueINC(property,(long)value);
   else
      this.SetControlledValueINC(property,(double)value);
  }  
//+------------------------------------------------------------------+
//| Set the value of the controlled property decrease                |
//+------------------------------------------------------------------+
template<typename T> void CSymbol::SetControlPropertyDEC(const int property,const T value)
  {
   if(property<SYMBOL_PROP_INTEGER_TOTAL)
      this.SetControlledValueDEC(property,(long)value);
   else
      this.SetControlledValueDEC(property,(double)value);
  }
//+------------------------------------------------------------------+
//| Set the value of the controlled property level                   |
//+------------------------------------------------------------------+
template<typename T> void CSymbol::SetControlPropertyLEVEL(const int property,const T value)
  {
   if(property<SYMBOL_PROP_INTEGER_TOTAL)
      this.SetControlledValueLEVEL(property,(long)value);
   else
      this.SetControlledValueLEVEL(property,(double)value);
  }
//+------------------------------------------------------------------+
//| Set the flag of the symbol property value change                 |
//| exceeding the increase value                                     |
//+------------------------------------------------------------------+
template<typename T> void CSymbol::SetControlFlagINC(const int property,const T value)
  {
   if(property<SYMBOL_PROP_INTEGER_TOTAL)
      this.SetControlledFlagINC(property,(long)value);
   else
      this.SetControlledFlagINC(property,(double)value);
  }  
//+------------------------------------------------------------------+
//| Set the flag of the symbol property value change                 |
//| exceeding the decrease value                                     |
//+------------------------------------------------------------------+
template<typename T> void CSymbol::SetControlFlagDEC(const int property,const T value)
  {
   if(property<SYMBOL_PROP_INTEGER_TOTAL)
      this.SetControlledFlagDEC(property,(long)value);
   else
      this.SetControlledFlagDEC(property,(double)value);
  }
//+------------------------------------------------------------------+
//| Set the change value of the controlled symbol property           |
//+------------------------------------------------------------------+
template<typename T> void CSymbol::SetControlChangedValue(const int property,const T value)
  {
   if(property<SYMBOL_PROP_INTEGER_TOTAL)
      this.SetControlledChangedValue(property,(long)value);
   else
      this.SetControlledChangedValue(property,(double)value);
  }
//+------------------------------------------------------------------+
//| Set the Bid or Last price controlled increase                    |
//+------------------------------------------------------------------+
void CSymbol::SetControlBidLastInc(const double value)
  {
   this.SetControlPropertyINC((this.ChartMode()==SYMBOL_CHART_MODE_BID ? SYMBOL_PROP_BID : SYMBOL_PROP_LAST),::fabs(value));
  }
//+------------------------------------------------------------------+
//|Set the Bid or Last price controlled decrease                     |
//+------------------------------------------------------------------+
void CSymbol::SetControlBidLastDec(const double value)
  {
   this.SetControlPropertyDEC((this.ChartMode()==SYMBOL_CHART_MODE_BID ? SYMBOL_PROP_BID : SYMBOL_PROP_LAST),::fabs(value));
  }
//+------------------------------------------------------------------+
//| Set the Bid or Last price control level                          |
//+------------------------------------------------------------------+
void CSymbol::SetControlBidLastLevel(const double value)
  {
   this.SetControlPropertyLEVEL((this.ChartMode()==SYMBOL_CHART_MODE_BID ? SYMBOL_PROP_BID : SYMBOL_PROP_LAST),::fabs(value));
  }
//+------------------------------------------------------------------+
//| Return the Bid or Last price change value                        |
//+------------------------------------------------------------------+
double CSymbol::GetValueChangedBidLast(void) const
  {
   return(this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.GetControlChangedValue(SYMBOL_PROP_BID) : this.GetControlChangedValue(SYMBOL_PROP_LAST));
  }
//+------------------------------------------------------------------+
//| Return the flag of the Bid or Last price change                  |
//| exceeding the increase value                                     |
//+------------------------------------------------------------------+
bool CSymbol::IsIncreasedBidLast(void) const
  {
   return(this.ChartMode()==SYMBOL_CHART_MODE_BID ? (bool)this.GetControlFlagINC(SYMBOL_PROP_BID) : (bool)this.GetControlFlagINC(SYMBOL_PROP_LAST));
  }
//+------------------------------------------------------------------+
//| Return the flag of the Bid or Last price change                  |
//| exceeding the decrease value                                     |
//+------------------------------------------------------------------+
bool CSymbol::IsDecreasedBidLast(void) const
  {
   return(this.ChartMode()==SYMBOL_CHART_MODE_BID ? (bool)this.GetControlFlagDEC(SYMBOL_PROP_BID) : (bool)this.GetControlFlagDEC(SYMBOL_PROP_LAST));
  }
//+------------------------------------------------------------------+
//| Set the controlled increase value                                |
//| of the maximum Bid or Last price                                 |
//+------------------------------------------------------------------+
void CSymbol::SetControlBidLastHighInc(const double value)
  {
   this.SetControlPropertyINC((this.ChartMode()==SYMBOL_CHART_MODE_BID ? SYMBOL_PROP_BIDHIGH : SYMBOL_PROP_LASTHIGH),::fabs(value));
  }
//+------------------------------------------------------------------+
//| Set the controlled decrease value                                |
//| of the maximum Bid or Last price                                 |
//+------------------------------------------------------------------+
void CSymbol::SetControlBidLastHighDec(const double value)
  {
   this.SetControlPropertyDEC((this.ChartMode()==SYMBOL_CHART_MODE_BID ? SYMBOL_PROP_BIDHIGH : SYMBOL_PROP_LASTHIGH),::fabs(value));
  }
//+------------------------------------------------------------------+
//| Set the maximum Bid or Last price control level                  |
//+------------------------------------------------------------------+
void CSymbol::SetControlBidLastHighLevel(const double value)
  {
   this.SetControlPropertyLEVEL((this.ChartMode()==SYMBOL_CHART_MODE_BID ? SYMBOL_PROP_BIDHIGH : SYMBOL_PROP_LASTHIGH),::fabs(value));
  }
//+------------------------------------------------------------------+
//| Return the maximum Bid or Last price change value                |
//+------------------------------------------------------------------+
double CSymbol::GetValueChangedBidLastHigh(void) const
  {
   return(this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.GetControlChangedValue(SYMBOL_PROP_BIDHIGH) : this.GetControlChangedValue(SYMBOL_PROP_LASTHIGH));
  }
//+------------------------------------------------------------------+
//| Return the flag of a change of the maximum                       |
//| Bid or Last price exceeding the increase value                   |
//+------------------------------------------------------------------+
bool CSymbol::IsIncreasedBidLastHigh(void) const
  {
   return(this.ChartMode()==SYMBOL_CHART_MODE_BID ? (bool)this.GetControlFlagINC(SYMBOL_PROP_BIDHIGH) : (bool)this.GetControlFlagINC(SYMBOL_PROP_LASTHIGH));
  }
//+------------------------------------------------------------------+
//| Return the flag of a change of the maximum                       |
//| Bid or Last price exceeding the decrease value                   |
//+------------------------------------------------------------------+
bool CSymbol::IsDecreasedBidLastHigh(void) const
  {
   return(this.ChartMode()==SYMBOL_CHART_MODE_BID ? (bool)this.GetControlFlagDEC(SYMBOL_PROP_BIDHIGH) : (bool)this.GetControlFlagDEC(SYMBOL_PROP_LASTHIGH));
  }
//+------------------------------------------------------------------+
//| Set the controlled increase value                                |
//| of the minimum Bid or Last price                                 |
//+------------------------------------------------------------------+
void CSymbol::SetControlBidLastLowInc(const double value)
  {
   this.SetControlPropertyINC((this.ChartMode()==SYMBOL_CHART_MODE_BID ? SYMBOL_PROP_BIDLOW : SYMBOL_PROP_LASTLOW),::fabs(value));
  }
//+------------------------------------------------------------------+
//| Set the controlled decrease value                                |
//| of the minimum Bid or Last price                                 |
//+------------------------------------------------------------------+
void CSymbol::SetControlBidLastLowDec(const double value)
  {
   this.SetControlPropertyDEC((this.ChartMode()==SYMBOL_CHART_MODE_BID ? SYMBOL_PROP_BIDLOW : SYMBOL_PROP_LASTLOW),::fabs(value));
  }
//+------------------------------------------------------------------+
//| Set the minimum Bid or Last price control level                  |
//+------------------------------------------------------------------+
void CSymbol::SetControlBidLastLowLevev(const double value)
  {
   this.SetControlPropertyLEVEL((this.ChartMode()==SYMBOL_CHART_MODE_BID ? SYMBOL_PROP_BIDLOW : SYMBOL_PROP_LASTLOW),::fabs(value));
  }
//+------------------------------------------------------------------+
//| Return the minimum Bid or Last price change value                |
//+------------------------------------------------------------------+
double CSymbol::GetValueChangedBidLastLow(void) const
  {
   return(this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.GetControlChangedValue(SYMBOL_PROP_BIDLOW) : this.GetControlChangedValue(SYMBOL_PROP_LASTLOW));
  }
//+------------------------------------------------------------------+
//| Return the flag of a change of the minimum                       |
//| Bid or Last price exceeding the increase value                   |
//+------------------------------------------------------------------+
bool CSymbol::IsIncreasedBidLastLow(void) const
  {
   return(this.ChartMode()==SYMBOL_CHART_MODE_BID ? (bool)this.GetControlFlagINC(SYMBOL_PROP_BIDLOW) : (bool)this.GetControlFlagINC(SYMBOL_PROP_LASTLOW));
  }
//+------------------------------------------------------------------+
//| Return the flag of a change of the minimum                       |
//| Bid or Last price exceeding the decrease value                   |
//+------------------------------------------------------------------+
bool CSymbol::IsDecreasedBidLastLow(void) const
  {
   return(this.ChartMode()==SYMBOL_CHART_MODE_BID ? (bool)this.GetControlFlagDEC(SYMBOL_PROP_BIDLOW) : (bool)this.GetControlFlagDEC(SYMBOL_PROP_LASTLOW));
  }
//+------------------------------------------------------------------+


Wir haben die ähnlichen Methoden bereits bei der Verbesserung der Basisobjektklasse berücksichtigt. Die betrachteten Methoden werden hier in Abhängigkeit von einer erforderlichen Symbolobjekteigenschaft aufgerufen.

Damit ist die Verbesserung der Symbolobjektklasse abgeschlossen.

Nun bleibt nur noch, die Klasse der Symbolkollektion etwas zu verfeinern.
Öffnen Sie die Datei \MQL5\Include\DoEasy\Collections\SymbolsCollection.mqh und nehmen Sie die notwendigen Änderungen vor.

Da wir nicht mehr für jedes Objekt separate Ereignisenumerationen erstellen müssen, setzen Sie den Typ 'int' für die Variable "last symbol event" und die Methode GetLastEvent() anstelle des vorherigen Typs ENUM_SYMBOL_EVENT:

int m_last_event; // The last event
int GetLastEvent(void) const { return this.m_last_event; }


Da nun alle Symbolereignisse (sowie Ereignisse eines beliebigen abgeleiteten Objekts) in der Basisobjektklasse behandelt werden, benennen Sie die Methode EventDescription() in EventMWDescription() um und übergeben die Variable mit dem Enumerationstyp der Fensterereignisse in der Marktübersicht an die Methode:.

//--- Return the description of the (1) Market Watch window event, (2) mode of working with symbols
   string            EventMWDescription(const ENUM_MW_EVENT event);
   string            ModeSymbolsListDescription(void);


Da sich die Namen der Enumerationen geändert haben, hat sich die Arbeitsweise mit dem Fenster der Marktübersicht geringfügig auch geändert (Enumerationsnamen und der Typ der Ereignisvariablen wurde geändert):

//+------------------------------------------------------------------+
//| 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;
      ushort event_id=
        (ushort(
         this.m_total_symbols>this.m_total_symbol_prev ? MARKET_WATCH_EVENT_SYMBOL_ADD :
         this.m_total_symbols<this.m_total_symbol_prev ? MARKET_WATCH_EVENT_SYMBOL_DEL :
         MARKET_WATCH_EVENT_SYMBOL_SORT)
        );
      //--- Adding a symbol to the Market Watch window
      if(event_id==MARKET_WATCH_EVENT_SYMBOL_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==MARKET_WATCH_EVENT_SYMBOL_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==MARKET_WATCH_EVENT_SYMBOL_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;
     }
  }
//+------------------------------------------------------------------+


Der Typ der Ereignisvariablen wurde auch in der Arbeitsweise mit der Ereignisliste der Symbolkollektion geändert:

//+------------------------------------------------------------------+
//| 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;
         ushort event_id=event.ID();
         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());
           }
        }
     }
  }
//+------------------------------------------------------------------+


Die Namen der Enumerationskonstanten der Ereignisse wurden auch in der Methode geändert, die die Zeichenkettenbeschreibung der Ereignisse im Fenster der Marktübersicht zurückgibt:

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


Lassen Sie uns nun die Klasse CEngine verbessern. Öffnen Sie die Datei \MQL5\Include\DoEasy\Engine.mqh und nehmen Sie dort die notwendigen Änderungen vor:

Die Variable, die das letzte Ereignis in den Symboleigenschaften speichert, und die Methode , die den Wert der Variable zurückgibt, sind ebenfalls vom Typ 'int':

   int m_last_symbol_event;  // Last event in the symbol properties
   int LastSymbolsEvent(void) const { return this.m_last_symbol_event; }


Fügen Sie im öffentlichen Abschnitt der Klasse die Deklaration der Methode hinzu, die eine 'ushort'-Nummer aus dem Container 'long' zum angegebenen Speicherindex im 'long'-Parameter der 'ushort'-Nummer abruft:

//--- Retrieve a necessary 'ushort' number from the packed 'long' value
   ushort               LongToUshortFromByte(const long source_value,const uchar index) const;


Schreiben Sie auch die drei Methoden, die sofort die Millisekunden, den Grund und die Quelle des Ergebnisses aus dem 'long'-Ereignisparameter zurückgeben:

//--- Return event (1) milliseconds, (2) reason and (3) source from its 'long' value
   ushort               EventMSC(const long lparam)               const { return this.LongToUshortFromByte(lparam,0);         }
   ushort               EventReason(const long lparam)            const { return this.LongToUshortFromByte(lparam,1);         }
   ushort               EventSource(const long lparam)            const { return this.LongToUshortFromByte(lparam,2);         }


Da Null die allererste ganzzahlige Eigenschaft eines beliebigen Objekts ist, ändern Sie den Initialisierungswert für die Variable, die das letzte Symbolereignis in der Initialisierungsliste des Klassenkonstruktors speichert — jetzt wird er mit einem negativen Wert initialisiert:

//+------------------------------------------------------------------+
//| 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(WRONG_VALUE),
                     m_global_error(ERR_SUCCESS)
  {


Implementierung des Verfahrens zum Abrufen einer 'ushort'-Nummer aus dem 'long'-Container durch den Byteindex seiner Position im 'long'-Container:

//+------------------------------------------------------------------+
//| Retrieve a necessary 'ushort' number from the packed 'long' value|
//+------------------------------------------------------------------+
ushort CEngine::LongToUshortFromByte(const long source_value,const uchar index) const
  {
   if(index>3)
     {
      ::Print(DFUN,TextByLanguage("Ошибка. Значение \"index\" должно быть в пределах 0 - 3","Error. \"index\" value should be between 0 - 3"));
      return 0;
     }
   long res=source_value>>(16*index);
   return ushort(res &=0xFFFF);
  }
//+------------------------------------------------------------------+


Das Verfahren empfängt einen 'long'-Wert, aus dem eine 'ushort'-Nummer extrahiert werden soll, und den Byteindex, in dem sich die Nummer befindet (die Tabelle der 'ushort'-Nummern, die sich im 'long'-Container befinden, wurde oben berücksichtigt). Anschließend wird die Gültigkeit der Indexspezifikation überprüft. Wenn der Index ungültig ist, wird eine Fehlermeldung angezeigt und 0 zurückgegeben.
Als Nächstes verschieben Sie die long'-Zahlenbits um 16 * Indexbits nach rechts, wenden Sie eine Maske zum "Löschen" der restlichen hohen Bits an und geben Sie eine so erhaltene 'ushort'-Zahl zurück.

Um in MQL4 zu arbeiten, müssen wir den Compiler über den Größenfehler ERR_ZEROSIZE_ARRAY des Arrays mit der Größe Null.
Der Fehler, der für ein Array mit der Größe Null am besten geeignet ist, ist der dem MQL4-Compiler bekannte Fehler "invalid array". Stellen wird das als Alternative zum Array-Nullgrößenfehler ein.

Öffnen Sie die Datei \MQL5\Include\DoEasy\ToMQL4.mqh und fügen Sie den für den MQL4-Compiler unbekannten Fehlercode hinzu:

//+------------------------------------------------------------------+
//|                                                       ToMQL4.mqh |
//|              Copyright 2017, Artem A. Trishkin, Skype artmedia70 |
//|                         https://www.mql5.com/de/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, Artem A. Trishkin, Skype artmedia70"
#property link      "https://www.mql5.com/de/users/artmedia70"
#property strict
#ifdef __MQL4__
//+------------------------------------------------------------------+
//| Error codes                                                      |
//+------------------------------------------------------------------+
#define ERR_SUCCESS                       (ERR_NO_ERROR)
#define ERR_MARKET_UNKNOWN_SYMBOL         (ERR_UNKNOWN_SYMBOL)
#define ERR_ZEROSIZE_ARRAY                (ERR_ARRAY_INVALID)
//+------------------------------------------------------------------+


Dies sind alle Änderungen, die wir brauchten, um Symbole zu starten, die mit den neuen Ereignisfunktionen ausgestattet sind, die das Objekt CBaseObj allen seinen Nachkommen bietet.


Testen der Ereignisfunktionen des Basisobjekts aller Bibliotheksobjekte

Um die neuen Ereignisfunktionen des Basisobjekts zu testen, nehmen Sie den EA aus dem vorherigen Artikel und speichern Sie ihn unter dem Namen TestDoEasyPart17.mq5 in \MQL5\Experts\TestDoEasy\ Part17.

Testen wir die Änderung des Spread des aktuellen Symbols um 4 Punkte (erhöhen und verringern), sowie die Kontrolle eines Spread von 15 Punkten. Für den Bid-Preis kontrollieren Sie die Erhöhung/Verminderung des Wertes um +/- 10 Punkte und verfolgen Sie den Preis, der das Niveau von 1,13700 überschreitet.

Um die oben genannten Überwachungswerte einzustellen, fügen Sie einfach die folgenden Zeichenketten in OnInit() in diesem Beispiel hinzu:

//+------------------------------------------------------------------+
//| Initialisierungsfunktion des Experten                            |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Calling the function displays the list of enumeration constants in the journal 
//--- (the list is set in the strings 22 and 25 of the DELib.mqh file) for checking the constants validity
   //EnumNumbersTest();

//--- Set EA global variables
   prefix=MQLInfoString(MQL_PROGRAM_NAME)+"_";
   for(int i=0;i<TOTAL_BUTT;i++)
     {
      butt_data[i].name=prefix+EnumToString((ENUM_BUTTONS)i);
      butt_data[i].text=EnumToButtText((ENUM_BUTTONS)i);
     }
   lot=NormalizeLot(Symbol(),fmax(InpLots,MinimumLots(Symbol())*2.0));
   magic_number=InpMagic;
   stoploss=InpStopLoss;
   takeprofit=InpTakeProfit;
   distance_pending=InpDistance;
   distance_stoplimit=InpDistanceSL;
   slippage=InpSlippage;
   trailing_stop=InpTrailingStop*Point();
   trailing_step=InpTrailingStep*Point();
   trailing_start=InpTrailingStart;
   stoploss_to_modify=InpStopLossModify;
   takeprofit_to_modify=InpTakeProfitModify;
   
//--- 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;
        }
     }
//--- Fill in the array of used symbols
   used_symbols=InpUsedSymbols;
   CreateUsedSymbolsArray((ENUM_SYMBOLS_MODE)used_symbols_mode,used_symbols,array_used_symbols);

//--- 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());

//--- Set controlled values for the current symbol
   CSymbol* symbol=engine.GetSymbolCurrent();
   if(symbol!=NULL)
     {
      //--- Set control of the current symbol price increase by 10 points
      symbol.SetControlBidInc(10*Point());
      //--- Set control of the current symbol price decrease by 10 points
      symbol.SetControlBidDec(10*Point());
      //--- Set control of the current symbol spread increase by 4 points
      symbol.SetControlSpreadInc(4);
      //--- Set control of the current symbol spread decrease by 4 points
      symbol.SetControlSpreadDec(4);
      //--- Set control of the current spread by the value of 15 points
      symbol.SetControlSpreadLevel(15);
      //--- Set control of the price crossing the level of 1.13700
      symbol.SetControlBidLevel(1.13700);
     }

//--- Check and remove remaining EA graphical objects
   if(IsPresentObects(prefix))
      ObjectsDeleteAll(0,prefix);

//--- Create the button panel
   if(!CreateButtons(InpButtShiftX,InpButtShiftY))
      return INIT_FAILED;
//--- Set trailing activation button status
   ButtonState(butt_data[TOTAL_BUTT-1].name,trailing_on);

//--- Set CTrade trading class parameters
#ifdef __MQL5__
   trade.SetDeviationInPoints(slippage);
   trade.SetExpertMagicNumber(magic_number);
   trade.SetTypeFillingBySymbol(Symbol());
   trade.SetMarginMode();
   trade.LogLevel(LOG_LEVEL_NO);
#endif 
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+


Dies ist ein Testbeispiel für das Setzen von verfolgten Symbolparametern, daher legen wir sofort die erforderlichen Kontrollwerte in OnInit() fest.
Aber nichts hindert uns daran, die rückverfolgbaren Werte des Symbols anhand einiger aktueller Kriterien während des Arbeitsprozesses zeitnah zu ändern - alle Methoden befinden sich im Basisobjekt. Es genügt, Zugriff auf eines der von CBaseObj geerbten Objekte zu erhalten, um Methoden zur Einstellung kontrollierter Parameter und Methoden zum Erhalten der geänderten Parameter zur Verfügung zu haben, und dann die kontrollierten Parameter gemäß der im Programm eingebetteten Logik zu ändern — programmatisch oder aus der grafischen Oberfläche der Bibliothek, die ebenfalls später erstellt wird.

Aus der Funktion OnTick() des EAs entfernen Sie die Variable, die das letzte Symbolereignis speichert. Wir haben andere Werkzeuge zur Verfolgung von Symbolereignissen als einen einfachen Vergleich des aktuellen und vorherigen Zustands.

//+------------------------------------------------------------------+
//| 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))
     {


Ändern Sie die Ereignisbehandlung der Bibliothek in Bezug auf die Behandlung der Ereignisse einer Symbolkollektion:

//+------------------------------------------------------------------+
//| 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);
   
//--- Retrieve (1) event time milliseconds, (2) reason and (3) source from lparam, as well as (4) set the exact event time
   ushort msc=engine.EventMSC(lparam);
   ushort reason=engine.EventReason(lparam);
   ushort source=engine.EventSource(lparam);
   long time=TimeCurrent()*1000+msc;
      
//--- Handling market watch window events
   if(idx>MARKET_WATCH_EVENT_NO_EVENT && idx<SYMBOL_EVENTS_NEXT_CODE)
     {
      string name="";
      //--- Market Watch window event
      string descr=engine.GetMWEventDescription((ENUM_MW_EVENT)idx);
      name=(idx==MARKET_WATCH_EVENT_SYMBOL_SORT ? "" : ": "+sparam);
      Print(TimeMSCtoString(lparam)," ",descr,name);
     }
//--- Handling symbol events
   if(source==COLLECTION_SYMBOLS_ID)
     {
      CSymbol *symbol=engine.GetSymbolObjByName(sparam);
      if(symbol==NULL)
         return;
      //--- Number of decimal places in the event value - in case of a 'long' event, it is 0, otherwise - Digits() of a symbol
      int digits=(idx<SYMBOL_PROP_INTEGER_TOTAL ? 0 : symbol.Digits());
      //--- Event text description
      string id_descr=(idx<SYMBOL_PROP_INTEGER_TOTAL ? symbol.GetPropertyDescription((ENUM_SYMBOL_PROP_INTEGER)idx) : symbol.GetPropertyDescription((ENUM_SYMBOL_PROP_DOUBLE)idx));
      //--- Property change text value
      string value=DoubleToString(dparam,digits);
      //--- Check event reasons and display its description in the journal
      if(reason==BASE_EVENT_REASON_INC)
        {
         Print(symbol.EventDescription(idx,(ENUM_BASE_EVENT_REASON)reason,source,value,id_descr,digits));
        }
      if(reason==BASE_EVENT_REASON_DEC)
        {
         Print(symbol.EventDescription(idx,(ENUM_BASE_EVENT_REASON)reason,source,value,id_descr,digits));
        }
      if(reason==BASE_EVENT_REASON_MORE_THEN)
        {
         Print(symbol.EventDescription(idx,(ENUM_BASE_EVENT_REASON)reason,source,value,id_descr,digits));
        }
      if(reason==BASE_EVENT_REASON_LESS_THEN)
        {
         Print(symbol.EventDescription(idx,(ENUM_BASE_EVENT_REASON)reason,source,value,id_descr,digits));
        }
      if(reason==BASE_EVENT_REASON_EQUALS)
        {
         Print(symbol.EventDescription(idx,(ENUM_BASE_EVENT_REASON)reason,source,value,id_descr,digits));
        }
     }
      
//--- Handling trading events
   if(idx>TRADE_EVENT_NO_EVENT && idx<TRADE_EVENTS_NEXT_CODE)
     {
      event=EnumToString((ENUM_TRADE_EVENT)ushort(idx));
      int 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 increase 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 
                 }
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+


Alle Änderungen werden im Code kommentiert und beziehen sich nur darauf, eine Ereignisbeschreibung aus dem Symbolobjekt zu erhalten und diese je nach Ereignisgrund im Journal anzuzeigen. Fügen Sie in der Nicht-Test-Behandlung die normale Ereignisbehandlung hinzu, anstatt eine Nachricht im Journal anzuzeigen.

Kompilieren und starten Sie den jetzt EA im Tester:

Wie wir sehen können, werden beim Erhöhen oder Verringern eines Spreads über die angegebenen Kontrollwerte hinaus die entsprechenden Einträge an das Journal gesendet. Änderungen des Bid-Preises (Erhöhung oder Senkung um mehr als 10 Punkte) werden auch von Journaleinträgen begleitet. Wenn der Bid-Preis die angegebene Kontrollstufe überschreitet, wird schließlich auch ein Ereignis gesendet und der Journaleintrag angezeigt.

So haben wir das Basisobjekt erstellt, das es uns ermöglicht, Ereignisse von jedem seiner Nachkommenobjekte zu verfolgen und sie an das Steuerungsprogramm zu senden, wo das Programm sie verfolgen und gemäß seiner eingebauten Logik reagieren kann, sowie neue verfolgte Werte und Ebenen einzustellen, die eine flexible Verwaltung der Programmbetriebslogik ermöglichen.

Was kommt als Nächstes?

Im nächsten Artikel werden wir die Arbeit des Konto-Objekts und seiner Ereignisse basierend auf der Ereignisfunktionen 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
Teil 16. Ereignisse der Kollektionssymbole


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

Beigefügte Dateien |
MQL5.zip (218.23 KB)
MQL4.zip (218.22 KB)
Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil XVIII): Interaktivität des Kontos und aller anderen Bibliotheksobjekte Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil XVIII): Interaktivität des Kontos und aller anderen Bibliotheksobjekte
Der Artikel reiht die Arbeit eines Kontoobjekts in ein neues Basisobjekt aller Bibliotheksobjekte ein, verbessert das Basisobjekt CBaseObj und testet die Einstellung von verfolgten Parametern sowie das Empfangen von Ereignissen für alle Bibliotheksobjekte.
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.
Entwicklung des Pivot Mean Oscillators: ein neuartiger Indikator für einen kumulativen gleitenden Durchschnitt Entwicklung des Pivot Mean Oscillators: ein neuartiger Indikator für einen kumulativen gleitenden Durchschnitt
Dieser Artikel stellt den Pivot Mean Oscillator (PMO) vor, eine Implementierung des kumulativen Moving Average (CMA) als Handelsindikator für die MetaTrader-Plattformen. Insbesondere führen wir zunächst Pivot Mean (PM) als Normalisierungsindex für Zeitreihen ein, der den Bruchteil zwischen einem beliebigen Datenpunkt und dem CMA berechnet. Wir bilden dann den PMO als Differenz zwischen den gleitenden Durchschnitten, die auf zwei PM-Signale angewendet werden. Einige erste Experimente, die mit dem EURUSD-Symbol durchgeführt wurden, um die Wirksamkeit des vorgeschlagenen Indikators zu testen, werden ebenfalls besprochen, so dass genügend Raum für weitere Überlegungen und Verbesserungen bleibt.
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.