Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil XIII): Ereignisse des Kontoobjekts

9 September 2019, 09:39
Artyom Trishkin
0
376

Inhalt


Das Konzept der Kontoereignisse

Zuvor haben wir eine separate Klasse erstellt, die Auftrags- und Positionsereignisse verfolgt (Teile IV-XI) und Daten über erkannte Änderungen an das Hauptbibliotheksobjekt CEngine sendet.


Um Kontoereignisse zu verfolgen, werden wir eine andere Methode verwenden: Da wir in der Lage sind, Ereignisse nur auf einem einzigen Konto zu verfolgen (demjenigen, mit dem das Terminal derzeit verbunden ist), wäre eine separate Klasse für diese redundant. Stattdessen werden wir die Methoden für die Arbeit mit Ereignissen direkt in der Klasse der Kollektion der Konten erstellen.
Um Änderungen in den Kontoeigenschaften zu erkennen, werden wir die Eigenschaften des aktuellen Kontos mit ihrem vorherigen Status vergleichen. Werden Änderungen festgestellt, wird ein Ereignis an das Programm auf dem Chart gesendet.
Wir haben bereits im vorherigen Artikel einige Funktionen zur Verfolgung von Ereigniskonten bei der Erstellung der Kontenobjektsammlung entwickelt. In diesem Artikel werden wir die bestehende Funktionalität verbessern, um sie vollständig nutzbar zu machen.


Methoden für die Arbeit mit Kontoereignissen

Beginnen wir damit, die notwendigen Enumerationen und Makroersetzungen in der Datei Defines.mqh zu erstellen. Da die Entwickler die tatsächliche Größe der Zeichenketten der Kontoeigenschaften in Bytes bekanntgegeben haben, werden wir die Größe im Code der Klasse CAccount fest einstellen, wodurch die Notwendigkeit der Makroersetzung entfällt, die die Größe von uchar-Arrays zur Speicherung der Eigenschaften der Zeichenkette des Kontoobjekts festlegt. Entfernen der Makroersetzung aus dem Defines.mqh Listing

#define UCHAR_ARRAY_SIZE            (64)                       // Size of uchar arrays for storing string properties

Ich habe mich auch entschieden, alle notwendigen Enumerationen und Makro-Substitutionen für die Arbeit mit Kontoobjekten ganz am Ende der Datei hinzuzufügen — nach den Daten für die Arbeit mit Handelsereignissen, da wir nicht nur Kontoereignisse, sondern auch implementierte Handelsereignisse an das Programm senden werden. Das bedeutet, dass die Zahlenwerte der Ereigniscodes des Kontos vom Zahlenwert des allerletzten Trading-Ereigniscodes+1 ausgehen sollen. Wenn die Anzahl der Handelsereignisse steigt, deklarieren wir die Makro-Substitution mit der Gesamtzahl aller Handelsereignisse, um die Zahlenwerte der Ereigniscodes des Kontos nicht neu zu schreiben. Außerdem werden wir die Makro-Substitution festlegen, die die Gesamtzahl der Kontoereignisse angibt, falls wir andere Ereignisse (wie Symbolereignisse) implementieren. In diesem Fall beginnen die Zahlencodes dieser neuen Ereignisse mit der Gesamtzahl der Kontoereignisse+1.

Am Ende der Liste der möglichen Handelsgeschehnisse auf dem Konto, einfügen der Makro-Substitution unter Angabe des Wertes, der dem Zahlenwert des letzten Handelsgeschehens+1 entspricht:

//+------------------------------------------------------------------+
//| Liste der möglichen Handelsereignisse auf dem Konto              |
//+------------------------------------------------------------------+
enum ENUM_TRADE_EVENT
  {
   TRADE_EVENT_NO_EVENT = 0,                                // No trading event
   TRADE_EVENT_PENDING_ORDER_PLASED,                        // Pending-Order platziert
   TRADE_EVENT_PENDING_ORDER_REMOVED,                       // Pending-Order entfernt
//--- Mitglieder der Enumeration stimmen mit den Mitgliedern der Enumeration ENUM_DEAL_TYPE überein
//--- (constant order below should not be changed, no constants should be added/deleted)
   TRADE_EVENT_ACCOUNT_CREDIT = DEAL_TYPE_CREDIT,           // Accruing credit (3)
   TRADE_EVENT_ACCOUNT_CHARGE,                              // Weitere Lastschrift
   TRADE_EVENT_ACCOUNT_CORRECTION,                          // Korrekturbuchung
   TRADE_EVENT_ACCOUNT_BONUS,                               // Accruing bonuses
   TRADE_EVENT_ACCOUNT_COMISSION,                           // Zusätzliche Kommission
   TRADE_EVENT_ACCOUNT_COMISSION_DAILY,                     // Commission charged at the end of a trading day
   TRADE_EVENT_ACCOUNT_COMISSION_MONTHLY,                   // Commission charged at the end of a trading month
   TRADE_EVENT_ACCOUNT_COMISSION_AGENT_DAILY,               // Kommission des Agenten belastet am Tagesende
   TRADE_EVENT_ACCOUNT_COMISSION_AGENT_MONTHLY,             // Kommission des Agenten belastet am Monatsende
   TRADE_EVENT_ACCOUNT_INTEREST,                            // Accrued interest on free funds
   TRADE_EVENT_BUY_CANCELLED,                               // Stornierter Kauf-Deal
   TRADE_EVENT_SELL_CANCELLED,                              // Stornierter Verkaufs-Deal
   TRADE_EVENT_DIVIDENT,                                    // Accruing dividends
   TRADE_EVENT_DIVIDENT_FRANKED,                            // Accruing franked dividends
   TRADE_EVENT_TAX                        = DEAL_TAX,       // Tax
//--- constants related to the DEAL_TYPE_BALANCE deal type from the DEAL_TYPE_BALANCE enumeration
   TRADE_EVENT_ACCOUNT_BALANCE_REFILL     = DEAL_TAX+1,     // Replenishing account balance
   TRADE_EVENT_ACCOUNT_BALANCE_WITHDRAWAL = DEAL_TAX+2,     // Withdrawing funds from an account
//--- Remaining possible trading events//--- (constant order below can be changed, constants can be added/deleted)
   TRADE_EVENT_PENDING_ORDER_ACTIVATED    = DEAL_TAX+3,     // Pending order activated by price
   TRADE_EVENT_PENDING_ORDER_ACTIVATED_PARTIAL,             // Pending-Order, teilweise ausgelöst durch den Preis
   TRADE_EVENT_POSITION_OPENED,                             // Position eröffnet
   TRADE_EVENT_POSITION_OPENED_PARTIAL,                     // Position teilweise eröffnet
   TRADE_EVENT_POSITION_CLOSED,                             // Position geschlossen
   TRADE_EVENT_POSITION_CLOSED_BY_POS,                      // Position durch eine entgegengesetzte Position geschlossen
   TRADE_EVENT_POSITION_CLOSED_BY_SL,                       // Position geschlossen duch Stop-Loss
   TRADE_EVENT_POSITION_CLOSED_BY_TP,                       // Position geschlossen durch Take-Profit
   TRADE_EVENT_POSITION_REVERSED_BY_MARKET,                 // Position reversal by a new deal (netting)
   TRADE_EVENT_POSITION_REVERSED_BY_PENDING,                // Position reversal by activating a pending order (netting)
   TRADE_EVENT_POSITION_REVERSED_BY_MARKET_PARTIAL,         // Position reversal by partial market order execution (netting)
   TRADE_EVENT_POSITION_REVERSED_BY_PENDING_PARTIAL,        // Position reversal by partial pending order activation (netting)
   TRADE_EVENT_POSITION_VOLUME_ADD_BY_MARKET,               // Added volume to a position by a new deal (netting)
   TRADE_EVENT_POSITION_VOLUME_ADD_BY_MARKET_PARTIAL,       // Added volume to a position by partial activation of an order (netting)
   TRADE_EVENT_POSITION_VOLUME_ADD_BY_PENDING,              // Added volume to a position by activating a pending order (netting)
   TRADE_EVENT_POSITION_VOLUME_ADD_BY_PENDING_PARTIAL,      // Added volume to a position by partial activation of a pending order (netting)
   TRADE_EVENT_POSITION_CLOSED_PARTIAL,                     // Position teilweise geschlossen
   TRADE_EVENT_POSITION_CLOSED_PARTIAL_BY_POS,              // Position closed partially by an opposite one
   TRADE_EVENT_POSITION_CLOSED_PARTIAL_BY_SL,               // Position teilweise geschlossen duch Stop-Loss
   TRADE_EVENT_POSITION_CLOSED_PARTIAL_BY_TP,               // Position teilweise geschlossen durch Take-Profit
   TRADE_EVENT_TRIGGERED_STOP_LIMIT_ORDER,                  // StopLimit order activation
   TRADE_EVENT_MODIFY_ORDER_PRICE,                          // Changing order price
   TRADE_EVENT_MODIFY_ORDER_PRICE_STOP_LOSS,                // Changing order and StopLoss price 
   TRADE_EVENT_MODIFY_ORDER_PRICE_TAKE_PROFIT,              // Changing order and TakeProfit price
   TRADE_EVENT_MODIFY_ORDER_PRICE_STOP_LOSS_TAKE_PROFIT,    // Changing order, StopLoss and TakeProfit price
   TRADE_EVENT_MODIFY_ORDER_STOP_LOSS_TAKE_PROFIT,          // Changing order's StopLoss and TakeProfit price
   TRADE_EVENT_MODIFY_ORDER_STOP_LOSS,                      // Changing order Stop Loss
   TRADE_EVENT_MODIFY_ORDER_TAKE_PROFIT,                    // Changing order Take Profit
   TRADE_EVENT_MODIFY_POSITION_STOP_LOSS_TAKE_PROFIT,       // Changing position StopLoss and TakeProfit
   TRADE_EVENT_MODIFY_POSITION_STOP_LOSS,                   // Changing position StopLoss
   TRADE_EVENT_MODIFY_POSITION_TAKE_PROFIT,                 // Changing position TakeProfit
  };
#define TRADE_EVENTS_NEXT_CODE      (TRADE_EVENT_MODIFY_POSITION_TAKE_PROFIT+1)// The code of the next event after the last trading event code
//+------------------------------------------------------------------+

Dies ist der Code, von dem aus die Ereigniscodes des Kontos ausgehen sollen.

Im vorherigen Artikel haben wir die Kontoeigenschaften Integer, Double und String sowie mögliche Sortierkriterien für Konten festgelegt und vor die Daten für die Arbeit mit Kontoereignissen gestellt. Jetzt gehen wir zum Ende und stellen zusätzliche Daten für die Arbeit mit Kontoereignissen zur Verfügung — die Liste der Kontoereigniskennzeichen und möglichen Kontoereignisse:

//+------------------------------------------------------------------+
//| Data for working with accounts                                   |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| List of account event flags                                      |
//+------------------------------------------------------------------+
enum ENUM_ACCOUNT_EVENT_FLAGS
  {
   ACCOUNT_EVENT_FLAG_NO_EVENT            =  0,             // No event
   ACCOUNT_EVENT_FLAG_LEVERAGE            =  1,             // Changing the leverage
   ACCOUNT_EVENT_FLAG_LIMIT_ORDERS        =  2,             // Changing the maximum allowed number of active pending orders
   ACCOUNT_EVENT_FLAG_TRADE_ALLOWED       =  4,             // Changing permission to trade for the account
   ACCOUNT_EVENT_FLAG_TRADE_EXPERT        =  8,             // Changing permission for auto trading for the account
   ACCOUNT_EVENT_FLAG_BALANCE             =  16,            // The balance exceeds the specified change value +/-
   ACCOUNT_EVENT_FLAG_EQUITY              =  32,            // The equity exceeds the specified change value +/-
   ACCOUNT_EVENT_FLAG_PROFIT              =  64,            // The profit exceeds the specified change value +/-
   ACCOUNT_EVENT_FLAG_CREDIT              =  128,           // Changing the credit in a deposit currency
   ACCOUNT_EVENT_FLAG_MARGIN              =  256,           // The reserved margin on an account in the deposit currency exceeds the specified change value +/-
   ACCOUNT_EVENT_FLAG_MARGIN_FREE         =  512,           // The free funds available for opening a position in a deposit currency exceed the specified change value +/-
   ACCOUNT_EVENT_FLAG_MARGIN_LEVEL        =  1024,          // The margin level on an account in % exceeds the specified change value +/-
   ACCOUNT_EVENT_FLAG_MARGIN_INITIAL      =  2048,          // The funds reserved on an account to ensure a guarantee amount for all pending orders exceed the specified change value +/-
   ACCOUNT_EVENT_FLAG_MARGIN_MAINTENANCE  =  4096,          // The funds reserved on an account to ensure a minimum amount for all open positions exceed the specified change value +/-
   ACCOUNT_EVENT_FLAG_MARGIN_SO_CALL      =  8192,          // Changing the Margin Call level
   ACCOUNT_EVENT_FLAG_MARGIN_SO_SO        =  16384,         // Changing the Stop Out level
   ACCOUNT_EVENT_FLAG_ASSETS              =  32768,         // The current assets on an account exceed the specified change value +/-
   ACCOUNT_EVENT_FLAG_LIABILITIES         =  65536,         // The current liabilities on an account exceed the specified change value +/-
   ACCOUNT_EVENT_FLAG_COMISSION_BLOCKED   =  131072,        // The current sum of blocked commissions on an account exceeds the specified change value +/-
  };
//+------------------------------------------------------------------+
//| List of possible account events                                  |
//+------------------------------------------------------------------+
enum ENUM_ACCOUNT_EVENT
  {
   ACCOUNT_EVENT_NO_EVENT = TRADE_EVENTS_NEXT_CODE,         // No event
   ACCOUNT_EVENT_LEVERAGE_INC,                              // Increasing the leverage
   ACCOUNT_EVENT_LEVERAGE_DEC,                              // Decreasing the leverage
   ACCOUNT_EVENT_LIMIT_ORDERS_INC,                          // Increasing the maximum allowed number of active pending orders
   ACCOUNT_EVENT_LIMIT_ORDERS_DEC,                          // Decreasing the maximum allowed number of active pending orders
   ACCOUNT_EVENT_TRADE_ALLOWED_ON,                          // Enabling trading for the account
   ACCOUNT_EVENT_TRADE_ALLOWED_OFF,                         // Disabling trading for the account
   ACCOUNT_EVENT_TRADE_EXPERT_ON,                           // Enabling auto trading for the account
   ACCOUNT_EVENT_TRADE_EXPERT_OFF,                          // Disabling auto trading for the account
   ACCOUNT_EVENT_BALANCE_INC,                               // The balance exceeds the specified value
   ACCOUNT_EVENT_BALANCE_DEC,                               // The balance falls below the specified value
   ACCOUNT_EVENT_EQUITY_INC,                                // The equity exceeds the specified value
   ACCOUNT_EVENT_EQUITY_DEC,                                // The equity falls below the specified value
   ACCOUNT_EVENT_PROFIT_INC,                                // The profit exceeds the specified value
   ACCOUNT_EVENT_PROFIT_DEC,                                // The profit falls below the specified value
   ACCOUNT_EVENT_CREDIT_INC,                                // The credit exceeds the specified value
   ACCOUNT_EVENT_CREDIT_DEC,                                // The credit falls below the specified value
   ACCOUNT_EVENT_MARGIN_INC,                                // Increasing the reserved margin on an account in the deposit currency
   ACCOUNT_EVENT_MARGIN_DEC,                                // Decreasing the reserved margin on an account in the deposit currency
   ACCOUNT_EVENT_MARGIN_FREE_INC,                           // Increasing the free funds available for opening a position in a deposit currency
   ACCOUNT_EVENT_MARGIN_FREE_DEC,                           // Decreasing the free funds available for opening a position in a deposit currency
   ACCOUNT_EVENT_MARGIN_LEVEL_INC,                          // Increasing the margin level on an account in %
   ACCOUNT_EVENT_MARGIN_LEVEL_DEC,                          // Decreasing the margin level on an account in %
   ACCOUNT_EVENT_MARGIN_INITIAL_INC,                        // Increasing the funds reserved on an account to ensure a guarantee amount for all pending orders
   ACCOUNT_EVENT_MARGIN_INITIAL_DEC,                        // Decreasing the funds reserved on an account to ensure a guarantee amount for all pending orders
   ACCOUNT_EVENT_MARGIN_MAINTENANCE_INC,                    // Increasing the funds reserved on an account to ensure a minimum amount for all open positions
   ACCOUNT_EVENT_MARGIN_MAINTENANCE_DEC,                    // Decreasing the funds reserved on an account to ensure a minimum amount for all open positions
   ACCOUNT_EVENT_MARGIN_SO_CALL_INC,                        // Increasing the Margin Call level
   ACCOUNT_EVENT_MARGIN_SO_CALL_DEC,                        // Decreasing the Margin Call level
   ACCOUNT_EVENT_MARGIN_SO_SO_INC,                          // Increasing the Stop Out level
   ACCOUNT_EVENT_MARGIN_SO_SO_DEC,                          // Decreasing the Stop Out level
   ACCOUNT_EVENT_ASSETS_INC,                                // Increasing the current asset size on the account
   ACCOUNT_EVENT_ASSETS_DEC,                                // Decreasing the current asset size on the account
   ACCOUNT_EVENT_LIABILITIES_INC,                           // Increasing the current liabilities on the account
   ACCOUNT_EVENT_LIABILITIES_DEC,                           // Decreasing the current liabilities on the account
   ACCOUNT_EVENT_COMISSION_BLOCKED_INC,                     // Increasing the current sum of blocked commissions on an account
   ACCOUNT_EVENT_COMISSION_BLOCKED_DEC,                     // Decreasing the current sum of blocked commissions on an account<
  };
#define ACCOUNT_EVENTS_NEXT_CODE       (ACCOUNT_EVENT_COMISSION_BLOCKED_DEC+1)   // The code of the next event after the last account event code
//+------------------------------------------------------------------+
//| Account integer properties                                       |
//+------------------------------------------------------------------+
enum ENUM_ACCOUNT_PROP_INTEGER
  {
   ACCOUNT_PROP_LOGIN,                                      // Account number
   ACCOUNT_PROP_TRADE_MODE,                                 // Trading account type
   ACCOUNT_PROP_LEVERAGE,                                   // Provided leverage
   ACCOUNT_PROP_LIMIT_ORDERS,                               // Maximum allowed number of active pending orders
   ACCOUNT_PROP_MARGIN_SO_MODE,                             // Mode of setting the minimum available margin level
   ACCOUNT_PROP_TRADE_ALLOWED,                              // Permission to trade for the current account from the server side
   ACCOUNT_PROP_TRADE_EXPERT,                               // Permission to trade for an EA from the server side
   ACCOUNT_PROP_MARGIN_MODE,                                // Margin calculation mode
   ACCOUNT_PROP_CURRENCY_DIGITS,                            // Number of digits for an account currency necessary for accurate display of trading results
   ACCOUNT_PROP_SERVER_TYPE                                 // Trade server type (MetaTrader 5, MetaTrader 4)
  };
#define ACCOUNT_PROP_INTEGER_TOTAL    (10)                  // Total number of account's integer properties
#define ACCOUNT_PROP_INTEGER_SKIP     (0)                   // Number of account's integer properties not used in sorting
//+------------------------------------------------------------------+
//| Account real properties                                          |
//+------------------------------------------------------------------+
enum ENUM_ACCOUNT_PROP_DOUBLE
  {
   ACCOUNT_PROP_BALANCE = ACCOUNT_PROP_INTEGER_TOTAL,       // Account balance in a deposit currency
   ACCOUNT_PROP_CREDIT,                                     // Credit in a deposit currency
   ACCOUNT_PROP_PROFIT,                                     // Current profit on an account in the account currency
   ACCOUNT_PROP_EQUITY,                                     // Equity on an account in the deposit currency
   ACCOUNT_PROP_MARGIN,                                     // Reserved margin on an account in a deposit currency
   ACCOUNT_PROP_MARGIN_FREE,                                // Free funds available for opening a position in a deposit currency
   ACCOUNT_PROP_MARGIN_LEVEL,                               // Margin level on an account in %
   ACCOUNT_PROP_MARGIN_SO_CALL,                             // Margin Call level
   ACCOUNT_PROP_MARGIN_SO_SO,                               // Stop Out level
   ACCOUNT_PROP_MARGIN_INITIAL,                             // Funds reserved on an account to ensure a guarantee amount for all pending orders 
   ACCOUNT_PROP_MARGIN_MAINTENANCE,                         // Funds reserved on an account to ensure a minimum amount for all open positions
   ACCOUNT_PROP_ASSETS,                                     // Current assets on an account
   ACCOUNT_PROP_LIABILITIES,                                // Current liabilities on an account
   ACCOUNT_PROP_COMMISSION_BLOCKED                          // Current sum of blocked commissions on an account
  };
#define ACCOUNT_PROP_DOUBLE_TOTAL     (14)                  // Total number of account's real properties
#define ACCOUNT_PROP_DOUBLE_SKIP      (0)                   // Number of account's real properties not used in sorting
//+------------------------------------------------------------------+
//| Account string properties                                        |
//+------------------------------------------------------------------+
enum ENUM_ACCOUNT_PROP_STRING
  {
   ACCOUNT_PROP_NAME = (ACCOUNT_PROP_INTEGER_TOTAL+ACCOUNT_PROP_DOUBLE_TOTAL), // Client name
   ACCOUNT_PROP_SERVER,                                     // Trade server name
   ACCOUNT_PROP_CURRENCY,                                   // Deposit currency
   ACCOUNT_PROP_COMPANY                                     // Name of a company serving an account
  };
#define ACCOUNT_PROP_STRING_TOTAL     (4)                   // Total number of account's string properties
#define ACCOUNT_PROP_STRING_SKIP      (0)                   // Number of account string properties not used in sorting
//+------------------------------------------------------------------+
//| Possible account sorting criteria                                |
//+------------------------------------------------------------------+
#define FIRST_ACC_DBL_PROP            (ACCOUNT_PROP_INTEGER_TOTAL-ACCOUNT_PROP_INTEGER_SKIP)
#define FIRST_ACC_STR_PROP            (ACCOUNT_PROP_INTEGER_TOTAL-ACCOUNT_PROP_INTEGER_SKIP+ACCOUNT_PROP_DOUBLE_TOTAL-ACCOUNT_PROP_DOUBLE_SKIP)
enum ENUM_SORT_ACCOUNT_MODE
  {
   SORT_BY_ACCOUNT_LOGIN               =  0,                      // Sort by account number
   SORT_BY_ACCOUNT_TRADE_MODE          =  1,                      // Sort by trading account type
   SORT_BY_ACCOUNT_LEVERAGE            =  2,                      // Sort by leverage
   SORT_BY_ACCOUNT_LIMIT_ORDERS        =  3,                      // Sort by maximum acceptable number of existing pending orders
   SORT_BY_ACCOUNT_MARGIN_SO_MODE      =  4,                      // Sort by mode for setting the minimum acceptable margin level
   SORT_BY_ACCOUNT_TRADE_ALLOWED       =  5,                      // Sort by permission to trade for the current account
   SORT_BY_ACCOUNT_TRADE_EXPERT        =  6,                      // Sort by permission to trade for an EA
   SORT_BY_ACCOUNT_MARGIN_MODE         =  7,                      // Sort by margin calculation mode
   SORT_BY_ACCOUNT_CURRENCY_DIGITS     =  8,                      // Sort by number of digits for an account currency
   SORT_BY_ACCOUNT_SERVER_TYPE         =  9,                      // Sort by trade server type (MetaTrader 5, MetaTrader 4)
    
   SORT_BY_ACCOUNT_BALANCE             =  FIRST_ACC_DBL_PROP,     // Sort by an account balance in the deposit currency
   SORT_BY_ACCOUNT_CREDIT              =  FIRST_ACC_DBL_PROP+1,   // Sort by credit in a deposit currency
   SORT_BY_ACCOUNT_PROFIT              =  FIRST_ACC_DBL_PROP+2,   // Sort by the current profit on an account in the deposit currency
   SORT_BY_ACCOUNT_EQUITY              =  FIRST_ACC_DBL_PROP+3,   // Sort by an account equity in the deposit currency
   SORT_BY_ACCOUNT_MARGIN              =  FIRST_ACC_DBL_PROP+4,   // Sort by an account reserved margin in the deposit currency
   SORT_BY_ACCOUNT_MARGIN_FREE         =  FIRST_ACC_DBL_PROP+5,   // Sort by account free funds available for opening a position in the deposit currency
   SORT_BY_ACCOUNT_MARGIN_LEVEL        =  FIRST_ACC_DBL_PROP+6,   // Sort by account margin level in %
   SORT_BY_ACCOUNT_MARGIN_SO_CALL      =  FIRST_ACC_DBL_PROP+7,   // Sort by margin level requiring depositing funds to an account (Margin Call)
   SORT_BY_ACCOUNT_MARGIN_SO_SO        =  FIRST_ACC_DBL_PROP+8,   // Sort by margin level, at which the most loss-making position is closed (Stop Out)
   SORT_BY_ACCOUNT_MARGIN_INITIAL      =  FIRST_ACC_DBL_PROP+9,   // Sort by funds reserved on an account to ensure a guarantee amount for all pending orders 
   SORT_BY_ACCOUNT_MARGIN_MAINTENANCE  =  FIRST_ACC_DBL_PROP+10,  // Sort by funds reserved on an account to ensure a minimum amount for all open positions
   SORT_BY_ACCOUNT_ASSETS              =  FIRST_ACC_DBL_PROP+11,  // Sort by the amount of the current assets on an account
   SORT_BY_ACCOUNT_LIABILITIES         =  FIRST_ACC_DBL_PROP+12,  // Sort by the current liabilities on an account
   SORT_BY_ACCOUNT_COMMISSION_BLOCKED  =  FIRST_ACC_DBL_PROP+13,  // Sort by the current amount of blocked commissions on an account

   SORT_BY_ACCOUNT_NAME                =  FIRST_ACC_STR_PROP,     // Sort by a client name
   SORT_BY_ACCOUNT_SERVER              =  FIRST_ACC_STR_PROP+1,   // Sort by a trade server name
   SORT_BY_ACCOUNT_CURRENCY            =  FIRST_ACC_STR_PROP+2,   // Sort by a deposit currency
   SORT_BY_ACCOUNT_COMPANY             =  FIRST_ACC_STR_PROP+3    // Sort by a name of a company serving an account
  };
//+------------------------------------------------------------------+

Da sich mehrere Kontoeigenschaften gleichzeitig ändern können, werden wir mit einer Reihe von Ereignis-Flags arbeiten, um nicht eine einzige der aufgetretenen Änderungen zu verpassen. Die Flags werden einer Variable des Ereigniscodes hinzugefügt. Dann wird das Vorhandensein eines bestimmten Flags innerhalb der Variable überprüft. Basierend auf den Flags, die im Ereigniscode vorhanden sind, definieren wir, was genau in den Kontoeigenschaften passiert ist. Alle erkannten Ereignisse sind im Array zu speichern. Die Zugriffsmöglichkeit ist in der Klasse CEngine und später im Programm bereitzustellen.

Wie Sie sehen können, bietet die Liste der ganzzahligen Kontoeigenschaften eine weitere Eigenschaft — trade server type. Dementsprechend wurde die Gesamtzahl der ganzzahligen Eigenschaften von 9 auf 10 geändert.
Diese Kontoeigenschaft dient dazu, zu definieren, ob ein Konto zu MetaTrader 5 oder MetaTrader 4 gehört. Ich habe mich entschieden, die Eigenschaft hinzuzufügen, weil die Liste aller Konten, mit denen das Programm jemals verbunden war, alle Konten erhält — sowohl MetaTrader 5 als auch MetaTrader 4, wenn das bibliotheksbasierte Programm in beiden Terminals gestartet wird. Die Eigenschaft erlaubt es uns, die Typen der Handelsserver zu unterscheiden. Sie soll in der im Journal durch die Methoden PrintShort() der Klasse CAccount angezeigten Kontenbeschreibung vorhanden sein. Außerdem sind wir in der Lage, Kontoobjekte nach der Plattform zu sortieren, zu der sie gehören.

Kommen wir nun zur Datei Acount.mqh. Fügen wir die neue Eigenschaft hinzu und setzen die genaue Größe der Arrays zum Speichern der String-Eigenschaften des Kontos im 'private' Bereich der Kontodatenstruktur:

//+------------------------------------------------------------------+
//| Account class                                                    |
//+------------------------------------------------------------------+
class CAccount : public CObject
  {
private:
   struct SData
     {
      //--- Account integer properties
      long           login;                        // ACCOUNT_LOGIN (Account number)
      int            trade_mode;                   // ACCOUNT_TRADE_MODE (Trading account type)
      long           leverage;                     // ACCOUNT_LEVERAGE (Leverage)
      int            limit_orders;                 // ACCOUNT_LIMIT_ORDERS (Maximum allowed number of active pending orders)
      int            margin_so_mode;               // ACCOUNT_MARGIN_SO_MODE (Mode of setting the minimum available margin level)
      bool           trade_allowed;                // ACCOUNT_TRADE_ALLOWED (Permission to trade for the current account from the server side)
      bool           trade_expert;                 // ACCOUNT_TRADE_EXPERT (Permission to trade for an EA from the server side)
      int            margin_mode;                  // ACCOUNT_MARGIN_MODE (Margin calculation mode)
      int            currency_digits;              // ACCOUNT_CURRENCY_DIGITS (Number of digits for an account currency)
      int            server_type;                  // Trade server type (MetaTrader 5, MetaTrader 4)
      //--- Account real properties
      double         balance;                      // ACCOUNT_BALANCE (Account balance in the deposit currency)
      double         credit;                       // ACCOUNT_CREDIT (Credit in the deposit currency)
      double         profit;                       // ACCOUNT_PROFIT (Current profit on an account in the deposit currency)
      double         equity;                       // ACCOUNT_EQUITY (Equity on an account in the deposit currency)
      double         margin;                       // ACCOUNT_MARGIN (Reserved margin on an account in the deposit currency)
      double         margin_free;                  // ACCOUNT_MARGIN_FREE (Free funds available for opening a position in the deposit currency)
      double         margin_level;                 // ACCOUNT_MARGIN_LEVEL (Margin level on an account in %)
      double         margin_so_call;               // ACCOUNT_MARGIN_SO_CALL (Margin Call level)
      double         margin_so_so;                 // ACCOUNT_MARGIN_SO_SO (Stop Out level)
      double         margin_initial;               // ACCOUNT_MARGIN_INITIAL (Funds reserved on an account to ensure a guarantee amount for all pending orders)
      double         margin_maintenance;           // ACCOUNT_MARGIN_MAINTENANCE (Funds reserved on an account to ensure a minimum amount for all open positions)
      double         assets;                       // ACCOUNT_ASSETS (Current assets on an account)
      double         liabilities;                  // ACCOUNT_LIABILITIES (Current liabilities on an account)
      double         comission_blocked;            // ACCOUNT_COMMISSION_BLOCKED (Current sum of blocked commissions on an account)
      //--- Account string properties
      uchar          name[128];                    // ACCOUNT_NAME (Client name)
      uchar          server[64];                   // ACCOUNT_SERVER (Trade server name)
      uchar          currency[32];                 // ACCOUNT_CURRENCY (Deposit currency)
      uchar          company[128];                 // ACCOUNT_COMPANY (Name of a company serving an account)
     };
   SData             m_struct_obj;                                      // Account object structure
   uchar             m_uchar_array[];                                   // uchar array of the account object structure

Fügen Sie im 'public' Bereich der Klasse eine weitere Methode für einen vereinfachten Zugriff auf die Eigenschaften der Kontoobjekte hinzu, die den Handelsservertyp zurückgibt:

//+------------------------------------------------------------------+
//| Methods of a simplified access to the account object properties  |
//+------------------------------------------------------------------+
//--- Return the account's integer propertie
   ENUM_ACCOUNT_TRADE_MODE    TradeMode(void)                     const { return (ENUM_ACCOUNT_TRADE_MODE)this.GetProperty(ACCOUNT_PROP_TRADE_MODE);       }
   ENUM_ACCOUNT_STOPOUT_MODE  MarginSOMode(void)                  const { return (ENUM_ACCOUNT_STOPOUT_MODE)this.GetProperty(ACCOUNT_PROP_MARGIN_SO_MODE); }
   ENUM_ACCOUNT_MARGIN_MODE   MarginMode(void)                    const { return (ENUM_ACCOUNT_MARGIN_MODE)this.GetProperty(ACCOUNT_PROP_MARGIN_MODE);     }
   long              Login(void)                                  const { returnthis.GetProperty(ACCOUNT_PROP_LOGIN);                                      }
   long              Leverage(void)                               const { returnthis.GetProperty(ACCOUNT_PROP_LEVERAGE);                                   }
   long              LimitOrders(void)                            const { returnthis.GetProperty(ACCOUNT_PROP_LIMIT_ORDERS);                               }
   long              TradeAllowed(void)                           const { returnthis.GetProperty(ACCOUNT_PROP_TRADE_ALLOWED);                              }
   long              TradeExpert(void)                            const { returnthis.GetProperty(ACCOUNT_PROP_TRADE_EXPERT);                               }
   long              CurrencyDigits(void)                         const { returnthis.GetProperty(ACCOUNT_PROP_CURRENCY_DIGITS);                            }
   long              ServerType(void)                             const { returnthis.GetProperty(ACCOUNT_PROP_SERVER_TYPE);                                }

Fügen Sie in den Methoden der Beschreibung der Kontoeigenschaften eine weitere Methode hinzu, die die Beschreibung des Handelsservertyps zurückgibt:

//+------------------------------------------------------------------+
//| Descriptions of the account object properties                    |
//+------------------------------------------------------------------+
//--- Return the description of the account's (1) integer, (2) real and (3) string properties
   string            GetPropertyDescription(ENUM_ACCOUNT_PROP_INTEGER property);
   string            GetPropertyDescription(ENUM_ACCOUNT_PROP_DOUBLE property);
   string            GetPropertyDescription(ENUM_ACCOUNT_PROP_STRING property);
//--- Return the trading account type name (demo, contest, real)
   string            TradeModeDescription(void)    const;
//--- Return the trade server type name (MetaTrader 5, MetaTrader 4)
   string            ServerTypeDescription(void)    const;
//--- Return the description of the mode for setting the minimum available margin level
   string            MarginSOModeDescription(void) const;
//--- Return the description of the margin calculation mode
   string            MarginModeDescription(void)   const;
//--- Display the description of the account properties in the journal (full_prop=true - all properties, false - supported ones only)
   void              Print(constbool full_prop=false);
//--- Display a short account description in the journal
   void              PrintShort(void);

Tragen Sie im Klassenkonstruktor die Eigenschaft ein, die den Typ des Handelsservers speichert:

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

Hier lesen wir einfach den Terminalnamen. Wenn dies MetaTrader 5 ist, tragen Sie 5 ein, ansonsten 4.

Fügen Sie das Einfügen der neuen Eigenschaft der Methode ObjectToStruct() zum Erstellen einer Objektstruktur hinzu:

//+------------------------------------------------------------------+
//| Create the account object structure                              |
//+------------------------------------------------------------------+
bool CAccount::ObjectToStruct(void)
  {
//--- Save the integer properties
   this.m_struct_obj.login=this.Login();
   this.m_struct_obj.trade_mode=this.TradeMode();
   this.m_struct_obj.leverage=this.Leverage();
   this.m_struct_obj.limit_orders=(int)this.LimitOrders();
   this.m_struct_obj.margin_so_mode=this.MarginSOMode();
   this.m_struct_obj.trade_allowed=this.TradeAllowed();
   this.m_struct_obj.trade_expert=this.TradeExpert();
   this.m_struct_obj.margin_mode=this.MarginMode();
   this.m_struct_obj.currency_digits=(int)this.CurrencyDigits();
   this.m_struct_obj.server_type=(int)this.ServerType();
//--- Save the real properties
   this.m_struct_obj.balance=this.Balance();
   this.m_struct_obj.credit=this.Credit();
   this.m_struct_obj.profit=this.Profit();
   this.m_struct_obj.equity=this.Equity();
   this.m_struct_obj.margin=this.Margin();
   this.m_struct_obj.margin_free=this.MarginFree();
   this.m_struct_obj.margin_level=this.MarginLevel();
   this.m_struct_obj.margin_so_call=this.MarginSOCall();
   this.m_struct_obj.margin_so_so=this.MarginSOSO();
   this.m_struct_obj.margin_initial=this.MarginInitial();
   this.m_struct_obj.margin_maintenance=this.MarginMaintenance();
   this.m_struct_obj.assets=this.Assets();
   this.m_struct_obj.liabilities=this.Liabilities();
   this.m_struct_obj.comission_blocked=this.ComissionBlocked();
//--- Save the string properties
   ::StringToCharArray(this.Name(),this.m_struct_obj.name);
   ::StringToCharArray(this.Server(),this.m_struct_obj.server);
   ::StringToCharArray(this.Currency(),this.m_struct_obj.currency);
   ::StringToCharArray(this.Company(),this.m_struct_obj.company);
   //--- Save the structure to the uchar array
   ::ResetLastError();
   if(!::StructToCharArray(this.m_struct_obj,this.m_uchar_array))
     {
      ::Print(DFUN,TextByLanguage("Не удалось сохранить структуру объекта в uchar-массив, ошибка ","Failed to save object structure to uchar array, error "),(string)::GetLastError());
      returnfalse;
     }
   returntrue;
  }
//+------------------------------------------------------------------+

während die Methode zum Erzeugen eines Objekts aus der Struktur StructToObject() die enthaltene Eigenschaft aus der Struktur erhält:

//+------------------------------------------------------------------+
//| Create the account object from the structure                     |
//+------------------------------------------------------------------+
void CAccount::StructToObject(void)
  {
//--- Sichern der ganzzahligen Eigenschaften
   this.m_long_prop[ACCOUNT_PROP_LOGIN]                              = this.m_struct_obj.login;
   this.m_long_prop[ACCOUNT_PROP_TRADE_MODE]                         = this.m_struct_obj.trade_mode;
   this.m_long_prop[ACCOUNT_PROP_LEVERAGE]                           = this.m_struct_obj.leverage;
   this.m_long_prop[ACCOUNT_PROP_LIMIT_ORDERS]                       = this.m_struct_obj.limit_orders;
   this.m_long_prop[ACCOUNT_PROP_MARGIN_SO_MODE]                     = this.m_struct_obj.margin_so_mode;
   this.m_long_prop[ACCOUNT_PROP_TRADE_ALLOWED]                      = this.m_struct_obj.trade_allowed;
   this.m_long_prop[ACCOUNT_PROP_TRADE_EXPERT]                       = this.m_struct_obj.trade_expert;
   this.m_long_prop[ACCOUNT_PROP_MARGIN_MODE]                        = this.m_struct_obj.margin_mode;
   this.m_long_prop[ACCOUNT_PROP_CURRENCY_DIGITS]                    = this.m_struct_obj.currency_digits;
   this.m_long_prop[ACCOUNT_PROP_SERVER_TYPE]                        = this.m_struct_obj.server_type;
//--- Sichern der Double-Eigenschaften
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_BALANCE)]          = this.m_struct_obj.balance;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_CREDIT)]           = this.m_struct_obj.credit;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_PROFIT)]           = this.m_struct_obj.profit;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_EQUITY)]           = this.m_struct_obj.equity;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN)]           = this.m_struct_obj.margin;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_FREE)]      = this.m_struct_obj.margin_free;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_LEVEL)]     = this.m_struct_obj.margin_level;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_CALL)]   = this.m_struct_obj.margin_so_call;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_SO)]     = this.m_struct_obj.margin_so_so;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_INITIAL)]   = this.m_struct_obj.margin_initial;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_MAINTENANCE)]=this.m_struct_obj.margin_maintenance;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_ASSETS)]           = this.m_struct_obj.assets;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_LIABILITIES)]      = this.m_struct_obj.liabilities;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_COMMISSION_BLOCKED)]=this.m_struct_obj.comission_blocked;
//--- Sichern der String-Eigenschaften
   this.m_string_prop[this.IndexProp(ACCOUNT_PROP_NAME)]             = ::CharArrayToString(this.m_struct_obj.name);
   this.m_string_prop[this.IndexProp(ACCOUNT_PROP_SERVER)]           = ::CharArrayToString(this.m_struct_obj.server);
   this.m_string_prop[this.IndexProp(ACCOUNT_PROP_CURRENCY)]         = ::CharArrayToString(this.m_struct_obj.currency);
   this.m_string_prop[this.IndexProp(ACCOUNT_PROP_COMPANY)]          = ::CharArrayToString(this.m_struct_obj.company);
  }
//+------------------------------------------------------------------+

Fügen Sie nun die Anzeige des Handelsservertyps in der Methode zur Anzeige von Kurzbeschreibungen der Kontoeigenschaften: hinzu.

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

Hinzufügen der neuen Eigenschaftsbeschreibung zu der Methode, die die Beschreibung der Integer-Eigenschaften des Kontos zurückgibt:

//+------------------------------------------------------------------+
//| Display a description of an account integer property             |
//+------------------------------------------------------------------+
string CAccount::GetPropertyDescription(ENUM_ACCOUNT_PROP_INTEGER property)
  {
   return
     (
      property==ACCOUNT_PROP_LOGIN           ?  TextByLanguage("Номер счёта","Account number")+": "+(string)this.GetProperty(property)                                                    :
      property==ACCOUNT_PROP_TRADE_MODE      ?  TextByLanguage("Тип торгового счета","Account trade mode")+": "+this.TradeModeDescription()                                               :
      property==ACCOUNT_PROP_LEVERAGE        ?  TextByLanguage("Размер предоставленного плеча","Account leverage")+": "+(string)this.GetProperty(property) :
      property==ACCOUNT_PROP_LIMIT_ORDERS    ?  TextByLanguage("Максимально допустимое количество действующих отложенных ордеров","Maximum allowed number of active pending orders")+": "+
                                                   (string)this.GetProperty(property)                                                                                                     :
      property==ACCOUNT_PROP_MARGIN_SO_MODE  ?  TextByLanguage("Режим задания минимально допустимого уровня залоговых средств","Mode for setting the minimal allowed margin")+": "+
                                                   this.MarginSOModeDescription()                                                          :
      property==ACCOUNT_PROP_TRADE_ALLOWED   ?  TextByLanguage("Разрешенность торговли для текущего счета","Allowed trade for the current account")+": "+
                                                   (this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))                                                 :
      property==ACCOUNT_PROP_TRADE_EXPERT    ?  TextByLanguage("Разрешенность торговли для эксперта","Allowed trade for an Expert Advisor")+": "+
                                                   (this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))                                                 :
      property==ACCOUNT_PROP_MARGIN_MODE     ?  TextByLanguage("Режим расчета маржи","Margin calculation mode")+": "+
                                                   this.MarginModeDescription()                                                         :
      property==ACCOUNT_PROP_CURRENCY_DIGITS ?  TextByLanguage("Количество знаков после запятой для валюты счета","Number of decimal places in account currency")+": "+
                                                   (string)this.GetProperty(property)                                                                                                     :
      property==ACCOUNT_PROP_SERVER_TYPE     ?  TextByLanguage("Тип торгового сервера","Type of trading server")+": "+
                                                   (string)this.GetProperty(property)                                                                                                     :
      ""
     );
  }
//+------------------------------------------------------------------+

Implementieren Sie die Methode, die den Namen des Typs des Handelsservers zurückgibt:

//+------------------------------------------------------------------+
//| Return the trading server type name                              |
//+------------------------------------------------------------------+
string CAccount::ServerTypeDescription(void) const
  {
   return(this.ServerType()==5 ? "MetaTrader5" : "MetaTrader4");
  }
//+------------------------------------------------------------------+

Damit ist die Verbesserung der Klasse CAccount abgeschlossen.

Nun lasst uns die notwendigen Änderungen an der Klasse der Kontenerhebung vornehmen, da wir beschlossen haben, Ereignisse aus der Klasse CAccountCollection zu verfolgen. Alle gefundenen Änderungen, die gleichzeitig aufgetreten sind, werden in das int-Array geschrieben. Um dies zu erreichen, verwenden wir die fertige Klasse des dynamischen Arrays der Variablen vom Typ int oder uint der Standardbibliothek CArrayInt.

Um sie zu verwenden, binden wir die Klassendatei in die Bibliotheksdatei AccountsCollection.mqh ein:

//+------------------------------------------------------------------+
//|                                           AccountsCollection.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/de/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright"Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/de/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include-Dateien                                                  |
//+------------------------------------------------------------------+
#include <Arrays\ArrayInt.mqh>
#include "ListObj.mqh"
#include "..\Services\Select.mqh"
#include "..\Objects\Accounts\Account.mqh"
//+------------------------------------------------------------------+
//| Account collection                                               |
//+------------------------------------------------------------------+
class CAccountsCollection : public CListObj
  {

Wir müssen entscheiden, was wir wollen. Wir müssen die Momente kennen, in denen sich einige Kontoeigenschaften geändert haben. Eine Eigenschaft kann aktiviert oder deaktiviert werden — zum Beispiel die Erlaubnis, auf einem Konto im Allgemeinen zu handeln oder EAs für den Handel zu verwenden. Wir müssen wissen, ob sich diese Eigenschaft geändert hat. Auf die gleiche Weise kann die Änderung des MarginCall oder StopOut-Levels die EA-Effizienz bei der Aufrechterhaltung eines Drawdowns usw. beeinflussen. Außerdem müssen wir auch die Zunahme und Abnahme der Geldmittel und des Saldos verfolgen, um bestimmte EA-bezogene Entscheidungen zu treffen.

Beispielsweise gibt es eine bestimmte Anzahl offener Positionen, und wir wollen einige von ihnen schließen, wenn ein positiver oder negativer Betrag erreicht wurde. Erstens müssen wir einen bestimmten Schwellenwert festlegen, bei dessen Überschreitung ein Ereignis erzeugt wird. Als Nächstes müssen wir eine bestimmte Entscheidung treffen, je nachdem, ob wir mit Wachstum oder Rückgang der Mittel über/unter dem angegebenen Wert konfrontiert sind. Die gleiche Logik gilt für den aktuellen Gewinn auf einem Konto, Saldo, freie Marge und Einlagenbelastung.

So müssen wir für einige Eigenschaften Schwellenwerte für Über-/Unterschreiten und den aktuellen Eigenschaftswert haben, während wir für andere nur den Wert benötigen, der aktiviert/deaktiviert oder geändert/unverändert werden kann.

Fügen Sie alle notwendigen Klassenvariablen zum 'private' Bereich der Klasse hinzu, um die Auf-/Abwärtswerte der verfolgten Eigenschaften und deren aktuelle Werte zu speichern, entfernen Sie die Methode SavePrevValues(), die sich als redundant erwiesen hat und fügen Sie die Methoden zur Initialisierung der verfolgten und kontrollierten Kontodaten hinzu, das Verfahren zum Überprüfen von Kontoänderungen und Rückgabe eines Änderungscodes, das Verfahren zum Einstellen des Ereignistyps und Füllen der Ereignisliste und schließlich das Verfahren zum Rückgeben des Flags im Kontoereignis:

//--- Save the current data status values of the current account as previous ones
   void              SavePrevValues(void)
//+------------------------------------------------------------------+
//| Account collection                                               |
//+------------------------------------------------------------------+
class CAccountsCollection : public CListObj
  {
private:
   struct MqlDataAccount
     {
      double         hash_sum;               // Account data hash sum
      //--- Account integer properties
      long           login;                  // ACCOUNT_LOGIN (Account number)
      long           leverage;               // ACCOUNT_LEVERAGE (Leverage)
      int            limit_orders;           // ACCOUNT_LIMIT_ORDERS (Maximum allowed number of active pending orders)
      bool           trade_allowed;          // ACCOUNT_TRADE_ALLOWED (Permission to trade for the current account from the server side)
      bool           trade_expert;           // ACCOUNT_TRADE_EXPERT (Permission to trade for an EA from the server side)
      //--- Account real properties
      double         balance;                // ACCOUNT_BALANCE (Account balance in a deposit currency)
      double         credit;                 // ACCOUNT_CREDIT (Credit in a deposit currency)
      double         profit;                 // ACCOUNT_PROFIT (Current profit on an account in the account currency)
      double         equity;                 // ACCOUNT_EQUITY (Equity on an account in the deposit currency)
      double         margin;                 // ACCOUNT_MARGIN (Reserved margin on an account in a deposit currency)
      double         margin_free;            // ACCOUNT_MARGIN_FREE (Free funds available for opening a position in a deposit currency)
      double         margin_level;           // ACCOUNT_MARGIN_LEVEL (Margin level on an account in %)
      double         margin_so_call;         // ACCOUNT_MARGIN_SO_CALL (Margin Call)
      double         margin_so_so;           // ACCOUNT_MARGIN_SO_SO (Stop Out)
      double         margin_initial;         // ACCOUNT_MARGIN_INITIAL (Funds reserved on an account to ensure a guarantee amount for all pending orders)
      double         margin_maintenance;     // ACCOUNT_MARGIN_MAINTENANCE (Funds reserved on an account to ensure a minimum amount for all open positions)
      double         assets;                 // ACCOUNT_ASSETS (Current assets on an account)
      double         liabilities;            // ACCOUNT_LIABILITIES (Current liabilities on an account)
      double         comission_blocked;      // ACCOUNT_COMMISSION_BLOCKED (Current sum of blocked commissions on an account)
     };
   MqlDataAccount    m_struct_curr_account;              // Account current data
   MqlDataAccount    m_struct_prev_account;              // Account previous data
   
   MqlTick           m_tick;                             // Tick structure
   string            m_symbol;                           // Current symbol
   long              m_chart_id;                         // Control program chart ID
   CListObj          m_list_accounts;                    // Account object list
   CArrayInt         m_list_changes;                     // Account change list
   string            m_folder_name;                      // Name of the folder storing the account objects
   int               m_index_current;                    // Index of an account object featuring the current account data
//--- Tracking account changes
   bool              m_is_account_event;                 // Event flag in the account data
   int               m_change_code;                      // Account change code
   //--- Leverage
   long              m_changed_leverage_value;           // Leverage change value
   bool              m_is_change_leverage_inc;           // Leverage increase flag
   bool              m_is_change_leverage_dec;           // Leverage decrease flag
   //--- Number of active pending orders
   int               m_changed_limit_orders_value;       // Change value of the maximum allowed number of active pending orders
   bool              m_is_change_limit_orders_inc;       // Increase flag of the maximum allowed number of active pending orders
   bool              m_is_change_limit_orders_dec;       // Decrease flag of the maximum allowed number of active pending orders
   //--- Trading on an account
   bool              m_is_change_trade_allowed_on;       // The flag allowing to trade for the current account from the server side
   bool              m_is_change_trade_allowed_off;      // The flag prohibiting trading for the current account from the server side
   //--- Auto trading on an account
   bool              m_is_change_trade_expert_on;        // The flag allowing to trade for an EA from the server side
   bool              m_is_change_trade_expert_off;       //The flag prohibiting trading for an EA from the server side
   //--- Balance
   double            m_control_balance_inc;              // Tracked balance growth value
   double            m_control_balance_dec;              // Tracked balance decrease value
   double            m_changed_balance_value;            // Balance change value
   bool              m_is_change_balance_inc;            // The flag of the balance change exceeding the growth value
   bool              m_is_change_balance_dec;            // The flag of the balance change exceeding the decrease value
   //--- Credit
   double            m_changed_credit_value;             // Credit change value
   bool              m_is_change_credit_inc;             // Credit increase flag
   bool              m_is_change_credit_dec;             // Credit decrease flag
   //--- Profit
   double            m_control_profit_inc;               // Tracked profit growth value
   double            m_control_profit_dec;               // Tracked profit decrease value
   double            m_changed_profit_value;             // Profit change value
   bool              m_is_change_profit_inc;             // The flag of the profit change exceeding the growth value
   bool              m_is_change_profit_dec;             // The flag of the profit change exceeding the decrease value
   //--- Funds (equity)
   double            m_control_equity_inc;               // Tracked funds growth value
   double            m_control_equity_dec;               // Tracked funds decrease value
   double            m_changed_equity_value;             // Funds change value
   bool              m_is_change_equity_inc;             // The flag of the funds change exceeding the growth value
   bool              m_is_change_equity_dec;             // The flag of the funds change exceeding the decrease value
   //--- Margin
   double            m_control_margin_inc;               // Tracked margin growth value
   double            m_control_margin_dec;               // Tracked margin decrease value
   double            m_changed_margin_value;             // Margin change value
   bool              m_is_change_margin_inc;             // The flag of the margin change exceeding the growth value
   bool              m_is_change_margin_dec;             // The flag of the margin change exceeding the decrease value
   //--- Free margin
   double            m_control_margin_free_inc;          // Tracked free margin growth value
   double            m_control_margin_free_dec;          // Tracked free margin decrease value<
   double            m_changed_margin_free_value;        // Free margin change value
   bool              m_is_change_margin_free_inc;        // The flag of the free margin change exceeding the growth value
   bool              m_is_change_margin_free_dec;        // The flag of the free margin change exceeding the decrease value
   //--- Margin level
   double            m_control_margin_level_inc;         // Tracked margin level growth value
   double            m_control_margin_level_dec;         // Tracked margin level decrease value
   double            m_changed_margin_level_value;       // Margin level change value
   bool              m_is_change_margin_level_inc;       // The flag of the margin level change exceeding the growth value
   bool              m_is_change_margin_level_dec;       // The flag of the margin level change exceeding the decrease value
   //--- Margin Call
   double            m_changed_margin_so_call_value;     // Margin Call level change value
   bool              m_is_change_margin_so_call_inc;     // Margin Call level increase value
   bool              m_is_change_margin_so_call_dec;     // Margin Call level decrease value
   //--- MarginStopOut
   double            m_changed_margin_so_so_value;       // Margin StopOut level change value
   bool              m_is_change_margin_so_so_inc;       // Margin StopOut level increase flag
   bool              m_is_change_margin_so_so_dec;       // Margin StopOut level decrease flag
   //--- Guarantee sum for pending orders
   double            m_control_margin_initial_inc;       // Tracked growth value of the reserved funds for providing the guarantee sum for pending orders
   double            m_control_margin_initial_dec;       // Tracked decrease value of the reserved funds for providing the guarantee sum for pending orders
   double            m_changed_margin_initial_value;     // The change value of the reserved funds for providing the guarantee sum for pending orders
   bool              m_is_change_margin_initial_inc;     // The flag of the reserved funds for providing the guarantee sum for pending orders exceeding the growth value
   bool              m_is_change_margin_initial_dec;     // The flag of the reserved funds for providing the guarantee sum for pending orders exceeding the decrease value
   //--- Guarantee sum for open positions
   double            m_control_margin_maintenance_inc;   // The tracked increase value of the funds reserved on an account to ensure a minimum amount for all open positions
   double            m_control_margin_maintenance_dec;   // The tracked decrease value of the funds reserved on an account to ensure a minimum amount for all open positions
   double            m_changed_margin_maintenance_value; // The change value of the funds reserved on an account to ensure a minimum amount for all open positions
   bool              m_is_change_margin_maintenance_inc; // The flag of the funds reserved on an account to ensure a minimum amount for all open positions exceeding the growth value
   bool              m_is_change_margin_maintenance_dec; // The flag of the funds reserved on an account to ensure a minimum amount for all open positions exceeding the decrease value
   //--- Assets
   double            m_control_assets_inc;               // Tracked assets growth value
   double            m_control_assets_dec;               // Tracked assets decrease value
   double            m_changed_assets_value;             // Assets change value
   bool              m_is_change_assets_inc;             // The flag of the assets change exceeding the growth value
   bool              m_is_change_assets_dec;             // The flag of the assets change exceeding the decrease value
   //--- Liabilities
   double            m_control_liabilities_inc;          // Tracked liabilities growth value
   double            m_control_liabilities_dec;          // Tracked liabilities decrease value
   double            m_changed_liabilities_value;        // Liabilities change values
   bool              m_is_change_liabilities_inc;        // The flag of the liabilities change exceeding the growth value
   bool              m_is_change_liabilities_dec;        // The flag of the liabilities change exceeding the decrease value
   //--- Blocked commissions
   double            m_control_comission_blocked_inc;    // Tracked blocked commissions growth value
   double            m_control_comission_blocked_dec;    // Tracked blocked commissions decrease value
   double            m_changed_comission_blocked_value;  // Blocked commissions changed value
   bool              m_is_change_comission_blocked_inc;  // The flag of the tracked commissions change exceeding the growth value
   bool              m_is_change_comission_blocked_dec;  // The flag of the tracked commissions change exceeding the decrease value
   
//--- Initialize the variables of (1) tracked, (2) controlled account data
   void              InitChangesParams(void); 
   void              InitControlsParams(void);
//--- Check account changes, return a change code
   int               SetChangeCode(void);
//--- Set an event type and fill in the event list
   void              SetTypeEvent(void);
//--- return the flag presence in the account event
   bool              IsPresentEventFlag(constint change_code)   const { return (this.m_change_code & change_code)==change_code;               }
//--- Write the current account data to the account object properties
   void              SetAccountsParams(CAccount* account);

//--- Check the account object presence in the collection list
   bool              IsPresent(CAccount* account);
//--- Find and return the account object index with the current account data
   int               Index(void);
public:

Die Methode SavePrevValues() hat sich als redundant erwiesen. Wenn wir die Änderung der Kontoeigenschaften definieren, müssen wir den neuen Eigenschaftswert in die Struktur schreiben, die die Daten über den vorherigen Status der geänderten Eigenschaft speichert. Die restlichen Eigenschaften sollten so belassen werden, wie sie bei der vorherigen Prüfung vor der eigentlichen Änderung waren. Die Methode SavePrevValues() speichert alle Kontoeigenschaften als vorherige und verletzt damit die Verfolgung eines bestimmten Änderungswerts, der standardmäßig für jede der verfolgten Eigenschaften festgelegt ist, die separat mit bestimmten Methoden zum Setzen eines verfolgten Wertes eingestellt werden können.

Schreiben wir die Methode zur Initialisierung von verfolgten Daten außerhalb des Klassenkörpers:

//+------------------------------------------------------------------+
//| Initialize the variables of tracked account data                 |
//+------------------------------------------------------------------+
void CAccountsCollection::InitChangesParams(void)
  {
//--- List and code of changes
   this.m_list_changes.Clear();                    // Clear the change list
   this.m_list_changes.Sort();                     // Sort the change list
//--- Leverage
   this.m_changed_leverage_value=0;                // Leverage change value
   this.m_is_change_leverage_inc=false;            // Leverage increase flag
   this.m_is_change_leverage_dec=false;            // Leverage decrease flag
//--- Number of active pending orders
   this.m_changed_limit_orders_value=0;            // Change value of the maximum allowed number of active pending orders
   this.m_is_change_limit_orders_inc=false;        // Increase flag of the maximum allowed number of active pending orders
   this.m_is_change_limit_orders_dec=false;        // Decrease flag of the maximum allowed number of active pending orders
//--- Trading on an account
   this.m_is_change_trade_allowed_on=false;        // The flag allowing to trade for the current account from the server side
   this.m_is_change_trade_allowed_off=false;       // The flag prohibiting trading for the current account from the server side
//--- Auto trading on an account
   this.m_is_change_trade_expert_on=false;         // The flag allowing to trade for an EA from the server side
   this.m_is_change_trade_expert_off=false;        // The flag prohibiting trading for an EA from the server side
//--- Balance
   this.m_changed_balance_value=0;                 // Balance change value
   this.m_is_change_balance_inc=false;             // The flag of the balance change exceeding the growth value
   this.m_is_change_balance_dec=false;             // The flag of the balance change exceeding the decrease value
//--- Credit
   this.m_changed_credit_value=0;                  // Credit change value
   this.m_is_change_credit_inc=false;              // Credit increase flag
   this.m_is_change_credit_dec=false;              // Credit decrease flag
//--- Profit
   this.m_changed_profit_value=0;                  // Profit change value
   this.m_is_change_profit_inc=false;              // The flag of the profit change exceeding the growth value
   this.m_is_change_profit_dec=false;              // The flag of the profit change exceeding the decrease value
//--- Funds
   this.m_changed_equity_value=0;                  // Funds change value
   this.m_is_change_equity_inc=false;              // The flag of the funds change exceeding the growth value
   this.m_is_change_equity_dec=false;              // The flag of the funds change exceeding the decrease value
//--- Margin
   this.m_changed_margin_value=0;                  // Margin change value
   this.m_is_change_margin_inc=false;              // The flag of the margin change exceeding the growth value
   this.m_is_change_margin_dec=false;              // The flag of the margin change exceeding the decrease value
//--- Free margin
   this.m_changed_margin_free_value=0;             // Free margin change value
   this.m_is_change_margin_free_inc=false;         // The flag of the free margin change exceeding the growth value
   this.m_is_change_margin_free_dec=false;         // The flag of the free margin change exceeding the decrease value
//--- Margin level
   this.m_changed_margin_level_value=0;            // Margin level change value
   this.m_is_change_margin_level_inc=false;        // The flag of the margin level change exceeding the growth value
   this.m_is_change_margin_level_dec=false;        // The flag of the margin level change exceeding the decrease value
//--- Margin Call level
   this.m_changed_margin_so_call_value=0;          // Margin Call level change value
   this.m_is_change_margin_so_call_inc=false;      // Margin Call level increase flag
   this.m_is_change_margin_so_call_dec=false;      // Margin Call level decrease flag
//--- Margin StopOut level
   this.m_changed_margin_so_so_value=0;            // Margin StopOut level change value
   this.m_is_change_margin_so_so_inc=false;        // Margin StopOut level increase flag
   this.m_is_change_margin_so_so_dec=false;        // Margin StopOut level decrease flag
//--- Guarantee sum for pending orders
   this.m_changed_margin_initial_value=0;          // The change value of the reserved funds for providing the guarantee sum for pending orders
   this.m_is_change_margin_initial_inc=false;      // The flag of the reserved funds for providing the guarantee sum for pending orders exceeding the growth value
   this.m_is_change_margin_initial_dec=false;      // The flag of the reserved funds for providing the guarantee sum for pending orders exceeding the decrease value
//--- Guarantee sum for open positions
   this.m_changed_margin_maintenance_value=0;      // The change value of the funds reserved on an account to ensure a minimum amount for all open positions
   this.m_is_change_margin_maintenance_inc=false;  // The flag of the funds reserved on an account to ensure a minimum amount for all open positions exceeding the growth value
   this.m_is_change_margin_maintenance_dec=false;  // The flag of the funds reserved on an account to ensure a minimum amount for all open positions exceeding the decrease value
//--- Assets
   this.m_changed_assets_value=0;                  // Assets change value
   this.m_is_change_assets_inc=false;              // The flag of the assets change exceeding the growth value
   this.m_is_change_assets_dec=false;              // The flag of the assets change exceeding the decrease value
//--- Liabilities
   this.m_changed_liabilities_value=0;             // Liabilities change value
   this.m_is_change_liabilities_inc=false;         // The flag of the liabilities change exceeding the growth value
   this.m_is_change_liabilities_dec=false;         // The flag of the liabilities change exceeding the decrease value
//--- Blocked commissions
   this.m_changed_comission_blocked_value=0;       // Blocked commissions change value
   this.m_is_change_comission_blocked_inc=false;   // The flag of the tracked commissions change exceeding the growth value
   this.m_is_change_comission_blocked_dec=false;   // The flag of the tracked commissions change exceeding the decrease value
  }
//+------------------------------------------------------------------+

Das Verfahren zum Initialisieren der kontrollierten Daten:

//+------------------------------------------------------------------+
//| Initialize the variables of controlled account data              |
//+------------------------------------------------------------------+
void CAccountsCollection::InitControlsParams(void)
  {
//--- Balance
   this.m_control_balance_inc=50;                  // Tracked balance growth value
   this.m_control_balance_dec=50;                  // Tracked balance decrease value
//--- Profit
   this.m_control_profit_inc=20;                   // Tracked profit growth value
   this.m_control_profit_dec=20;                   // Tracked profit decrease value
//--- Funds (equity)
   this.m_control_equity_inc=15;                   // Tracked funds growth value
   this.m_control_equity_dec=15;                   // Tracked funds decrease value
//--- Margin
   this.m_control_margin_inc=1000;                 // Tracked margin growth value
   this.m_control_margin_dec=1000;                 // Tracked margin decrease value
//--- Free margin
   this.m_control_margin_free_inc=1000;            // Tracked free margin growth value
   this.m_control_margin_free_dec=1000;            // Tracked free margin decrease value
//--- Margin level
   this.m_control_margin_level_inc=10000;          // Tracked margin level growth value
   this.m_control_margin_level_dec=500;            // Tracked margin level decrease value
//--- Guarantee sum for pending orders
   this.m_control_margin_initial_inc=1000;         // Tracked growth value of the reserved funds for providing the guarantee sum for pending orders
   this.m_control_margin_initial_dec=1000;         // Tracked decrease value of the reserved funds for providing the guarantee sum for pending orders
//--- Guarantee sum for open positions
   this.m_control_margin_maintenance_inc=1000;     // The tracked increase value of the funds reserved on an account to ensure a minimum amount for all open positions
   this.m_control_margin_maintenance_dec=1000;     // The tracked decrease value of the funds reserved on an account to ensure a minimum amount for all open positions
//--- Assets
   this.m_control_assets_inc=1000;                 // Tracked assets growth value
   this.m_control_assets_dec=1000;                 // Tracked assets decrease value
//--- Liabilities
   this.m_control_liabilities_inc=1000;            // Tracked liabilities growth value
   this.m_control_liabilities_dec=1000;            // Tracked liabilities decrease value
//--- Blocked commissions
   this.m_control_comission_blocked_inc=1000;      // Tracked blocked commissions growth value
   this.m_control_comission_blocked_dec=1000;      // Tracked blocked commissions decrease value
  }
//+------------------------------------------------------------------+

Bei dieser Methode initialisieren wir die Variablen einfach mit Standardwerten. Wenn die Eigenschaften die in den Variablen eingestellten Werte überschreiten, wird ein entsprechendes Kontoereignis erzeugt. Diese Eigenschaften können auch durch direkten Aufruf der entsprechenden Methoden zum Einstellen der kontrollierten Kontoeigenschaften festgelegt werden.

Die Methode, die die Eigenschaften des Kontos überprüft, ändert sich und füllt den Ereigniscode mit den entsprechenden Kennzeichen aus:

//+------------------------------------------------------------------+
//| Check account changes, return the change code                    |
//+------------------------------------------------------------------+
int CAccountsCollection::SetChangeCode(void)
  {
   this.m_change_code=ACCOUNT_EVENT_FLAG_NO_EVENT;
   
   if(this.m_struct_curr_account.trade_allowed!=this.m_struct_prev_account.trade_allowed)
      this.m_change_code+=ACCOUNT_EVENT_FLAG_TRADE_ALLOWED;
   if(this.m_struct_curr_account.trade_expert!=this.m_struct_prev_account.trade_expert)
      this.m_change_code+=ACCOUNT_EVENT_FLAG_TRADE_EXPERT;
   if(this.m_struct_curr_account.leverage-this.m_struct_prev_account.leverage!=0)
      this.m_change_code+=ACCOUNT_EVENT_FLAG_LEVERAGE;
   if(this.m_struct_curr_account.limit_orders-this.m_struct_prev_account.limit_orders!=0)
      this.m_change_code+=ACCOUNT_EVENT_FLAG_LIMIT_ORDERS;
   if(this.m_struct_curr_account.balance-this.m_struct_prev_account.balance!=0)
      this.m_change_code+=ACCOUNT_EVENT_FLAG_BALANCE;
   if(this.m_struct_curr_account.credit-this.m_struct_prev_account.credit!=0)
      this.m_change_code+=ACCOUNT_EVENT_FLAG_CREDIT;
   if(this.m_struct_curr_account.profit-this.m_struct_prev_account.profit!=0)
      this.m_change_code+=ACCOUNT_EVENT_FLAG_PROFIT;
   if(this.m_struct_curr_account.equity-this.m_struct_prev_account.equity!=0)
      this.m_change_code+=ACCOUNT_EVENT_FLAG_EQUITY;
   if(this.m_struct_curr_account.margin-this.m_struct_prev_account.margin!=0)
      this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN;
   if(this.m_struct_curr_account.margin_free-this.m_struct_prev_account.margin_free!=0)
      this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN_FREE;
   if(this.m_struct_curr_account.margin_level-this.m_struct_prev_account.margin_level!=0)
      this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN_LEVEL;
   if(this.m_struct_curr_account.margin_so_call-this.m_struct_prev_account.margin_so_call!=0)
      this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN_SO_CALL;
   if(this.m_struct_curr_account.margin_so_so-this.m_struct_prev_account.margin_so_so!=0)
      this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN_SO_SO;
   if(this.m_struct_curr_account.margin_initial-this.m_struct_prev_account.margin_initial!=0)
      this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN_INITIAL;
   if(this.m_struct_curr_account.margin_maintenance-this.m_struct_prev_account.margin_maintenance!=0)
      this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN_MAINTENANCE;
   if(this.m_struct_curr_account.assets-this.m_struct_prev_account.assets!=0)
      this.m_change_code+=ACCOUNT_EVENT_FLAG_ASSETS;
   if(this.m_struct_curr_account.liabilities-this.m_struct_prev_account.liabilities!=0)
      this.m_change_code+=ACCOUNT_EVENT_FLAG_LIABILITIES;
   if(this.m_struct_curr_account.comission_blocked-this.m_struct_prev_account.comission_blocked!=0)
      this.m_change_code+=ACCOUNT_EVENT_FLAG_COMISSION_BLOCKED;
//---
   returnthis.m_change_code;
  }
//+------------------------------------------------------------------+

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

Die Methode, die einen Ereignistyp festlegt und das Ereignis zur Liste der Kontoänderungen hinzufügt:

//+------------------------------------------------------------------+
//| Set the account object event type                                |
//+------------------------------------------------------------------+
void CAccountsCollection::SetTypeEvent(void)
  {
   this.InitChangesParams();
   ENUM_ACCOUNT_EVENT event=ACCOUNT_EVENT_NO_EVENT;
//--- Changing permission to trade for the account
   if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_TRADE_ALLOWED))
     {
      if(!this.m_struct_curr_account.trade_allowed)
        {
         this.m_is_change_trade_allowed_off=true;
         event=ACCOUNT_EVENT_TRADE_ALLOWED_OFF;
         this.m_struct_prev_account.trade_allowed=this.m_struct_curr_account.trade_allowed;
        }
      else
        {
         this.m_is_change_trade_allowed_on=true;
         event=ACCOUNT_EVENT_TRADE_ALLOWED_ON;
         this.m_struct_prev_account.trade_allowed=this.m_struct_curr_account.trade_allowed;
        }
      if(this.m_list_changes.Search(event)==WRONG_VALUE)
         this.m_list_changes.Add(event);
     }
//--- Changing permission for auto trading for the account
   if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_TRADE_EXPERT))
     {
      if(!this.m_struct_curr_account.trade_expert)
        {
         this.m_is_change_trade_expert_off=true;
         event=ACCOUNT_EVENT_TRADE_EXPERT_OFF;
         this.m_struct_prev_account.trade_expert=false;
        }
      else
        {
         this.m_is_change_trade_expert_on=true;
         event=ACCOUNT_EVENT_TRADE_EXPERT_ON;
         this.m_struct_prev_account.trade_expert=true;
        }
      if(this.m_list_changes.Search(event)==WRONG_VALUE)
         this.m_list_changes.Add(event);
     }
//--- Change the leverage
   if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_LEVERAGE))
     {
      this.m_changed_leverage_value=this.m_struct_curr_account.leverage-this.m_struct_prev_account.leverage;
      if(this.m_changed_leverage_value>0)
        {
         this.m_is_change_leverage_inc=true;
         event=ACCOUNT_EVENT_LEVERAGE_INC;
        }
      else
        {
         this.m_is_change_leverage_dec=true;
         event=ACCOUNT_EVENT_LEVERAGE_DEC;
        }
      if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
         this.m_struct_prev_account.leverage=this.m_struct_curr_account.leverage;
     }
//--- Changing the maximum allowed number of active pending orders
   if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_LIMIT_ORDERS))
     {
      this.m_changed_limit_orders_value=this.m_struct_curr_account.limit_orders-this.m_struct_prev_account.limit_orders;
      if(this.m_changed_limit_orders_value>0)
        {
         this.m_is_change_limit_orders_inc=true;
         event=ACCOUNT_EVENT_LIMIT_ORDERS_INC;
        }
      else
        {
         this.m_is_change_limit_orders_dec=true;
         event=ACCOUNT_EVENT_LIMIT_ORDERS_DEC;
        }
      if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
         this.m_struct_prev_account.limit_orders=this.m_struct_curr_account.limit_orders;
     }
//--- Changing the credit in a deposit currency
   if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_CREDIT))
     {
      this.m_changed_credit_value=this.m_struct_curr_account.credit-this.m_struct_prev_account.credit;
      if(this.m_changed_credit_value>0)
        {
         this.m_is_change_credit_inc=true;
         event=ACCOUNT_EVENT_CREDIT_INC;
        }
      else
        {
         this.m_is_change_credit_dec=true;
         event=ACCOUNT_EVENT_CREDIT_DEC;
        }
      if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
         this.m_struct_prev_account.credit=this.m_struct_curr_account.credit;
     }
//--- Changing the Margin Call level
   if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN_SO_CALL))
     {
      this.m_changed_margin_so_call_value=this.m_struct_curr_account.margin_so_call-this.m_struct_prev_account.margin_so_call;
      if(this.m_changed_margin_so_call_value>0)
        {
         this.m_is_change_margin_so_call_inc=true;
         event=ACCOUNT_EVENT_MARGIN_SO_CALL_INC;
        }
      else
        {
         this.m_is_change_margin_so_call_dec=true;
         event=ACCOUNT_EVENT_MARGIN_SO_CALL_DEC;
        }
      if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
         this.m_struct_prev_account.margin_so_call=this.m_struct_curr_account.margin_so_call;
     }
//--- Changing the Stop Out level
   if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN_SO_SO))
     {
      this.m_changed_margin_so_so_value=this.m_struct_curr_account.margin_so_so-this.m_struct_prev_account.margin_so_so;
      if(this.m_changed_margin_so_so_value>0)
        {
         this.m_is_change_margin_so_so_inc=true;
         event=ACCOUNT_EVENT_MARGIN_SO_SO_INC;
        }
      else
        {
         this.m_is_change_margin_so_so_dec=true;
         event=ACCOUNT_EVENT_MARGIN_SO_SO_DEC;
        }
      if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
         this.m_struct_prev_account.margin_so_so=this.m_struct_curr_account.margin_so_so;
     }
//--- The balance exceeds the specified change value +/-
   if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_BALANCE))
     {
      this.m_changed_balance_value=this.m_struct_curr_account.balance-this.m_struct_prev_account.balance;
      if(this.m_changed_balance_value>this.m_control_balance_inc)
        {
         this.m_is_change_balance_inc=true;
         event=ACCOUNT_EVENT_BALANCE_INC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.balance=this.m_struct_curr_account.balance;
        }
      elseif(this.m_changed_balance_value<-this.m_control_balance_dec)
        {
         this.m_is_change_balance_dec=true;
         event=ACCOUNT_EVENT_BALANCE_DEC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.balance=this.m_struct_curr_account.balance;
        }
     }
//--- The profit exceeds the specified change value +/-
   if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_PROFIT))
     {
      this.m_changed_profit_value=this.m_struct_curr_account.profit-this.m_struct_prev_account.profit;
      if(this.m_changed_profit_value>this.m_control_profit_inc)
        {
         this.m_is_change_profit_inc=true;
         event=ACCOUNT_EVENT_PROFIT_INC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.profit=this.m_struct_curr_account.profit;
        }
      elseif(this.m_changed_profit_value<-this.m_control_profit_dec)
        {
         this.m_is_change_profit_dec=true;
         event=ACCOUNT_EVENT_PROFIT_DEC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.profit=this.m_struct_curr_account.profit;
        }
     }
//--- The equity exceeds the specified change value +/-
   if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_EQUITY))
     {
      this.m_changed_equity_value=this.m_struct_curr_account.equity-this.m_struct_prev_account.equity;
      if(this.m_changed_equity_value>this.m_control_equity_inc)
        {
         this.m_is_change_equity_inc=true;
         event=ACCOUNT_EVENT_EQUITY_INC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.equity=this.m_struct_curr_account.equity;
        }
      elseif(this.m_changed_equity_value<-this.m_control_equity_dec)
        {
         this.m_is_change_equity_dec=true;
         event=ACCOUNT_EVENT_EQUITY_DEC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.equity=this.m_struct_curr_account.equity;
        }
     }
//--- The reserved margin on an account in the deposit currency change exceeds the specified value +/-
   if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN))
     {
      this.m_changed_margin_value=this.m_struct_curr_account.margin-this.m_struct_prev_account.margin;
      if(this.m_changed_margin_value>this.m_control_margin_inc)
        {
         this.m_is_change_margin_inc=true;
         event=ACCOUNT_EVENT_MARGIN_INC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.margin=this.m_struct_curr_account.margin;
        }
      elseif(this.m_changed_margin_value<-this.m_control_margin_dec)
        {
         this.m_is_change_margin_dec=true;
         event=ACCOUNT_EVENT_MARGIN_DEC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.margin=this.m_struct_curr_account.margin;
        }
     }
//--- The free funds available for opening a position in a deposit currency exceed the specified change value +/-
   if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN_FREE))
     {
      this.m_changed_margin_free_value=this.m_struct_curr_account.margin_free-this.m_struct_prev_account.margin_free;
      if(this.m_changed_margin_free_value>this.m_control_margin_free_inc)
        {
         this.m_is_change_margin_free_inc=true;
         event=ACCOUNT_EVENT_MARGIN_FREE_INC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.margin_free=this.m_struct_curr_account.margin_free;
        }
      elseif(this.m_changed_margin_free_value<-this.m_control_margin_free_dec)
        {
         this.m_is_change_margin_free_dec=true;
         event=ACCOUNT_EVENT_MARGIN_FREE_DEC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.margin_free=this.m_struct_curr_account.margin_free;
        }
     }
//--- The margin level on an account in % exceeds the specified change value +/-
   if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN_LEVEL))
     {
      this.m_changed_margin_level_value=this.m_struct_curr_account.margin_level-this.m_struct_prev_account.margin_level;
      if(this.m_changed_margin_level_value>this.m_control_margin_level_inc)
        {
         this.m_is_change_margin_level_inc=true;
         event=ACCOUNT_EVENT_MARGIN_LEVEL_INC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.margin_level=this.m_struct_curr_account.margin_level;
        }
      elseif(this.m_changed_margin_level_value<-this.m_control_margin_level_dec)
        {
         this.m_is_change_margin_level_dec=true;
         event=ACCOUNT_EVENT_MARGIN_LEVEL_DEC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.margin_level=this.m_struct_curr_account.margin_level;
        }
     }
//--- The funds reserved on an account to ensure a guarantee amount for all pending orders exceed the specified change value +/-
   if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN_INITIAL))
     {
      this.m_changed_margin_initial_value=this.m_struct_curr_account.margin_initial-this.m_struct_prev_account.margin_initial;
      if(this.m_changed_margin_initial_value>this.m_control_margin_initial_inc)
        {
         this.m_is_change_margin_initial_inc=true;
         event=ACCOUNT_EVENT_MARGIN_INITIAL_INC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.margin_initial=this.m_struct_curr_account.margin_initial;
        }
      elseif(this.m_changed_margin_initial_value<-this.m_control_margin_initial_dec)
        {
         this.m_is_change_margin_initial_dec=true;
         event=ACCOUNT_EVENT_MARGIN_INITIAL_DEC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.margin_initial=this.m_struct_curr_account.margin_initial;
        }
     }
//--- The funds reserved on an account to ensure a minimum amount for all open positions exceed the specified change value +/-
   if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN_MAINTENANCE))
     {
      this.m_changed_margin_maintenance_value=this.m_struct_curr_account.margin_maintenance-this.m_struct_prev_account.margin_maintenance;
      if(this.m_changed_margin_maintenance_value>this.m_control_margin_maintenance_inc)
        {
         this.m_is_change_margin_maintenance_inc=true;
         event=ACCOUNT_EVENT_MARGIN_MAINTENANCE_INC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.margin_maintenance=this.m_struct_curr_account.margin_maintenance;
        }
      elseif(this.m_changed_margin_maintenance_value<-this.m_control_margin_maintenance_dec)
        {
         this.m_is_change_margin_maintenance_dec=true;
         event=ACCOUNT_EVENT_MARGIN_MAINTENANCE_DEC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.margin_maintenance=this.m_struct_curr_account.margin_maintenance;
        }
     }
//--- The current assets on an account exceed the specified change value +/-
   if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_ASSETS))
     {
      this.m_changed_assets_value=this.m_struct_curr_account.assets-this.m_struct_prev_account.assets;
      if(this.m_changed_assets_value>this.m_control_assets_inc)
        {
         this.m_is_change_assets_inc=true;
         event=ACCOUNT_EVENT_ASSETS_INC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.assets=this.m_struct_curr_account.assets;
        }
      elseif(this.m_changed_assets_value<-this.m_control_assets_dec)
        {
         this.m_is_change_assets_dec=true;
         event=ACCOUNT_EVENT_ASSETS_DEC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.assets=this.m_struct_curr_account.assets;
        }
     }
//--- The current liabilities on an account exceed the specified change value +/-
   if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_LIABILITIES))
     {
      this.m_changed_liabilities_value=this.m_struct_curr_account.liabilities-this.m_struct_prev_account.liabilities;
      if(this.m_changed_liabilities_value>this.m_control_liabilities_inc)
        {
         this.m_is_change_liabilities_inc=true;
         event=ACCOUNT_EVENT_LIABILITIES_INC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.liabilities=this.m_struct_curr_account.liabilities;
        }
      elseif(this.m_changed_liabilities_value<-this.m_control_liabilities_dec)
        {
         this.m_is_change_liabilities_dec=true;
         event=ACCOUNT_EVENT_LIABILITIES_DEC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.liabilities=this.m_struct_curr_account.liabilities;
        }
     }
//--- The current sum of blocked commissions on an account exceeds the specified change value +/-
   if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_COMISSION_BLOCKED))
     {
      this.m_changed_comission_blocked_value=this.m_struct_curr_account.comission_blocked-this.m_struct_prev_account.comission_blocked;
      if(this.m_changed_comission_blocked_value>this.m_control_comission_blocked_inc)
        {
         this.m_is_change_comission_blocked_inc=true;
         event=ACCOUNT_EVENT_COMISSION_BLOCKED_INC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.comission_blocked=this.m_struct_curr_account.comission_blocked;
        }
      elseif(this.m_changed_comission_blocked_value<-this.m_control_comission_blocked_dec)
        {
         this.m_is_change_comission_blocked_dec=true;
         event=ACCOUNT_EVENT_COMISSION_BLOCKED_DEC;
         if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event))
            this.m_struct_prev_account.comission_blocked=this.m_struct_curr_account.comission_blocked;
        }
     }
  }
//+------------------------------------------------------------------+

Die Methode verfügt über zwei Ereignis-Typen:

  1. einfache Verfolgung einer Eigenschaftserlaubnis/-veränderung,
  2. Verfolgen von Änderungen, die bestimmten Werte über- oder unterschreitet.

Da die Methode recht umfangreich ist, werden wir die beiden Typen der Kontoereignisdefinition als Beispiel verwenden:

Zunächst werden alle Änderungsflags und Daten zurückgesetzt und der Ereignistyp auf Null gesetzt.
Weiter, für den ersten Logiktyp (mit der Erlaubnis, auf einem Konto zu handeln):

  • Aktivieren Sie das Flag der Berechtigung zum Handeln auf einem Konto im Ereigniscode
  • wenn der Handel derzeit verboten ist , wurde die Berechtigung gerade deaktiviert
    • setzen Sie die Flag, die den Handel auf dem Konto verbietet
    • aqetzen Sie das Ereignis "Handel auf dem Konto deaktiviert"
    • speichern des aktuellen Status der Kontoeigenschaft in der vorherigen Datenstruktur zur späteren Überprüfung
  • andernfalls, wenn der Handel derzeit erlaubt ist
    • setzen Sie das Flag, das den Handel auf dem Konto ermöglicht
    • setzen Sie das Ereignis "Trading auf dem Konto aktiviert"
    • speichern des aktuellen Status der Kontoeigenschaft in der vorherigen Datenstruktur zur späteren Überprüfung
  • wenn es kein solches Ereignis in der Änderungsliste gibt
  • ein Ereignis zur Liste hinzufügen

Für den zweiten Logiktyp (am Beispiel der Änderung der Summe der gesperrten Provisionen):

  • Aktivieren Sie das Flag zum Ändern der Summe der gesperrten Provisionen
  • Berechnen der Änderung der Summe der gesperrten Provisionen
  • Wenn der Änderungswert den kontrollierten Wachstumswert überschreitet
    • setzen Sie das Flag der Summe der blockierten Provisionen
    • setzen Sie das Ereignis "Summe der Erhöhung der gesperrten Provisionen überschreitet den angegebenen Wert"
    • wenn es kein solches Ereignis in der Änderungsliste gibt und das Ereignis erfolgreich zur Liste hinzugefügt wurde
      • speichern des aktuellen Status der Kontoeigenschaft in der vorherigen Datenstruktur zur späteren Überprüfung
  • andernfalls, wenn der Änderungswert den kontrollierten Abnahmewert überschreitet.
    • setzen Sie das Flag für die Verringerung der Summe der gesperrte Provisionen
    • setzen Sie das Ereignis "Summe der blockierten Provisionen überschreitet den angegebenen Wert"
    • wenn es kein solches Ereignis in der Änderungsliste gibt und das Ereignis erfolgreich zur Liste hinzugefügt wurde
      • speichern des aktuellen Status der Kontoeigenschaft in der vorherigen Datenstruktur zur späteren Überprüfung

Im 'public' Teil der Klasse fügen Sie die Methoden hinzu, die den Code des Kontoereignisses, deren Liste und das Kontoereignis durch seinen Index in der Liste zurückgeben; die Methoden Einstellen und Rückgeben eines Symbols, die Methode, die die ID des Steuerungsprogramm-Diagramms und die Methode, die die Beschreibung des Kontoereignisses zurückgibt. Fügen Sie auch die Methoden zum Empfangen und Einstellen der Parameter von verfolgten Änderungen hinzu:

public:
//--- Return the full account collection list "as is"
   CArrayObj        *GetList(void)                                                                          { return &this.m_list_accounts;                                         }
//--- Rückgabe der Auswahlliste von (1) Integer-, (2) Double- und (3) String-Eigenschaften, die dem Vergleichskriterium entsprechen
   CArrayObj        *GetList(ENUM_ACCOUNT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL)   { return CSelect::ByAccountProperty(this.GetList(),property,value,mode);}
   CArrayObj        *GetList(ENUM_ACCOUNT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL)  { return CSelect::ByAccountProperty(this.GetList(),property,value,mode);}
   CArrayObj        *GetList(ENUM_ACCOUNT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL)  { return CSelect::ByAccountProperty(this.GetList(),property,value,mode);}
//--- Return the (1) current account object index, (2) the flag of the event occurred in the account data, (3) event type
   int               IndexCurrentAccount(void)                                                        const { return this.m_index_current;                                           }
   bool              IsAccountEvent(void)                                                             const { return this.m_is_account_event;                                        }
//--- Return the (1) object account event code, (2) event list, (3) account event by its number in the list
   int               GetEventCode(void)                                                               const { return this.m_change_code;                                             }
   CArrayInt        *GetListChanges(void)                                                                   { return &this.m_list_changes;                          }
   ENUM_ACCOUNT_EVENT GetEvent(constint shift=WRONG_VALUE);
//--- (1) Set and (2) return the current symbol
   void              SetSymbol(conststring symbol)                                                          { this.m_symbol=symbol;                                 }
   string            GetSymbol(void)                                                                  const { return this.m_symbol;                                 }
//--- Setzen der Chart-ID des Steuerprogramms
   void              SetChartID(constlong id)                                                               { this.m_chart_id=id;                                   }

//--- Constructor, destructor
                     CAccountsCollection();
                    ~CAccountsCollection();
//--- Add the account object to the list
   bool              AddToList(CAccount* account);
//--- (1) Save account objects from the list to the files
//--- (2) Save account objects from the files to the list
   bool              SaveObjects(void);
   bool              LoadObjects(void);
//--- Return the account event description
   string            EventDescription(const ENUM_ACCOUNT_EVENT event);
//--- Update the current account data
   void              Refresh(void);
   
//--- Get and set the parameters of tracked changes
   //--- Leverage:
   //--- (1) Leverage change value, (2) Leverage increase flag, (3) Leverage decrease flag
   long              GetValueChangedLeverage(void)                                                    const { return this.m_changed_leverage_value;                  }
   bool              IsIncreaseLeverage(void)                                                         const { return this.m_is_change_leverage_inc;                  }
   bool              IsDecreaseLeverage(void)                                                         const { return this.m_is_change_leverage_dec;                  }
   //--- Number of active pending orders:
   //--- (1) Change value, (2) Increase flag, (3) Decrease flag
   int               GetValueChangedLimitOrders(void)                                                 const { return this.m_changed_limit_orders_value;              }
   bool              IsIncreaseLimitOrders(void)                                                      const { return this.m_is_change_limit_orders_inc;              }
   bool              IsDecreaseLimitOrders(void)                                                      const { return this.m_is_change_limit_orders_dec;              }
   //--- Trading on an account:
   //--- (1) The flag allowing to trade for the current account, (2) The flag prohibiting trading for the current account from the server side
   bool              IsOnTradeAllowed(void)                                                           const { return this.m_is_change_trade_allowed_on;              }
   bool              IsOffTradeAllowed(void)                                                          const { return this.m_is_change_trade_allowed_off;             }
   //--- Auto trading on an account:
   //--- (1) The flag allowing to trade for an EA, (2) The flag prohibiting trading for an EA from the server side
   bool              IsOnTradeExpert(void)                                                            const { return this.m_is_change_trade_expert_on;               }
   bool              IsOffTradeExpert(void)                                                           const { return this.m_is_change_trade_expert_off;              }
   //--- Balance:
   //--- setting the tracked value of the balance (1) growth, (2) decrease
   //--- getting (3) the balance change value,
   //--- getting the flag of the balance change exceeding the (4) growth value, (5) decrease value
   void              SetControlBalanceInc(const double value)                                               { this.m_control_balance_inc=::fabs(value);              }
   void              SetControlBalanceDec(const double value)                                               { this.m_control_balance_dec=::fabs(value);              }
   double            GetValueChangedBalance(void)                                                     const { return this.m_changed_balance_value;                   }
   bool              IsIncreaseBalance(void)                                                          const { return this.m_is_change_balance_inc;                   }
   bool              IsDecreaseBalance(void)                                                          const { return this.m_is_change_balance_dec;                   }
   //--- Credit:
   //--- getting (1) the credit change value, (2) credit increase flag, (3) decrease flag
   double            GetValueChangedCredit(void)                                                      const { return this.m_changed_credit_value;                    }
   bool              IsIncreaseCredit(void)                                                           const { return this.m_is_change_credit_inc;                    }
   bool              IsDecreaseCredit(void)                                                           const { return this.m_is_change_credit_dec;                    }
   //--- Profit:
   //--- setting the tracked profit (1) growth, (2) decrease value
   //--- getting the (3) profit change value,
   //--- getting the flag of the profit change exceeding the (4) growth, (5) decrease value
   void              SetControlProfitInc(const double value)                                                { this.m_control_profit_inc=::fabs(value);               }
   void              SetControlProfitDec(const double value)                                                { this.m_control_profit_dec=::fabs(value);               }
   double            GetValueChangedProfit(void)                                                      const { return this.m_changed_profit_value;                    }
   bool              IsIncreaseProfit(void)                                                           const { return this.m_is_change_profit_inc;                    }
   bool              IsDecreaseProfit(void)                                                           const { return this.m_is_change_profit_dec;                    }
   //--- Equity:
   //--- setting the tracked equity (1) growth, (2) decrease value
   //--- getting the (3) equity change value,
   //--- getting the flag of the equity change exceeding the (4) growth, (5) decrease value
   void              SetControlEquityInc(const double value)                                                { this.m_control_equity_inc=::fabs(value);               }
   void              SetControlEquityDec(const double value)                                                { this.m_control_equity_dec=::fabs(value);               }
   double            GetValueChangedEquity(void)                                                      const { return this.m_changed_equity_value;                    }
   bool              IsIncreaseEquity(void)                                                           const { return this.m_is_change_equity_inc;                    }
   bool              IsDecreaseEquity(void)                                                           const { return this.m_is_change_equity_dec;                    }
   //--- Margin:
   //--- setting the tracked margin (1) growth, (2) decrease value
   //--- getting the (3) margin change value,
   //--- getting the flag of the margin change exceeding the (4) growth, (5) decrease value
   void              SetControlMarginInc(const double value)                                                { this.m_control_margin_inc=::fabs(value);               }
   void              SetControlMarginDec(const double value)                                                { this.m_control_margin_dec=::fabs(value);               }
   double            GetValueChangedMargin(void)                                                      const { return this.m_changed_margin_value;                    }
   bool              IsIncreaseMargin(void)                                                           const { return this.m_is_change_margin_inc;                    }
   bool              IsDecreaseMargin(void)                                                           const { return this.m_is_change_margin_dec;                    }
   //--- Free margin:
   //--- setting the tracked free margin (1) growth, (2) decrease value
   //--- getting the (3) free margin change value,
   //--- getting the flag of the free margin change exceeding the (4) growth, (5) decrease value
   void              SetControlMarginFreeInc(const double value)                                            { this.m_control_margin_free_inc=::fabs(value);          }
   void              SetControlMarginFreeDec(const double value)                                            { this.m_control_margin_free_dec=::fabs(value);          }
   double            GetValueChangedMarginFree(void)                                                  const { return this.m_changed_margin_free_value;               }
   bool              IsIncreaseMarginFree(void)                                                       const { return this.m_is_change_margin_free_inc;               }
   bool              IsDecreaseMarginFree(void)                                                       const { return this.m_is_change_margin_free_dec;               }
   //--- Margin level:
   //--- setting the tracked margin level (1) growth, (2) decrease value
   //--- getting the (3) margin level change value,
   //--- getting the flag of the margin level change exceeding the (4) growth, (5) decrease value
   void              SetControlMarginLevelInc(const double value)                                           { this.m_control_margin_level_inc=::fabs(value);         }
   void              SetControlMarginLevelDec(const double value)                                           { this.m_control_margin_level_dec=::fabs(value);         }
   double            GetValueChangedMarginLevel(void)                                                 const { return this.m_changed_margin_level_value;              }
   bool              IsIncreaseMarginLevel(void)                                                      const { return this.m_is_change_margin_level_inc;              }
   bool              IsDecreaseMarginLevel(void)                                                      const { return this.m_is_change_margin_level_dec;              }
   //--- Margin Call:
   //--- getting (1) Margin Call change value, (2) increase flag, (3) decrease flag
   double            GetValueChangedMarginCall(void)                                                  const { return this.m_changed_margin_so_call_value;            }
   bool              IsIncreaseMarginCall(void)                                                       const { return this.m_is_change_margin_so_call_inc;            }
   bool              IsDecreaseMarginCall(void)                                                       const { return this.m_is_change_margin_so_call_dec;            }
   //--- Margin StopOut:
   //--- getting (1) Margin StopOut change value, (2) increase flag, (3) decrease flag
   double            GetValueChangedMarginStopOut(void)                                               const { return this.m_changed_margin_so_so_value;              }
   bool              IsIncreaseMarginStopOut(void)                                                    const { return this.m_is_change_margin_so_so_inc;              }
   bool              IsDecreasMarginStopOute(void)                                                    const { return this.m_is_change_margin_so_so_dec;              }
   //--- Guarantee sum for pending orders:
   //--- setting the tracked value of the reserved funds for providing the guarantee sum for pending orders (1) growth, (2) decrease
   //--- getting the change value of the (3) reserved funds for providing the guarantee sum,
   //--- getting the flag of the reserved funds for providing the guarantee sum for pending orders exceeding the (4) growth, (5) decrease value
   void              SetControlMarginInitialInc(const double value)                                         { this.m_control_margin_initial_inc=::fabs(value);       }
   void              SetControlMarginInitialDec(const double value)                                         { this.m_control_margin_initial_dec=::fabs(value);       }
   double            GetValueChangedMarginInitial(void)                                               const { return this.m_changed_margin_initial_value;            }
   bool              IsIncreaseMarginInitial(void)                                                    const { return this.m_is_change_margin_initial_inc;            }
   bool              IsDecreaseMarginInitial(void)                                                    const { return this.m_is_change_margin_initial_dec;            }
   //--- Guarantee sum for open positions:
   //--- setting the tracked value of the funds reserved on an account to ensure a minimum amount for all open positions (1) growth, (2) decrease
   //--- getting the change value of the (3) funds reserved on an account to ensure a minimum amount for all open positions,
   //--- getting the flag of the funds reserved on an account to ensure a minimum amount for all open positions exceeding the (4) growth, (5) decrease value
   void              SetControlMarginMaintenanceInc(const double value)                                     { this.m_control_margin_maintenance_inc=::fabs(value);   }
   void              SetControlMarginMaintenanceDec(const double value)                                     { this.m_control_margin_maintenance_dec=::fabs(value);   }
   double            GetValueChangedMarginMaintenance(void)                                           const { return this.m_changed_margin_maintenance_value;        }
   bool              IsIncreaseMarginMaintenance(void)                                                const { return this.m_is_change_margin_maintenance_inc;        }
   bool              IsDecreaseMarginMaintenance(void)                                                const { return this.m_is_change_margin_maintenance_dec;        }
   //--- Assets:
   //--- setting the tracked value of the assets (1) growth, (2) decrease
   //--- getting (3) the assets change value,
   //--- getting the flag of the change exceeding the (4) growth, (5) decrease value
   void              SetControlAssetsInc(const double value)                                                { this.m_control_assets_inc=::fabs(value);               }
   void              SetControlAssetsDec(const double value)                                                { this.m_control_assets_dec=::fabs(value);               }
   double            GetValueChangedAssets(void)                                                      const { return this.m_changed_assets_value;                    }
   bool              IsIncreaseAssets(void)                                                           const { return this.m_is_change_assets_inc;                    }
   bool              IsDecreaseAssets(void)                                                           const { return this.m_is_change_assets_dec;                    }
   //--- Liabilities:
   //--- setting the tracked value of the liabilities (1) growth, (2) decrease
   //--- getting (3) the liabilities change value,
   //--- getting the flag of the liabilities change exceeding the (4) growth, (5) decrease value
   void              SetControlLiabilitiesInc(const double value)                                           { this.m_control_liabilities_inc=::fabs(value);          }
   void              SetControlLiabilitiesDec(const double value)                                           { this.m_control_liabilities_dec=::fabs(value);          }
   double            GetValueChangedLiabilities(void)                                                 const { return this.m_changed_liabilities_value;               }
   bool              IsIncreaseLiabilities(void)                                                      const { return this.m_is_change_liabilities_inc;               }
   bool              IsDecreaseLiabilities(void)                                                      const { return this.m_is_change_liabilities_dec;               }
   //--- Blocked commissions:
   //--- setting the tracked blocked commissions (1) growth, (2) decrease value
   //--- getting (3) the blocked commissions change value,
   //--- getting the flag of the tracked commissions change exceeding the (4) growth, (5) decrease value
   void              SetControlComissionBlockedInc(const double value)                                      { this.m_control_comission_blocked_inc=::fabs(value);    }
   void              SetControlComissionBlockedDec(const double value)                                      { this.m_control_comission_blocked_dec=::fabs(value);    }
   double            GetValueChangedComissionBlocked(void)                                            const { return this.m_changed_comission_blocked_value;         }
   bool              IsIncreaseComissionBlocked(void)                                                 const { return this.m_is_change_comission_blocked_inc;         }
   bool              IsDecreaseComissionBlocked(void)                                                 const { return this.m_is_change_comission_blocked_dec;         }
  };
//+------------------------------------------------------------------+

Implementieren Sie über den Klassenkörper hinaus die Methode, die das Kontoereignis nach seiner Nummer in der Liste zurückgibt:

//+------------------------------------------------------------------+
//| Return the account event by its number in the list               |
//+------------------------------------------------------------------+
ENUM_ACCOUNT_EVENT CAccountsCollection::GetEvent(constint shift=WRONG_VALUE)
  {
   int total=this.m_list_changes.Total();
   if(total==0)
      return ACCOUNT_EVENT_NO_EVENT;   
   int index=(shift<0 || shift>total-1 ? total-1 : total-shift-1);
   int event=this.m_list_changes.At(index);
   return ENUM_ACCOUNT_EVENT(event!=NULL ? event : ACCOUNT_EVENT_NO_EVENT);
  }
//+------------------------------------------------------------------+

Die Ereignisse in der Liste der Änderungen der Kontoeigenschaften befinden sich in der Reihenfolge, in der sie hinzugefügt wurden — das allererste befindet sich im Index 0, während das allerletzte im Index (list_size-1) liegt. Wir wollen jedoch, dass die Nutzer wie in einer Zeitreihe ein gewünschtes Ereignis erhalten — der Nullindex sollte das allerletzte Ereignis enthalten. Um dies zu erreichen, verfügt die Methode über die Indexberechnung: index = (list_size - desired_event_number-1). In diesem Fall, wenn wir 0 übergeben, wird das letzte Ereignis in der Liste zurückgegeben; wenn 1, das vorletzte; wenn eine Zahl die Listengröße überschreitet, wird das letzte Ereignis zurückgegeben.

So wird der Index eines gewünschten Ereignisses an die Methode übergeben.
Überprüfen Sie zunächst die Anzahl der Ereignisse in der Liste. Wenn es keine Ereignisse gibt, geben Sie 'no event' zurück.
Als Nächstes überprüfen Sie einen gewünschten Ereignisindex. Wenn der übergebene Wert kleiner als Null ist oder die Array-Größe überschreitet, gibt der Index das letzte Ereignis in der Liste an, andernfalls berechnet den Ereignisindex in der Liste nach der Regel: wenn 0 an die Methode übergeben wird, wollen wir das letzte Ereignis (wie in einer Zeitreihe) erhalten, wenn 1 — das vorletzte, etc. Alternativ, wenn Sie das letzte Ereignis holen müssen, übergeben Sie -1 als Indexeingabe.
Als Nächstes, ermitteln Sie das Ereignis aus der Liste durch den berechneten Index und geben Sie es zurück.
Wenn kein Ereignis ermittelt werden konnte, geben Sie NULL zurück. Das bedeutet, dass das Ergebnis der Methodenoperation vor der Verwendung auf Gültigkeit überprüft werden sollte.

Implementieren Sie die Methode, die eine Beschreibung des Kontoereignisses zurückgibt:

//+------------------------------------------------------------------+
//| Return an account event description                              |
//+------------------------------------------------------------------+
string CAccountsCollection::EventDescription(const ENUM_ACCOUNT_EVENT event)
  {
   int total=this.m_list_accounts.Total();
   if(total==0)
      return(DFUN+TextByLanguage("Ошибка. Список изменений пуст","Error. List of changes is empty"));
   CAccount* account=this.m_list_accounts.At(this.m_index_current);
   if(account==NULL)
      return(DFUN+TextByLanguage("Ошибка. Не удалось получить данные аккаунта","Error. Failed to get account data"));
   constint dg=(account.MarginSOMode()==ACCOUNT_STOPOUT_MODE_MONEY ? (int)account.CurrencyDigits() : 2);
   conststring curency=" "+account.Currency();
   conststring mode_lev=(account.IsPercentsForSOLevels() ? "%" : " "+curency);   return
     (
      event==ACCOUNT_EVENT_NO_EVENT                ? TextByLanguage("Нет события","No event")                                                                                                                                                                     :
      event==ACCOUNT_EVENT_TRADE_ALLOWED_ON        ? TextByLanguage("Торговля на счёте разрешена","Trading on account allowed now")                                                                                                                        :
      event==ACCOUNT_EVENT_TRADE_ALLOWED_OFF       ? TextByLanguage("Торговля на счёте запрещена","Trading on account prohibited now")                                                                                                                     :
      event==ACCOUNT_EVENT_TRADE_EXPERT_ON         ? TextByLanguage("Автоторговля на счёте разрешена","Autotrading on account allowed now")                                                                                                                :
      event==ACCOUNT_EVENT_TRADE_EXPERT_OFF        ? TextByLanguage("Автоторговля на счёте запрещена","Autotrade on account prohibited now")                                                                                                               :
      event==ACCOUNT_EVENT_LEVERAGE_INC            ?
         TextByLanguage("Плечо увеличено на ","Leverage increased by ")+(string)this.GetValueChangedLeverage()+" (1:"+(string)account.Leverage()+")"                                                                                                              :
      event==ACCOUNT_EVENT_LEVERAGE_DEC            ?
         TextByLanguage("Плечо уменьшено на ","Leverage decreased by ")+(string)this.GetValueChangedLeverage()+" (1:"+(string)account.Leverage()+")"                                                                                                              :
      event==ACCOUNT_EVENT_LIMIT_ORDERS_INC        ?
         TextByLanguage("Максимально допустимое количество действующих отложенных ордеров увеличено на","Maximum allowable number of active pending orders increased by ")+(string)this.GetValueChangedLimitOrders()+" ("+(string)account.LimitOrders()+")"       :
      event==ACCOUNT_EVENT_LIMIT_ORDERS_DEC        ?
         TextByLanguage("Максимально допустимое количество действующих отложенных ордеров уменьшено на","Maximum allowable number of active pending orders decreased by ")+(string)this.GetValueChangedLimitOrders()+" ("+(string)account.LimitOrders()+")"       :
      event==ACCOUNT_EVENT_BALANCE_INC             ?
         TextByLanguage("Баланс счёта увеличен на ","Account balance increased by ")+::DoubleToString(this.GetValueChangedBalance(),dg)+curency+" ("+::DoubleToString(account.Balance(),dg)+curency+")"                                                           :
      event==ACCOUNT_EVENT_BALANCE_DEC             ?
         TextByLanguage("Баланс счёта уменьшен на ","Account balance decreased by ")+::DoubleToString(this.GetValueChangedBalance(),dg)+curency+" ("+::DoubleToString(account.Balance(),dg)+curency+")"                                                           :
      event==ACCOUNT_EVENT_EQUITY_INC              ?
         TextByLanguage("Средства увеличены на ","Equity increased by ")+::DoubleToString(this.GetValueChangedEquity(),dg)+curency+" ("+::DoubleToString(account.Equity(),dg)+curency+")"                                                                         :
      event==ACCOUNT_EVENT_EQUITY_DEC              ?
         TextByLanguage("Средства уменьшены на ","Equity decreased by ")+::DoubleToString(this.GetValueChangedEquity(),dg)+curency+" ("+::DoubleToString(account.Equity(),dg)+curency+")"                                                                         :
      event==ACCOUNT_EVENT_PROFIT_INC              ?
         TextByLanguage("Текущая прибыль счёта увеличена на ","Account current profit increased by ")+::DoubleToString(this.GetValueChangedProfit(),dg)+curency+" ("+::DoubleToString(account.Profit(),dg)+curency+")"                                            :
      event==ACCOUNT_EVENT_PROFIT_DEC              ?
         TextByLanguage("Текущая прибыль счёта уменьшена на ","Account current profit decreased by ")+::DoubleToString(this.GetValueChangedProfit(),dg)+curency+" ("+::DoubleToString(account.Profit(),dg)+curency+")"                                            :
      event==ACCOUNT_EVENT_CREDIT_INC              ?
         TextByLanguage("Предоставленный кредит увеличен на ","Credit increased by ")+::DoubleToString(this.GetValueChangedCredit(),dg)+curency+" ("+::DoubleToString(account.Credit(),dg)+curency+")"                                                            :
      event==ACCOUNT_EVENT_CREDIT_DEC              ?
         TextByLanguage("Предоставленный кредит уменьшен на ","Credit decreased by ")+::DoubleToString(this.GetValueChangedCredit(),dg)+curency+" ("+::DoubleToString(account.Credit(),dg)+curency+")"                                                            :
      event==ACCOUNT_EVENT_MARGIN_INC              ?
         TextByLanguage("Залоговые средства увеличены на ","Margin increased by ")+::DoubleToString(this.GetValueChangedMargin(),dg)+curency+" ("+::DoubleToString(account.Margin(),dg)+curency+")"                                                               :
      event==ACCOUNT_EVENT_MARGIN_DEC              ?
         TextByLanguage("Залоговые средства уменьшены на ","Margin decreased by ")+::DoubleToString(this.GetValueChangedMargin(),dg)+curency+" ("+::DoubleToString(account.Margin(),dg)+curency+")"                                                               :
      event==ACCOUNT_EVENT_MARGIN_FREE_INC         ?
         TextByLanguage("Свободные средства увеличены на ","Free margin increased by ")+::DoubleToString(this.GetValueChangedMarginFree(),dg)+curency+" ("+::DoubleToString(account.MarginFree(),dg)+curency+")"                                                  :
      event==ACCOUNT_EVENT_MARGIN_FREE_DEC         ?
         TextByLanguage("Свободные средства уменьшены на ","Free margin decreased by ")+::DoubleToString(this.GetValueChangedMarginFree(),dg)+curency+" ("+::DoubleToString(account.MarginFree(),dg)+curency+")"                                                  :
      event==ACCOUNT_EVENT_MARGIN_LEVEL_INC        ?
         TextByLanguage("Уровень залоговых средств увеличен на ","Margin level increased by ")+::DoubleToString(this.GetValueChangedMarginLevel(),dg)+"%"+" ("+::DoubleToString(account.MarginLevel(),dg)+"%)"                                                    :
      event==ACCOUNT_EVENT_MARGIN_LEVEL_DEC        ?
         TextByLanguage("Уровень залоговых средств уменьшен на ","Margin level decreased by ")+::DoubleToString(this.GetValueChangedMarginLevel(),dg)+"%"+" ("+::DoubleToString(account.MarginLevel(),dg)+"%)"                                                    :
      event==ACCOUNT_EVENT_MARGIN_INITIAL_INC      ?
         TextByLanguage("Гарантийная сумма по отложенным ордерам увеличена на ","Guarantee sum for pending orders increased by ")+::DoubleToString(this.GetValueChangedMarginInitial(),dg)+curency+" ("+::DoubleToString(account.MarginInitial(),dg)+curency+")" :
      event==ACCOUNT_EVENT_MARGIN_INITIAL_DEC      ?
         TextByLanguage("Гарантийная сумма по отложенным ордерам уменьшена на ","Guarantee sum for pending orders decreased by ")+::DoubleToString(this.GetValueChangedMarginInitial(),dg)+curency+" ("+::DoubleToString(account.MarginInitial(),dg)+curency+")" :
      event==ACCOUNT_EVENT_MARGIN_MAINTENANCE_INC  ?
         TextByLanguage("Гарантийная сумма по позициям увеличена на ","Guarantee sum for positions increased by ")+::DoubleToString(this.GetValueChangedMarginMaintenance(),dg)+curency+" ("+::DoubleToString(account.MarginMaintenance(),dg)+curency+")"        :
      event==ACCOUNT_EVENT_MARGIN_MAINTENANCE_DEC  ?
         TextByLanguage("Гарантийная сумма по позициям уменьшена на ","Guarantee sum for positions decreased by ")+::DoubleToString(this.GetValueChangedMarginMaintenance(),dg)+curency+" ("+::DoubleToString(account.MarginMaintenance(),dg)+curency+")"        :
      event==ACCOUNT_EVENT_MARGIN_SO_CALL_INC      ?
         TextByLanguage("Увеличен уровень Margin Call на ","Increased Margin Call level by ")+::DoubleToString(this.GetValueChangedMarginCall(),dg)+mode_lev+" ("+::DoubleToString(account.MarginSOCall(),dg)+mode_lev+")"                                        :
      event==ACCOUNT_EVENT_MARGIN_SO_CALL_DEC      ?
         TextByLanguage("Уменьшен уровень Margin Call на ","Decreased Margin Call level by ")+::DoubleToString(this.GetValueChangedMarginCall(),dg)+mode_lev+" ("+::DoubleToString(account.MarginSOCall(),dg)+mode_lev+")"                                        :
      event==ACCOUNT_EVENT_MARGIN_SO_SO_INC        ?
         TextByLanguage("Увеличен уровень Stop Out на ","Increased Margin Stop Out level by ")+::DoubleToString(this.GetValueChangedMarginStopOut(),dg)+mode_lev+" ("+::DoubleToString(account.MarginSOSO(),dg)+mode_lev+")"                                      :
      event==ACCOUNT_EVENT_MARGIN_SO_SO_DEC        ?
         TextByLanguage("Уменьшен уровень Stop Out на ","Decreased Margin Stop Out level by ")+::DoubleToString(this.GetValueChangedMarginStopOut(),dg)+mode_lev+" ("+::DoubleToString(account.MarginSOSO(),dg)+mode_lev+")"                                      :
      event==ACCOUNT_EVENT_ASSETS_INC              ?
         TextByLanguage("Размер активов увеличен на ","Assets increased by ")+::DoubleToString(this.GetValueChangedAssets(),dg)+" ("+::DoubleToString(account.Assets(),dg)+")"                                                                                    :
      event==ACCOUNT_EVENT_ASSETS_DEC              ?
         TextByLanguage("Размер активов уменьшен на ","Assets decreased by ")+::DoubleToString(this.GetValueChangedAssets(),dg)+" ("+::DoubleToString(account.Assets(),dg)+")"                                                                                    :
      event==ACCOUNT_EVENT_LIABILITIES_INC         ?
         TextByLanguage("Размер обязательств увеличен на ","Liabilities increased by ")+::DoubleToString(this.GetValueChangedLiabilities(),dg)+" ("+::DoubleToString(account.Liabilities(),dg)+")"                                                                :
      event==ACCOUNT_EVENT_LIABILITIES_DEC         ?
         TextByLanguage("Размер обязательств уменьшен на ","Liabilities decreased by ")+::DoubleToString(this.GetValueChangedLiabilities(),dg)+" ("+::DoubleToString(account.Liabilities(),dg)+")"                                                                :
      event==ACCOUNT_EVENT_COMISSION_BLOCKED_INC   ?
         TextByLanguage("Размер заблокированных комиссий увеличен на ","Blocked commissions increased by ")+::DoubleToString(this.GetValueChangedComissionBlocked(),dg)+" ("+::DoubleToString(account.ComissionBlocked(),dg)+")"                                   :
      event==ACCOUNT_EVENT_COMISSION_BLOCKED_DEC   ?
         TextByLanguage("Размер заблокированных комиссий уменьшен на ","Blocked commissions decreased by ")+::DoubleToString(this.GetValueChangedComissionBlocked(),dg)+" ("+::DoubleToString(account.ComissionBlocked(),dg)+")"                                   :
      ::EnumToString(event)
     );
  }
//+------------------------------------------------------------------+

Hier wird das Kontoereignis an die Methode übergeben, deren Beschreibung erhalten werden soll. Überprüfen Sie die Größe der Objektliste des Kontos. Wenn sie leer ist, geben Sie die Fehlerbeschreibung zurück. Da wir nur die aktuellen Kontoereignisse verfolgen können, erhalten wir das aktuelle Kontoobjekt aus der Kontenliste über den Index des aktuellen Kontoobjekts. Wenn kein Objekt empfangen wird, geben Sie auch die Fehlerbeschreibung zurück.
Als nächstes, erhalten Sie die notwendigen Kontoeigenschaften für die korrekte Anzeige der Ereignisbeschreibung, überprüfen Sie das Ereignis und geben Sie seine Beschreibung zurück.

In der Initialisierungsliste des Klassenkonstruktors initialisieren Sie die Symbolvariablen und die ID des Programms auf dem Chart mit den Standardwerten — das aktuelle Symbol und das aktuelle Chart, Löschen Sie die Struktur der Ticks, wir müssen die Ereigniszeit definieren und initialisieren Sie editierbare und kontrollierte Kontenparameter:

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

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

Fügen Sie schließlich der Methode zur Aktualisierung der veränderten Kontodaten hinzu:

//+------------------------------------------------------------------+
//| Update the current account data                                  |
//+------------------------------------------------------------------+
void CAccountsCollection::Refresh(void)
  {
   this.m_is_account_event=false;
   if(this.m_index_current==WRONG_VALUE)
      return;
   CAccount* account=this.m_list_accounts.At(this.m_index_current);
   if(account==NULL)
      return;
   ::ZeroMemory(this.m_struct_curr_account);
   this.SetAccountsParams(account);
   
//--- Erster Start
   if(!this.m_struct_prev_account.login)
     {
      this.m_struct_prev_account=this.m_struct_curr_account;
      return;
     }
//--- f the account hash sum changed
   if(this.m_struct_curr_account.hash_sum!=this.m_struct_prev_account.hash_sum)
     {
      this.m_change_code=this.SetChangeCode();
      this.SetTypeEvent();
      int total=this.m_list_changes.Total();
      if(total>0)
        {
         this.m_is_account_event=true;
         for(int i=0;i<total;i++)
           {
            ENUM_ACCOUNT_EVENT event=this.GetEvent(i);
            if(event==NULL || !::SymbolInfoTick(this.m_symbol,this.m_tick))
               continue;
            string sparam=TimeMSCtoString(this.m_tick.time_msc)+": "+this.EventDescription(event);
            Print(sparam);
            ::EventChartCustom(this.m_chart_id,(ushort)event,this.m_tick.time_msc,(double)i,sparam);
           }
        }
      this.m_struct_prev_account.hash_sum=this.m_struct_curr_account.hash_sum;
     }
  }
//+------------------------------------------------------------------+
Zuerst setzen Sie das Flag für das Kontoereignis zurück. Da wir die Methode SavePrevValues() entfernt haben, fügen wir stattdessen die Zeichenkette hinzu — zum Speichern der aktuellen Datenstruktur in den vorherigen Daten beim ersten Start. Wenn Sie den Hash ändern, überprüfen und setzen Sie den Ereigniscode und den aufgetretenen Ereignistyp.

Bei der Methode zur Einstellung des Ereignistyps werden alle Ereignisse, die gleichzeitig in den Kontoeigenschaften aufgetreten sind, an die Änderungsliste übergeben. Überprüfen Sie daher zuerst die Größe der Änderungsliste. Wenn sie nicht leer ist, setzen Sie das aufgetretenen Änderungsflag, übernehmen Sie das Ereignisin einer Schleife durch die Listendaten, setzen Sie die Zeichenkettenbeschreibung in Form der Zeit in Millisekunden und der Ereignisbeschreibung, zeigen Sie temporär die Ereignisbeschreibung im Journal an (diese Funktion soll später entfernt werden, alle Meldungen des Bibliothekssystems sollen im Journal nur angezeigt werden, wenn die Protokollierung aktiviert ist) und senden Sie schließlich das Ereignis über EventChartCustom() an das Steuerungsprogramm.

In den Parametern der Funktion EventChartCustom() übergeben Sie:

  • ein Ereignis — über die event_id,
  • eine Ereigniszeit in Millisekunden — über lparam
  • Ereignisindex in der Liste der gleichzeitig aufgetretenen Kontoänderungen — über dparam
  • Beschreibung der Ereigniszeichenkette — über sparam

Am Ende der Methode stellen Sie sicher, dass Sie den aktuellen Hash als den vorherigen speichern, für eine spätere Verifizierung.

Damit ist die Verbesserung der Klasse CAccountsCollection abgeschlossen.

Kommen wir nun zur Klasse CEngine , die das Alpha und Omega der Bibliothek ist. Wir müssen alle notwendigen Funktionen für die Arbeit mit Kontoereignissen hinzufügen.

Fügen Sie im privaten Bereich der Klasse die Variablen zur Speicherung des Kennzeichens der Kontoeigenschaften Change Event und das letzte Ereignis auf dem Konto hinzu. Fügen Sie im 'public' Bereich die Methoden hinzu, die die Liste der gleichzeitig aufgetretenen Kontoereignisse und das letzte Kontoereignis zurückgeben:

//+------------------------------------------------------------------+
//| Bibliothek der Basisklasse                                       |
//+------------------------------------------------------------------+
class CEngine : public CObject
  {
private:
   CHistoryCollection   m_history;                       // Kollektion der historischen Aufträge und Deals
   CMarketCollection    m_market;                        // Kollektion der Marktorder und Deals
   CEventsCollection    m_events;                        // Event collection
   CAccountsCollection  m_accounts;                      // Account collection
   CArrayObj            m_list_counters;                 // Liste der Timerzähler
   bool                 m_first_start;                   // Flag des Erststarts
   bool                 m_is_hedge;                      // Flag des Hedging-Kontos
   bool                 m_is_tester;                     // Flag of working in the tester
   bool                 m_is_market_trade_event;         // Flag eines Handelsereignisses des Kontos
   bool                 m_is_history_trade_event;        // Flag eines historischen Handelsereignisses auf dem Konto
   bool                 m_is_account_event;              // Account change event flag
   ENUM_TRADE_EVENT     m_last_trade_event;              // Account last trading event
   ENUM_ACCOUNT_EVENT   m_last_account_event;            // Last event in account properties
//--- Rückgabe des Zählerindex über die ID
   int                  CounterIndex(constint id) const;
//--- Return (1) the first launch flag, (2) the flag presence in a trading event
   bool                 IsFirstStart(void);
//--- Working with (1) order, deal and position, as well as (2) account events
   void                 TradeEventsControl(void);
   void                 AccountEventsControl(void);
//--- Rückgabe der letzten (1) Pending-Order, (2) Marktorder, (3) letzten Position, (4) Position nach Ticket
   COrder*              GetLastMarketPending(void);
   COrder*              GetLastMarketOrder(void);
   COrder*              GetLastPosition(void);
   COrder*              GetPosition(constulong ticket);
//--- Return the last (1) removed pending order, (2) historical market order, (3) historical order (market or pending) by its ticket
   COrder*              GetLastHistoryPending(void);
   COrder*              GetLastHistoryOrder(void);
   COrder*              GetHistoryOrder(constulong ticket);
//--- Rückgabe des (1) ersten und (2) des letzten historischen Marktorder aus der Liste aller Positionen, (3) des letzten Deals
   COrder*              GetFirstOrderPosition(constulong position_id);
   COrder*              GetLastOrderPosition(constulong position_id);
   COrder*              GetLastDeal(void);
public:
   //--- Rückgabe der Liste aller (1) Positionen, (2) Pending-Order und (3) Marktorders
   CArrayObj*           GetListMarketPosition(void);
   CArrayObj*           GetListMarketPendings(void);
   CArrayObj*           GetListMarketOrders(void);
   //--- Rückgabe der Liste aller historischen (1) Aufträge, (2) gelöschten Pending-Orders, (3) Deals, (4) Positionen nach deren ID
   CArrayObj*           GetListHistoryOrders(void);
   CArrayObj*           GetListHistoryPendings(void);
   CArrayObj*           GetListDeals(void);
   CArrayObj*           GetListAllOrdersByPosID(constulong position_id);
//--- Return the list of (1) accounts, (2) account events
   CArrayObj*           GetListAllAccounts(void)                        { returnthis.m_accounts.GetList();          }
   CArrayInt*           GetListAccountEvents(void)                      { returnthis.m_accounts.GetListChanges();   }
//--- Return the list of order, deal and position events
   CArrayObj*           GetListAllOrdersEvents(void)                    { returnthis.m_events.GetList();            }
//--- Rücksetzen des letzten Handelsereignisses
   void                 ResetLastTradeEvent(void)                       { this.m_events.ResetLastTradeEvent(); }
//--- Return the (1) last trading event, (2) the last event in the account properties, (3) hedging account flag, (4) flag of working in the tester
   ENUM_TRADE_EVENT     LastTradeEvent(void)                      const { returnthis.m_last_trade_event;            }
   ENUM_ACCOUNT_EVENT   LastAccountEvent(void)                    const { returnthis.m_last_account_event;          }
   bool                 IsHedge(void)                             const { returnthis.m_is_hedge;                    }
   bool                 IsTester(void)                            const { returnthis.m_is_tester;                   }
//--- Erstellen der Timerzählers
   void                 CreateCounter(constint id,constulong frequency,constulong pause);
//--- Timer
   void                 OnTimer(void);
//--- Constructor/Destructor
                        CEngine();
                       ~CEngine();
  };
//+------------------------------------------------------------------+

Hinzufügen der Initialisierung des letzten Kontoereignisses in der Initialisierungsliste des Klassenkonstruktors:

//+------------------------------------------------------------------+
//| CEngine Konstruktor                                              |
//+------------------------------------------------------------------+
CEngine::CEngine() : m_first_start(true),m_last_trade_event(TRADE_EVENT_NO_EVENT),m_last_account_event(ACCOUNT_EVENT_NO_EVENT)
  {

Hinzufügen der Methode AccountEventsControl(), die bisher nur zum Aufruf der Methode Refresh() der Klasse der Kollektion der Konten verwendet wurde:

//+------------------------------------------------------------------+
//| Check account events                                             |
//+------------------------------------------------------------------+
void CEngine::AccountEventsControl(void)
  {
//--- Check account property changes and set the flag of the account change events
   this.m_accounts.Refresh();
   this.m_is_account_event=this.m_accounts.IsAccountEvent();
//--- If there are account property changes
   if(this.m_is_account_event)
     {
      //--- Get the last event of the account property change
      this.m_last_account_event=this.m_accounts.GetEvent();
     }
  }
//+------------------------------------------------------------------+

Hier ist alles einfach. Zuerst aktualisieren Sie die Kontodaten. Wenn sich eine der Kontoeigenschaften geändert hat, schreiben Sie einfach das letzte Ereignis in die Variable. Alle übrigen Daten zum Ereignis werden im bibliotheksbasierten Steuerprogramm abgerufen.

Testen der Kontoereignisse

Um die Kontoereignisse zu testen, können wir den EA aus dem vorherigen Artikel verwenden, da die Bibliothek alle Kontoeigenschaften selbstständig findet, eine entsprechende Nachricht an das Diagrammereignis sendet und die Beschreibung des aufgetretenen Kontoereignisses im Journal anzeigt.
Aber lasst uns versuchen, über die Bibliothek "Sandbox" hinauszugehen und einige Kontoereignisse im Programm zu behandeln, z.B. die Erhöhung des Kapitals.

Derzeit ist der Zugriff auf die Programmfunktionen von außen sehr eingeschränkt. Dies ist jedoch nur so lange der Fall, bis wir die notwendigen Daten gesammelt und verarbeitet haben — die Bibliothek zeigt verschiedene Ereignisse im Journal an, um die Richtigkeit der erstellten Klassen, gesammelten Daten und verfolgten Ereignisse zu testen. Darüber hinaus werden wir einen einfachen und bequemen Zugriff auf alle Bibliotheksdaten einführen, der deren Abruf aus dem Programm erheblich vereinfacht.

Um bereits jetzt Daten über Änderungen der Kontoeigenschaften zu erhalten, sollten wir die Klasse CEngine leicht verbessern. Wir müssen Zugang zum Objekt und zu den Ereignissen des laufenden Kontos erhalten.
Dazu fügen Sie die notwendigen Methoden im öffentlichen Teil der Klasse CEngine (die Datei Engine.mqh) hinzu:

public:
   //--- Rückgabe der Liste aller (1) Positionen, (2) Pending-Order und (3) Marktorders
   CArrayObj*           GetListMarketPosition(void);
   CArrayObj*           GetListMarketPendings(void);
   CArrayObj*           GetListMarketOrders(void);
   //--- Rückgabe der Liste aller historischen (1) Aufträge, (2) gelöschten Pending-Orders, (3) Deals, (4) Positionen nach deren ID
   CArrayObj*           GetListHistoryOrders(void);
   CArrayObj*           GetListHistoryPendings(void);
   CArrayObj*           GetListDeals(void);
   CArrayObj*           GetListAllOrdersByPosID(constulong position_id);
//--- Return the list of (1) accounts, (2) account events, (3) account change event by its index in the list
//--- (4) the current account, (5) event description
   CArrayObj*           GetListAllAccounts(void)                        { return this.m_accounts.GetList();          }
   CArrayInt*           GetListAccountEvents(void)                      { return this.m_accounts.GetListChanges();   }
   ENUM_ACCOUNT_EVENT   GetAccountEventByIndex(const int index)         { return this.m_accounts.GetEvent(index);    }
   CAccount*            GetAccountCurrent(void);
   string               GetAccountEventDescription(ENUM_ACCOUNT_EVENT event);
   

Hier haben wir die Methode zum Empfangen eines Kontoereignisses durch seinen Index in der Änderungsliste, die Methode zum Empfangen des aktuellen Kontoobjekts und die Methode zum Empfangen der Kontoereignisbeschreibung hinzugefügt.

Die Methode zum Empfangen eines Kontoereignisses über den Index gibt einfach das Operationsergebnis der zuvor beschriebenen Methode GetEvent() in der Klasse der Kontensammlung zurück.

Am Ende der Auflistung, Implementieren Sie die Methode zum Empfangen des Objekts des aktuellen Kontos:

//+------------------------------------------------------------------+
//| Return the current account                                       |
//+------------------------------------------------------------------+
CAccount* CEngine::GetAccountCurrent(void)
  {
   int index=this.m_accounts.IndexCurrentAccount();
   if(index==WRONG_VALUE)
      return NULL;
   CArrayObj* list=this.m_accounts.GetList();   
   return(list!=NULL ? (list.At(index)!=NULL ? list.At(index) : NULL) : NULL);  
  }
//+------------------------------------------------------------------+

Zuerst erhalten Sie den Index des aktuellen Kontos aus der Klasse der Kontenerhebung. Wenn kein Index empfangen wird, geben Sie NULL zurück. Als nächstes, erhalten Sie die vollständige Liste der Konten und geben Sie das benötigte, aktuelle Konto über seinen Index in der Kontenliste zurück. Im Falle eines Listen- oder Kontenfehlers wird NULL zurückgegeben.

Außerdem implementieren wir die Methode, die eine Beschreibung des Kontoereignisses zurückgibt:

//+------------------------------------------------------------------+
//| Return the account event description                             |
//+------------------------------------------------------------------+
string CEngine::GetAccountEventDescription(ENUM_ACCOUNT_EVENT event)
  {
   return this.m_accounts.EventDescription(event);
  }
//+------------------------------------------------------------------+

Die Methode gibt das Operationsergebnis der Methode der Kontenerfassungsklasse zurück, die die Beschreibung des Kontoereignisses zurückgibt.

Um die Kontoereignisse zu testen, verwenden Sie den EA aus dem vorherigen ArtikelTestDoEasyPart12_2.mq5, das sich in \MQL5\Experts\TestDoEasy\Part12\ befindet, und speichern Sie ihn als TestDoEasyPart13.mq5 in \MQL5\Experts\TestDoEasy\Part13.

Entfernen Sie sofort den folgenden Eingabeparameter.

inputbool     InpFullProperties    =  false;// Show full accounts properties

zusammen mit der Schnellprüfung der Kollektion der Konten in OnInit():

//--- Fast check of the account object collection   
   CArrayObj* list=engine.GetListAllAccounts();
   if(list!=NULL)
     {
      int total=list.Total();
      if(total>0)
         Print("\n",TextByLanguage("=========== Список сохранённых аккаунтов ===========","=========== List of saved accounts ==========="));
      for(int i=0;i<total;i++)
        {
         CAccount* account=list.At(i);
         if(account==NULL)
            continue;
         Sleep(100);
         if(InpFullProperties)
            account.Print();
         else
            account.PrintShort();
        }
     }
//---

Seit wir die Objektstruktur des Kontos geändert haben (geänderte Größe der uchar-Arrays zum Speichern von Zeichenketteneigenschaften und eine weitere ganzzahlige Eigenschaft), werden alle zuvor gespeicherten Kontoobjektdateien nicht mehr korrekt heruntergeladen. Wenn sie in \Files\DoEasy\Accounts\ des gemeinsamen Terminalordners vorhanden sind, löschen Sie sie, bevor Sie den Test-EA starten. Sie werden beim Wechsel von einem Konto zum anderen mit einer bereits neuen Objektstrukturgröße neu angelegt.

Der OnInit() Handler sieht nun wie folgt aus:

//+------------------------------------------------------------------+
//| 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 and remove remaining EA graphical objects
   if(IsPresentObects(prefix))
      ObjectsDeleteAll(0,prefix);

//--- Create the button panel
   if(!CreateButtons(InpButtShiftX,InpButtShiftY))
      returnINIT_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);
  }
//+------------------------------------------------------------------+

Um alle Ereignisse zu behandeln, die aus der Bibliothek in das Programm gelangen, und um das integrierte OnChartEvent() nicht zu überladen, implementieren Sie eine separate Funktion OnDoEasyEvent(), um alle erhaltenen Ereignisse darin zu verarbeiten. Dies macht den Code lesbarer und ermöglicht es uns vor allem, Ereignisse im Tester zu behandeln, was genau das ist, was wir gerade jetzt brauchen, da wir das Kontoereignis "Kapitalerhöhung über den angegebenen Wachstumswert hinaus" behandeln werden, und es ist viel schneller und einfacher, alles im Tester zu überprüfen, um dies zu erreichen.


Lassen Sie uns die notwendige Funktionalität für die Behandlung der Kontoereignisse im OnTick() Handler hinzufügen:

//+------------------------------------------------------------------+
//| Experten Funktion OnTick                                         |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Initialize the last events
   static ENUM_TRADE_EVENT last_trade_event=WRONG_VALUE;
   static ENUM_ACCOUNT_EVENT last_account_event=WRONG_VALUE;
//--- If working in the tester
   if(MQLInfoInteger(MQL_TESTER))
     {
      engine.OnTimer();
      PressButtonsControl();
     }
//--- If the last trading event changed
   if(engine.LastTradeEvent()!=last_trade_event)
     {
      last_trade_event=engine.LastTradeEvent();
      Comment("\nLast trade event: ",EnumToString(last_trade_event));
     }
//--- If the last account event changed
   if(engine.LastAccountEvent()!=last_account_event)
     {
      last_account_event=engine.LastAccountEvent();
      //--- If this is a tester
      if(MQLInfoInteger(MQL_TESTER))
        {
         //--- Get the list of all account events occurred simultaneously
         CArrayInt* list=engine.GetListAccountEvents();
         if(list!=NULL)
           {
            //--- Get the next event in a loop
            int total=list.Total();
            for(int i=0;i<total;i++)
              {
               ENUM_ACCOUNT_EVENT event=(ENUM_ACCOUNT_EVENT)list.At(i);
               if(event==NULL)
                  continue;
               string sparam=engine.GetAccountEventDescription(event);
               long lparam=TimeCurrent()*1000;
               double dparam=(double)i;
               //--- Send an event to the event handler
               OnDoEasyEvent(CHARTEVENT_CUSTOM+event,lparam,dparam,sparam);
              }
           }
        }
      Comment("\nLast account event: ",EnumToString(last_account_event));
     }
//--- If the trailing flag is set
   if(trailing_on)
     {
      TrailingPositions();
      TrailingOrders();
     }
  }
//+------------------------------------------------------------------+

Hier haben wir die neue Variable eingeführt, die den Typ des letzten Kontoereignisses speichert. Überprüfen Sie den aktuellen Status in Bezug auf die Art des letzten Ereignisses, das von der Klasse CAccountsCollection zurückgegeben wird . Wenn sich der Status geändert hat, gab es ein Kontoereignis. Als nächstes, nur für den Tester, holen Sie sich ein neues Ereignis in einer Schleife gemäß der Kontenliste der gleichzeitig aufgetretenen Ereignisse und senden Sie es an den Library Event Handler. Die Listenkommentare enthalten alle Aktionen, um Ereignisse zu empfangen und an den Handler zu senden. Bei der Arbeit mit dem Tester können wir nicht auf Daten zu einer Ereigniszeit in Millisekunden zugreifen. Senden Sie daher einfach die aktuelle Zeit * 1000.

Nun verbessern wir die Ereignisbehandlung durch OnChartEvent():

//+------------------------------------------------------------------+
//| Funktion der Chart-Ereignisse                                        |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   if(MQLInfoInteger(MQL_TESTER))
      return;
   if(id==CHARTEVENT_OBJECT_CLICK && StringFind(sparam,"BUTT_")>0)
     {
      PressButtonEvents(sparam);
     }
//--- DoEasy library event
   if(id>=CHARTEVENT_CUSTOM)
     {
      OnDoEasyEvent(id,lparam,dparam,sparam);
     } 
  }
//+------------------------------------------------------------------+

Hier haben wir den Aufruf der Ereignisbehandlung der Bibliothek hinzugefügt, falls die Ereignis-ID ein Bibliotheksereignis anzeigt.

Schließlich implementieren Sie dei Ereignisbehandlung der Bibliothek:.

//+------------------------------------------------------------------+
//| Handling DoEasy library events                                   |
//+------------------------------------------------------------------+
void OnDoEasyEvent(const int id,
                   const long &lparam,
                   const double &dparam,
                   const string &sparam)
  {
   int idx=id-CHARTEVENT_CUSTOM;
   string event="::"+string(idx);
   int digits=Digits();
//--- Handling trading events
   if(idx<TRADE_EVENTS_NEXT_CODE)
     {
      event=EnumToString((ENUM_TRADE_EVENT)ushort(idx));
      digits=(int)SymbolInfoInteger(sparam,SYMBOL_DIGITS);
     }
//--- Handling account events
   else if(idx<ACCOUNT_EVENTS_NEXT_CODE)
     {
      event=EnumToString((ENUM_ACCOUNT_EVENT)ushort(idx));
      digits=0;
      
      //--- if this is an equity increase
      if((ENUM_ACCOUNT_EVENT)idx==ACCOUNT_EVENT_EQUITY_INC)        
        {
         Print(DFUN,sparam);
         //--- Close a position with the highest profit when the equity exceeds the value
         //--- specified in the CAccountsCollection::InitControlsParams() method for
         //--- the m_control_equity_inc variable tracking the equity growth by 15 units (by default)
         //--- AccountCollection file, InitControlsParams() method, string 1199
         
         //--- Abrufen der Liste aller offenen Positionen
         CArrayObj* list_positions=engine.GetListMarketPosition();
         //--- 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 
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+

Beim Senden eines Ereignisses an die Regelprogrammkarte wird der Wert von CHARTEVENT_CUSTOM gleich 1000 in den Code eingefügt. Um einen echten Code zu erhalten, müssen wir daher den Wert CHARTEVENT_CUSTOM vom erhaltenen Code abziehen. Wenn der Zahlenwert des Ereignisses im Bereich von TRADE_EVENTS_NEXT_CODE bis ACCOUNT_EVENTS_NEXT_CODE-1 liegt, bedeutet dies, dass ein Ereignis zur Änderung der Kontoeigenschaften eingetroffen ist. Da wir die profitabelste Position schließen wollen, wenn das Eigenkapital über den in den Einstellungen angegebenen Wert hinaus steigt (der voreingestellte Wachstumswert ist 15 und höher), müssen wir das "Eigenkapital über dem angegebenen Wert" Ereignis überprüfen, die Ereignisbeschreibung im Journal anzeigen und die profitabelste Position schließen. Der Code enthält alle notwendigen Kommentare.

Wenn wir jetzt einfach den EA auf dem Chart starten, erhalten wir die Journalbuchungen über den Handel, der nach einer Weile aktiviert/deaktiviert wird:

2019.06.1010:56:33.8772019.06.1006:55:29.279: Trading on the account is prohibited now
2019.06.1011:08:56.5492019.06.1007:08:51.900: Trading on the account is allowed now

Auf dem Demokonto von MetaQuotes können solche Aktivierungen/Deaktivierungen mehrmals täglich beobachtet werden, so dass wir überprüfen können, wie die Bibliothek solche Ereignisse auf einem Demokonto definiert.

Starten Sie nun den EA im Tester und eröffnen Sie weitere Positionen, um das Ereignis der Eigenkapitalerhöhung schnell zu erkennen, gefolgt vom Schließen der profitabelsten Position:


Wie wir sehen können, wird die profitabelste Position automatisch geschlossen, wenn das Eigenkapital den angegebenen Wert erreicht. Das Journal zeigt die Meldungen über das verfolgte Kontoereignis an.

Was kommt als Nächstes?

Im nächsten Teil werde ich mit der Arbeit mit Symbolen beginnen. Ich möchte Symbolobjekte, Symbolobjektsammlung und Symbolereignisse implementieren.

Alle Dateien der aktuellen Version der Bibliothek sind unten zusammen mit den Dateien der Test-EAs angehängt, die Sie herunterladen und testen 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.

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

Beigefügte Dateien |
MQL5.zip (129.92 KB)
MQL4.zip (127.28 KB)
Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil XIII): Objektklasse "Account" und die Kollektion von Konto-Objekten Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil XIII): Objektklasse "Account" und die Kollektion von Konto-Objekten

Im vorherigen Artikel haben wir für MQL4 in der Bibliothek der Ereignisse des Positionsschließens definiert und die ungenutzten Auftragseigenschaften beseitigt. Hier werden wir die Erstellung des Konto-Objekts betrachten, die Kollektion von Konto-Objekten entwickeln und die Funktionsweise zur Verfolgung von Konto-Ereignissen vorbereiten.

Entwicklung eines plattformübergreifenden Grider-EAs (Teil III): Korrekturbasiertes Raster mit Martingal Entwicklung eines plattformübergreifenden Grider-EAs (Teil III): Korrekturbasiertes Raster mit Martingal

In diesem Artikel werden wir versuchen, den bestmögliche, rasterbasierten EA zu entwickeln. Wie üblich wird dies ein plattformübergreifender EA sein, der sowohl mit MetaTrader 4 als auch mit MetaTrader 5 arbeiten kann. Der erste EA war gut genug, außer dass er über einen langen Zeitraum keinen Gewinn erzielen konnte. Der zweite EA konnte in Zeiträumen von mehr als einigen Jahren arbeiten. Leider konnte er nicht mehr als 50% Gewinn pro Jahr bei einem maximalen Drawdown von weniger als 50% erzielen.

Eine neue Schiene: Benutzerdefinierte Indikatoren in MQL5 Eine neue Schiene: Benutzerdefinierte Indikatoren in MQL5

Ich werde nicht alle neuen Möglichkeiten und Funktionen des neuen Terminals und der Sprache aufzählen. Sie sind zahlreich und einige der Neuheiten sind eine Diskussion in einem eigenen Beitrag wert. Auch gibt es hier keinen Code, der mit objektorientierter Programmierung geschrieben wurde. Das Thema ist zu wichtig, um es nur im Kontext zusätzlicher Vorteile für Entwickler zu erwähnen. In diesem Beitrag gehen wir auf Indikatoren, ihre Struktur, Zeichnung, Typen und Programmierdetails im Vergleich zu MQL4 ein. Ich hoffe, dass dieser Beitrag für Einsteiger und erfahrene Entwickler hilfreich sein wird. Vielleicht entdeckt auch jemand etwas Neues.

Hier sind der neue MetaTrader 5 und MQL5 Hier sind der neue MetaTrader 5 und MQL5

Dies ist nur ein kurzer Überblick über MetaTrader 5. Ich kann nicht alle neuen Funktionen des Systems in so kurzer Zeit beschreiben. Die Tests begannen am 09.09.2009. Das ist ein symbolisches Datum und ich bin sicher, dass es eine Glückszahl werden wird. Es sind ein paar Tage vergangen, seit ich die Beta-Version des MetaTrader-5-Terminals und MQL5 bekommen habe. Ich konnte noch nicht alle Funktionen ausprobieren, doch ich bin jetzt schon beeindruckt.