Biblioteca para criação simples e rápida de programas para MetaTrader (Parte XXII): classes de negociação - classe básica de negociação, controle de restrições

29 janeiro 2020, 11:00
Artyom Trishkin
0
1 411

Sumário

No último artigo, abrimos uma seção extensa da biblioteca que estava dedicada às funções de negociação e criamos o objeto básico de negociação do símbolo. Este objeto de negociação recebia nos seus parâmetros todas as propriedades da solicitação de negociação enviada ao servidor, preenchia a estrutura da solicitação de negociação de acordo com o tipo do método de classe chamado (abertura de posição/posicionamento de ordem pendente/modificação/fechamento/remoção) e enviava a ordem de negociação ao servidor. Tivemos a mesma opinião quanto à concepção de que, para o envio da ordem de negociação, ao objeto básico de negociação são transferidos os valores corretos das propriedades da solicitação de negociação. Porém, para o pleno uso do sistema de negociação, primeiro precisávamos verificar as restrições existentes quanto à realização de operações de negociação no terminal, no programa, na conta e no símbolo. Já depois dessas verificações iniciais, podíamos verificar se as propriedades da solicitação de negociação estavam certas.

Hoje começaremos a criar uma classe de negociação integral, e a primeira coisa que faremos para concretização de um trabalho completo e confortável com a funcionalidade de negociação da biblioteca é verificar as restrições quanto à realização de operações de negociação.

Ideia

Já temos um objeto básico de negociação que faz parte do objeto-símbolo. Ele realiza a simples tarefa de preencher a estrutura da solicitação de negociação (de acordo com os parâmetros transferidos a um dos métodos da classe) e de enviar a ordem de negociação ao servidor. Hoje, antes de começarmos a fazer uma classe de negociação integral, adicionaremos um pouco de funcionalidade ao objeto básico de negociação, em outras palavras, adicionaremos a capacidade de sonorizar os resultados do envio de ordens de negociação. Como resultado, poderemos definir qualquer som para sonorizar eventos de negociação. Além disso, para cada símbolo, poderemos definir sons individuais para cada um dos eventos de negociação. Mas também, certamente, poderemos definir um conjunto comum de sons - para cada um dos eventos - que será igual para todos os símbolos. Em geral, o sistema básico de negociação dará amplas possibilidades para definir sons de eventos de negociação, sons esses que poderão ser tanto idênticos para todos os símbolos e eventos quanto individuais para um único símbolo e um único evento.

Em seguida, criaremos uma classe de negociação, a partir da qual mais adiante realizaremos todas as operações de negociação. Hoje, esta classe terá capacidade de verificar a permissão para realizar operações de negociação e de chamar os métodos de objetos básicos de negociação dos símbolos.

Expandindo a funcionalidade do objeto básico de negociação

Para definir os sons dos eventos de negociação, precisamos de substituições de macro e enumerações. Abrimos o arquivo Defines.mqh, e inserimos nele as substituições de macros que trocam os nomes dos arquivos de som padrão:

//+------------------------------------------------------------------+
//| Macro substitutions                                              |
//+------------------------------------------------------------------+
//--- Describe the function with the error line number
#define DFUN_ERR_LINE                  (__FUNCTION__+(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian" ? ", Page " : ", Line ")+(string)__LINE__+": ")
#define DFUN                           (__FUNCTION__+": ")        // "Function description"
#define COUNTRY_LANG                   ("Russian")                // Country language
#define END_TIME                       (D'31.12.3000 23:59:59')   // End date for account history data requests
#define TIMER_FREQUENCY                (16)                       // Minimal frequency of the library timer in milliseconds
//--- Standard sounds
#define SND_ALERT                      "alert.wav"
#define SND_ALERT2                     "alert2.wav"
#define SND_CONNECT                    "connect.wav"
#define SND_DISCONNECT                 "disconnect.wav"
#define SND_EMAIL                      "email.wav"
#define SND_EXPERT                     "expert.wav"
#define SND_NEWS                       "news.wav"
#define SND_OK                         "ok.wav"
#define SND_REQUEST                    "request.wav"
#define SND_STOPS                      "stops.wav"
#define SND_TICK                       "tick.wav"
#define SND_TIMEOUT                    "timeout.wav"
#define SND_WAIT                       "wait.wav"
//--- Parameters of the orders and deals collection timer

Simplesmente, assim é mais conveniente definir nomes para configurar arquivos de som padrão, se quisermos usá-los como arquivos de som para sonorizar eventos de negociação.

No final da listagem, no bloco de dados para trabalhar com classes de negociação
inserimos a enumeração de tipos de operações de negociação e a enumeração dos modos de configuração de som:

//+------------------------------------------------------------------+
//| Data for working with trading classes                            |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|  Logging level                                                   |
//+------------------------------------------------------------------+
enum ENUM_LOG_LEVEL
  {
   LOG_LEVEL_NO_MSG,                                        // Trading logging disabled
   LOG_LEVEL_ERROR_MSG,                                     // Only trading errors
   LOG_LEVEL_ALL_MSG                                        // Full logging
  };
//+------------------------------------------------------------------+
//| Types of performed operations                                    |
//+------------------------------------------------------------------+
enum ENUM_ACTION_TYPE
  {
   ACTION_TYPE_BUY               =  ORDER_TYPE_BUY,               // Open Buy
   ACTION_TYPE_SELL              =  ORDER_TYPE_SELL,              // Open Sell
   ACTION_TYPE_BUY_LIMIT         =  ORDER_TYPE_BUY_LIMIT,         // Place BuyLimit
   ACTION_TYPE_SELL_LIMIT        =  ORDER_TYPE_SELL_LIMIT,        // Place SellLimit
   ACTION_TYPE_BUY_STOP          =  ORDER_TYPE_BUY_STOP,          // Place BuyStop
   ACTION_TYPE_SELL_STOP         =  ORDER_TYPE_SELL_STOP,         // Place SellStop
   ACTION_TYPE_BUY_STOP_LIMIT    =  ORDER_TYPE_BUY_STOP_LIMIT,    // Place BuyStopLimit
   ACTION_TYPE_SELL_STOP_LIMIT   =  ORDER_TYPE_SELL_STOP_LIMIT,   // Place SellStopLimit
   ACTION_TYPE_CLOSE_BY          =  ORDER_TYPE_CLOSE_BY,          // Close a position by an opposite one
   ACTION_TYPE_MODIFY            =  ACTION_TYPE_CLOSE_BY+1,       // Modification
  };
//+------------------------------------------------------------------+
//| Sound setting mode                                               |
//+------------------------------------------------------------------+
enum ENUM_MODE_SET_SOUND
  {
   MODE_SET_SOUND_OPEN,                                     // Opening/placing sound setting mode
   MODE_SET_SOUND_CLOSE,                                    // Closing/removal sound setting mode
   MODE_SET_SOUND_MODIFY_SL,                                // StopLoss modification sound setting mode
   MODE_SET_SOUND_MODIFY_TP,                                // TakeProfit modification sound setting mode
   MODE_SET_SOUND_MODIFY_PRICE,                             // Placing price modification sound setting mode
   MODE_SET_SOUND_ERROR_OPEN,                               // Opening/placing error sound setting mode
   MODE_SET_SOUND_ERROR_CLOSE,                              // Closing/removal error sound setting mode
   MODE_SET_SOUND_ERROR_MODIFY_SL,                          // StopLoss modification error sound setting mode
   MODE_SET_SOUND_ERROR_MODIFY_TP,                          // TakeProfit modification error sound setting mode
   MODE_SET_SOUND_ERROR_MODIFY_PRICE,                       // Placing price modification error sound setting mode
  };
//+------------------------------------------------------------------+

A partir da versão do terminal 2155, em MQL5 apareceram novas propriedades de símbolo e de conta:

  1. MQL5: à enumeração ENUM_SYMBOL_INFO_STRING adicionados os seguintes valores:

    • SYMBOL_CATEGORY: categoria do símbolo. Utilizado para marcação adicional de instrumentos financeiros. Por exemplo, pode indicar setores de mercado relacionados com o símbolo: Agricultura, Petróleo e Gás, etc.
    • SYMBOL_EXCHANGE: é o nome da bolsa ou plataforma na qual o símbolo é negociado.

  2. MQL5: adicionado o suporte ao fechamento de posições pelo princípio FIFO.

    • À enumeração ENUM_ACCOUNT_INFO_INTEGER adicionado o valor ACCOUNT_FIFO_CLOSE: indica que a posição pode ser fechada apenas de acordo pelo princípio FIFO. Se o valor da propriedade for true, as posições de cada símbolo poderão ser fechadas somente na ordem em que foram abertas, isto é, primeiro a mais antiga, depois a mais recente etc. Se você tentar fechar as posições em uma ordem diferente, será mostrado um erro. Para contas sem registro com cobertura de posições (ACCOUNT_MARGIN_MODE!=ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) a propriedade sempre é igual a false.
    • Adicionado o novo código de retorno do servidor TRADE_RETCODE_FIFO_CLOSE: solicitação rejeitada, pois para a conta de negociação definida a regra "Permitido fechar posições existentes apenas segundo o princípio FIFO".

    O fechamento de posições podem ser realizado de três maneiras:

    • Fechamento através do terminal do cliente: é o encerramento das posições realizado manualmente pelo trader, com a ajuda de um robô de negociação, por meio do serviço de "Sinais", etc. Se não tentar fechar posições segundo o princípio FIFO, o trader verá o erro correspondente.
    • Fechamento quando acionado Stop Loss ou Take Profit: esses pedidos são processados no lado do servidor, respectivamente, e as posições de fechamento nesse caso são iniciadas não pelo profissional (terminal), mas pelo próprio servidor. Se para uma posição for acionado um Stop Loss ou Take Profit e essa posição não corresponder com o princípio FIFO (existem posições anteriores para o mesmo instrumento), ela não será fechada.
    • Se acionado Stop out, essas operações também serão acionadas no lado do servidor. No modo normal, quando desativado o fechamento segundo princípio FIFO, se acontecer um Stop out, as posições são fechadas, começando pela menos lucrativa. Se ativada esta opção, para as posições não lucrativas encerradas, será adicionalmente verificado seu tempo de abertura. O servidor determina as posições mal-sucedidas de cada símbolo, localiza a posição mais antiga de cada símbolo e fecha a que mais causa perdas nas posições encontradas.

Devido a isso, ao objeto-símbolo e ao objeto-conta foram adicionadas novas propriedades.

Ao bloco de propriedades integrais da conta foi inserida uma nova propriedade, enquanto o número de propriedades integrais foi aumentado para 11:

//+------------------------------------------------------------------+
//| Account integer properties                                       |
//+------------------------------------------------------------------+
enum ENUM_ACCOUNT_PROP_INTEGER
  {
   ACCOUNT_PROP_LOGIN,                                      // Account number
   ACCOUNT_PROP_TRADE_MODE,                                 // Trading account type
   ACCOUNT_PROP_LEVERAGE,                                   // 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 (MetaTrader5, MetaTrader4)
   ACCOUNT_PROP_FIFO_CLOSE                                  // Flag of a position closure by FIFO rule only
  };
#define ACCOUNT_PROP_INTEGER_TOTAL    (11)                  // Total number of integer properties
#define ACCOUNT_PROP_INTEGER_SKIP     (0)                   // Number of integer account properties not used in sorting
//+------------------------------------------------------------------+

À lista de possíveis critérios de classificação de símbolos adicionamos um novo critério de classificação de acordo com propriedades integrais:

Da mesma forma, foram adicionadas as propriedades do objeto-símbolo.

//+------------------------------------------------------------------+
//| 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 integer properties
   SORT_BY_ACCOUNT_LOGIN = 0,                               // Sort by account number
   SORT_BY_ACCOUNT_TRADE_MODE,                              // Sort by trading account type
   SORT_BY_ACCOUNT_LEVERAGE,                                // Sort by leverage
   SORT_BY_ACCOUNT_LIMIT_ORDERS,                            // Sort by maximum acceptable number of existing pending orders
   SORT_BY_ACCOUNT_MARGIN_SO_MODE,                          // Sort by mode for setting the minimum acceptable margin level
   SORT_BY_ACCOUNT_TRADE_ALLOWED,                           // Sort by permission to trade for the current account
   SORT_BY_ACCOUNT_TRADE_EXPERT,                            // Sort by permission to trade for an EA
   SORT_BY_ACCOUNT_MARGIN_MODE,                             // Sort by margin calculation mode
   SORT_BY_ACCOUNT_CURRENCY_DIGITS,                         // Sort by number of digits for an account currency
   SORT_BY_ACCOUNT_SERVER_TYPE,                             // Sort by trade server type (MetaTrader5, MetaTrader4)
   SORT_BY_ACCOUNT_FIFO_CLOSE,                              // Sort by the flag of a position closure by FIFO rule only
//--- Sort by real properties

Ao bloco de propriedades de string foram adicionadas duas novas propriedades, enquanto o número de propriedades de string foi aumentado para 13:

//+------------------------------------------------------------------+
//| Symbol string properties                                         |
//+------------------------------------------------------------------+
enum ENUM_SYMBOL_PROP_STRING
  {
   SYMBOL_PROP_NAME = (SYMBOL_PROP_INTEGER_TOTAL+SYMBOL_PROP_DOUBLE_TOTAL),   // Symbol name
   SYMBOL_PROP_BASIS,                                       // Name of the underlaying asset for a derivative symbol
   SYMBOL_PROP_CURRENCY_BASE,                               // Instrument base currency
   SYMBOL_PROP_CURRENCY_PROFIT,                             // Profit currency
   SYMBOL_PROP_CURRENCY_MARGIN,                             // Margin currency
   SYMBOL_PROP_BANK,                                        // Source of the current quote
   SYMBOL_PROP_DESCRIPTION,                                 // String description of a symbol
   SYMBOL_PROP_FORMULA,                                     // The formula used for custom symbol pricing
   SYMBOL_PROP_ISIN,                                        // The name of a trading symbol in the international system of securities identification numbers (ISIN)
   SYMBOL_PROP_PAGE,                                        // The web page containing symbol information
   SYMBOL_PROP_PATH,                                        // Location in the symbol tree
   SYMBOL_PROP_CATEGORY,                                    // Symbol category
   SYMBOL_PROP_EXCHANGE                                     // Name of an exchange a symbol is traded on
  };
#define SYMBOL_PROP_STRING_TOTAL     (13)                   // Total number of string properties
//+------------------------------------------------------------------+

À lista de possíveis critérios de classificação de símbolos foram adicionados dois novos critérios para classificar de acordo com as propriedades de string dos símbolos:

//--- Sort by string properties
   SORT_BY_SYMBOL_NAME = FIRST_SYM_STR_PROP,                // Sort by a symbol name
   SORT_BY_SYMBOL_BASIS,                                    // Sort by an underlying asset of a derivative
   SORT_BY_SYMBOL_CURRENCY_BASE,                            // Sort by a base currency of a symbol
   SORT_BY_SYMBOL_CURRENCY_PROFIT,                          // Sort by a profit currency
   SORT_BY_SYMBOL_CURRENCY_MARGIN,                          // Sort by a margin currency
   SORT_BY_SYMBOL_BANK,                                     // Sort by a feeder of the current quote
   SORT_BY_SYMBOL_DESCRIPTION,                              // Sort by a symbol string description
   SORT_BY_SYMBOL_FORMULA,                                  // Sort by the formula used for custom symbol pricing
   SORT_BY_SYMBOL_ISIN,                                     // Sort by the name of a symbol in the ISIN system
   SORT_BY_SYMBOL_PAGE,                                     // Sort by an address of the web page containing symbol information
   SORT_BY_SYMBOL_PATH,                                     // Sort by a path in the symbol tree
   SORT_BY_SYMBOL_CATEGORY,                                 // Sort by symbol category
   SORT_BY_SYMBOL_EXCHANGE                                  // Sort by a name of an exchange a symbol is traded on
  };
//+------------------------------------------------------------------+

Também foram adicionadas algumas novas constantes de índices de mensagens de texto da biblioteca, para trabalhar com novas propriedades, classes e métodos de objetos.
Vejamos as novas constantes adicionadas no arquivo Datas.mqh:

//+------------------------------------------------------------------+
//| List of the library's text message indices                       |
//+------------------------------------------------------------------+
enum ENUM_MESSAGES_LIB
  {
   MSG_LIB_PARAMS_LIST_BEG=ERR_USER_ERROR_FIRST,      // Beginning of the parameter list
   MSG_LIB_PARAMS_LIST_END,                           // End of the parameter list
   MSG_LIB_PROP_NOT_SUPPORTED,                        // Property not supported
   MSG_LIB_PROP_NOT_SUPPORTED_MQL4,                   // Property not supported in MQL4
   MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_2155,          // Property not supported in MetaTrader 5 versions lower than 2155
   MSG_LIB_PROP_NOT_SUPPORTED_POSITION,               // Property not supported for position
   MSG_LIB_PROP_NOT_SUPPORTED_PENDING,                // Property not supported for pending order
   MSG_LIB_PROP_NOT_SUPPORTED_MARKET,                 // Property not supported for market order
   MSG_LIB_PROP_NOT_SUPPORTED_MARKET_HIST,            // Property not supported for historical market order
   MSG_LIB_PROP_NOT_SET,                              // Value not set
   MSG_LIB_PROP_EMPTY,                                // Not set
   
   MSG_LIB_SYS_ERROR,                                 // Error
   MSG_LIB_SYS_NOT_SYMBOL_ON_SERVER,                  // Error. No such symbol on server
   MSG_LIB_SYS_NOT_SYMBOL_ON_LIST,                    // Error. No such symbol in the list of used symbols: 
   MSG_LIB_SYS_FAILED_PUT_SYMBOL,                     // Failed to place to market watch. Error: 
   MSG_LIB_SYS_NOT_GET_PRICE,                         // Failed to get current prices. Error: 
   MSG_LIB_SYS_NOT_GET_MARGIN_RATES,                  // Failed to get margin ratios. Error: 
   MSG_LIB_SYS_NOT_GET_DATAS,                         // Failed to get data
   
   MSG_LIB_SYS_FAILED_CREATE_STORAGE_FOLDER,          // Failed to create folder for storing files. Error: 
   MSG_LIB_SYS_FAILED_ADD_ACC_OBJ_TO_LIST,            // Error. Failed to add current account object to collection list
   MSG_LIB_SYS_FAILED_CREATE_CURR_ACC_OBJ,            // Error. Failed to create account object with current account data
   MSG_LIB_SYS_FAILED_OPEN_FILE_FOR_WRITE,            // Could not open file for writing
   MSG_LIB_SYS_INPUT_ERROR_NO_SYMBOL,                 // Input error: no symbol
   MSG_LIB_SYS_FAILED_CREATE_SYM_OBJ,                 // Failed to create symbol object
   MSG_LIB_SYS_FAILED_ADD_SYM_OBJ,                    // Failed to add symbol
   
   MSG_LIB_SYS_NOT_GET_CURR_PRICES,                   // Failed to get current prices by event symbol
   MSG_LIB_SYS_EVENT_ALREADY_IN_LIST,                 // This event is already in the list
   MSG_LIB_SYS_FILE_RES_ALREADY_IN_LIST,              // This file already created and added to list:
   MSG_LIB_SYS_FAILED_CREATE_RES_LINK,                // Error. Failed to create object pointing to resource file
   MSG_LIB_SYS_ERROR_ALREADY_CREATED_COUNTER,         // Error. Counter with ID already created
   MSG_LIB_SYS_FAILED_CREATE_COUNTER,                 // Failed to create timer counter
   MSG_LIB_SYS_FAILED_CREATE_TEMP_LIST,               // Error creating temporary list
   MSG_LIB_SYS_ERROR_NOT_MARKET_LIST,                 // Error. This is not a market collection list
   MSG_LIB_SYS_ERROR_NOT_HISTORY_LIST,                // Error. This is not a history collection list
   MSG_LIB_SYS_FAILED_ADD_ORDER_TO_LIST,              // Could not add order to the list
   MSG_LIB_SYS_FAILED_ADD_DEAL_TO_LIST,               // Could not add deal to the list
   MSG_LIB_SYS_FAILED_ADD_CTRL_ORDER_TO_LIST,         // Failed to add control order
   MSG_LIB_SYS_FAILED_ADD_CTRL_POSITION_TO_LIST,      // Failed to add control position
   MSG_LIB_SYS_FAILED_ADD_MODIFIED_ORD_TO_LIST,       // Could not add modified order to the list of modified orders
   MSG_LIB_SYS_FAILED_CREATE_TIMER,                   // Failed to create timer. Error: 
    
   MSG_LIB_SYS_NO_TICKS_YET,                          // No ticks yet
   MSG_LIB_SYS_FAILED_CREATE_OBJ_STRUCT,              // Could not create object structure
   MSG_LIB_SYS_FAILED_WRITE_UARRAY_TO_FILE,           // Could not write uchar array to file
   MSG_LIB_SYS_FAILED_LOAD_UARRAY_FROM_FILE,          // Could not load uchar array from file
   MSG_LIB_SYS_FAILED_CREATE_OBJ_STRUCT_FROM_UARRAY,  // Could not create object structure from uchar array
   MSG_LIB_SYS_FAILED_SAVE_OBJ_STRUCT_TO_UARRAY,      // Failed to save object structure to uchar array, error
   MSG_LIB_SYS_ERROR_INDEX,                           // Error. "index" value should be within 0 - 3
   MSG_LIB_SYS_ERROR_FAILED_CONV_TO_LOWERCASE,        // Failed to convert string to lowercase, error

//--- COrder
   MSG_ORD_BUY,                                       // Buy
   MSG_ORD_SELL,                                      // Sell
   MSG_ORD_TO_BUY,                                    // Buy order
   MSG_ORD_TO_SELL,                                   // Sell order
   MSG_DEAL_TO_BUY,                                   // Buy deal
   MSG_DEAL_TO_SELL,                                  // Sell deal
   MSG_ORD_MARKET,                                    // Market order
   MSG_ORD_HISTORY,                                   // Historical order
   MSG_ORD_DEAL,                                      // Deal
   MSG_ORD_POSITION,                                  // Position
   MSG_ORD_PENDING_ACTIVE,                            // Active pending order
   MSG_ORD_PENDING,                                   // Pending order
   MSG_ORD_UNKNOWN_TYPE,                              // Unknown order type
   MSG_POS_UNKNOWN_TYPE,                              // Unknown position type
   MSG_POS_UNKNOWN_DEAL,                              // Unknown deal type
   //---

   //---
   MSG_SYM_PROP_NAME,                                 // Symbol name
   MSG_SYM_PROP_BASIS,                                // Underlying asset of derivative
   MSG_SYM_PROP_CURRENCY_BASE,                        // Basic currency of symbol
   MSG_SYM_PROP_CURRENCY_PROFIT,                      // Profit currency
   MSG_SYM_PROP_CURRENCY_MARGIN,                      // Margin currency
   MSG_SYM_PROP_BANK,                                 // Feeder of the current quote
   MSG_SYM_PROP_DESCRIPTION,                          // Symbol description
   MSG_SYM_PROP_FORMULA,                              // Formula used for custom symbol pricing
   MSG_SYM_PROP_ISIN,                                 // Symbol name in ISIN system
   MSG_SYM_PROP_PAGE,                                 // Address of web page containing symbol information
   MSG_SYM_PROP_PATH,                                 // Location in symbol tree
   MSG_SYM_PROP_CAYEGORY,                             // Symbol category
   MSG_SYM_PROP_EXCHANGE,                             // Name of an exchange a symbol is traded on
   //---

   //---
   MSG_SYM_TRADE_MODE_DISABLED,                       // Trade disabled for symbol
   MSG_SYM_TRADE_MODE_LONGONLY,                       // Only long positions allowed
   MSG_SYM_TRADE_MODE_SHORTONLY,                      // Only short positions allowed
   MSG_SYM_TRADE_MODE_CLOSEONLY,                      // Enable close only
   MSG_SYM_TRADE_MODE_FULL,                           // No trading limitations
   
   MSG_SYM_MARKET_ORDER_DISABLED,                     // Market orders disabled
   MSG_SYM_LIMIT_ORDER_DISABLED,                      // Limit orders disabled
   MSG_SYM_STOP_ORDER_DISABLED,                       // Stop orders disabled
   MSG_SYM_STOP_LIMIT_ORDER_DISABLED,                 // StopLimit orders disabled
   MSG_SYM_SL_ORDER_DISABLED,                         // StopLoss orders disabled
   MSG_SYM_TP_ORDER_DISABLED,                         // TakeProfit orders disabled
   MSG_SYM_CLOSE_BY_ORDER_DISABLED,                   // CloseBy orders disabled
   //---

//--- CAccount
   MSG_ACC_PROP_LOGIN,                                // Account number
   MSG_ACC_PROP_TRADE_MODE,                           // Trading account type
   MSG_ACC_PROP_LEVERAGE,                             // Leverage
   MSG_ACC_PROP_LIMIT_ORDERS,                         // Maximum allowed number of active pending orders
   MSG_ACC_PROP_MARGIN_SO_MODE,                       // Mode of setting the minimum available margin level
   MSG_ACC_PROP_TRADE_ALLOWED,                        // Trading permission of the current account
   MSG_ACC_PROP_TRADE_EXPERT,                         // Trading permission of an EA
   MSG_ACC_PROP_MARGIN_MODE,                          // Margin calculation mode
   MSG_ACC_PROP_CURRENCY_DIGITS,                      // Number of decimal places for the account currency
   MSG_ACC_PROP_SERVER_TYPE,                          // Trade server type
   MSG_ACC_PROP_FIFO_CLOSE,                           // Flag of a position closure by FIFO rule only
   //---

//--- CTrading
   MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED,           // Trade operations are not allowed in the terminal (the AutoTrading button is disabled)
   MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED,                 // EA is not allowed to trade (F7 --> Common --> Allow Automated Trading)
   MSG_LIB_TEXT_ACCOUNT_NOT_TRADE_ENABLED,            // Trading is disabled for the current account
   MSG_LIB_TEXT_ACCOUNT_EA_NOT_TRADE_ENABLED,         // Trading on the trading server side is disabled for EAs on the current account
   MSG_LIB_TEXT_TERMINAL_NOT_CONNECTED,               // No connection to the trade server
   MSG_LIB_TEXT_REQUEST_REJECTED_DUE,                 // Request was rejected before sending to the server due to:
   MSG_LIB_TEXT_NOT_ENOUTH_MONEY_FOR,                 // Insufficient funds for opening a position:
   MSG_LIB_TEXT_MAX_VOLUME_LIMIT_EXCEEDED,            // Exceeded maximum allowed aggregate volume of orders and positions in one direction
   MSG_LIB_TEXT_REQ_VOL_LESS_MIN_VOLUME,              // Request volume is less than the minimum acceptable one
   MSG_LIB_TEXT_REQ_VOL_MORE_MAX_VOLUME,              // Request volume exceeds the maximum acceptable one
   MSG_LIB_TEXT_CLOSE_BY_ORDERS_DISABLED,             // Close by is disabled
   MSG_LIB_TEXT_INVALID_VOLUME_STEP,                  // Request volume is not a multiple of the minimum lot change step gradation
   MSG_LIB_TEXT_CLOSE_BY_SYMBOLS_UNEQUAL,             // Symbols of opposite positions are not equal
   
  };

E ao array de mensagens de texto adicionamos os textos correspondentes às constantes declaradas:

Como já sabemos, todas as ações realizadas servem para adicionar novas mensagens à biblioteca e para acessar rápido mensagens pelo índice especificado na constante da mensagem.

//+------------------------------------------------------------------+
//| Array of predefined library messages                             |
//| (1) in user's country language                                   |
//| (2) in the international language (English)                      |
//| (3) any additional language.                                     |
//|  The default languages are English and Russian.                  |
//|  To add the necessary number of other languages, simply          |
//|  set the total number of used languages in TOTAL_LANG            |
//|  and add the necessary translation after the English text        |
//+------------------------------------------------------------------+
string messages_library[][TOTAL_LANG]=
  {
   {"Начало списка параметров","Beginning of event parameter list"},
   {"Конец списка параметров","End of parameter list"},
   {"Свойство не поддерживается","Property not supported"},
   {"Свойство не поддерживается в MQL4","Property not supported in MQL4"},
   {"Свойство не поддерживается в MetaTrader5 версии ниже 2155","Property not supported in MetaTrader 5, build lower than 2155"},
   {"Свойство не поддерживается у позиции","Property not supported for position"},
   {"Свойство не поддерживается у отложенного ордера","Property not supported for pending order"},
   {"Свойство не поддерживается у маркет-ордера","Property not supported for market order"},
   {"Свойство не поддерживается у исторического маркет-ордера","Property not supported for historical market order"},
   {"Значение не задано","Value not set"},
   {"Отсутствует","Not set"},
   
   {"Ошибка ","Error "},
   {"Ошибка. Такого символа нет на сервере","Error. No such symbol on server"},
   {"Ошибка. Такого символа нет в списке используемых символов: ","Error. This symbol is not in the list of symbols used: "},
   {"Не удалось поместить в обзор рынка. Ошибка: ","Failed to put in market watch. Error: "},
   {"Не удалось получить текущие цены. Ошибка: ","Could not get current prices. Error: "},
   {"Не удалось получить коэффициенты взимания маржи. Ошибка: ","Failed to get margin rates. Error: "},
   {"Не удалось получить данные ","Failed to get data of "},
   
   {"Не удалось создать папку хранения файлов. Ошибка: ","Could not create file storage folder. Error: "},
   {"Ошибка. Не удалось добавить текущий объект-аккаунт в список-коллекцию","Error. Failed to add current account object to collection list"},
   {"Ошибка. Не удалось создать объект-аккаунт с данными текущего счёта","Error. Failed to create account object with current account data"},
   {"Не удалось открыть для записи файл ","Could not open file for writing: "},
   {"Ошибка входных данных: нет символа ","Input error: no "},
   {"Не удалось создать объект-символ ","Failed to create symbol object "},
   {"Не удалось добавить символ ","Failed to add "},
   
   {"Не удалось получить текущие цены по символу события ","Failed to get current prices by event symbol "},
   {"Такое событие уже есть в списке","This event already in the list"},
   {"Такой файл уже создан и добавлен в список: ","This file has already been created and added to list: "},
   {"Ошибка. Не удалось создать объект-указатель на файл ресурса","Error. Failed to create resource file link object"},
   
   {"Ошибка. Уже создан счётчик с идентификатором ","Error. Already created counter with id "},
   {"Не удалось создать счётчик таймера ","Failed to create timer counter "},
   
   {"Ошибка создания временного списка","Error creating temporary list"},
   {"Ошибка. Список не является списком рыночной коллекции","Error. The list is not a list of market collection"},
   {"Ошибка. Список не является списком исторической коллекции","Error. The list is not a list of history collection"},
   {"Не удалось добавить ордер в список","Could not add order to list"},
   {"Не удалось добавить сделку в список","Could not add deal to list"},
   {"Не удалось добавить контрольный ордер ","Failed to add control order "},
   {"Не удалось добавить контрольую позицию ","Failed to add control position "},
   {"Не удалось добавить модифицированный ордер в список изменённых ордеров","Could not add modified order to list of modified orders"},
   {"Не удалось создать таймер. Ошибка: ","Could not create timer. Error: "},
   

//--- COrder
   {"Buy","Buy"},
   {"Sell","Sell"},
   {"Ордер на покупку","Buy order"},
   {"Ордер на продажу","Sell order"},
   
   {"Сделка на покупку","Buy deal"},
   {"Сделка на продажу","Sell deal"},
   
   {"Маркет-ордер","Market order"},
   {"Исторический ордер","History order"},
   {"Сделка","Deal"},
   {"Позиция","Active position"},
   {"Установленный отложенный ордер","Active pending order"},
   {"Отложенный ордер","Pending order"},
   {"Неизвестный тип ордера","Unknown order type"},
   {"Неизвестный тип позиции","Unknown position type"},
   {"Неизвестный тип сделки","Unknown deal type"},
   //---

   {"Путь в дереве символов","Path in symbol tree"},
   {"Название категории или сектора, к которой принадлежит торговый символ","Name of sector or category trading symbol belongs to"},
   {"Название биржи или площадки, на которой торгуется символ","Name of exchange financial symbol traded in"},
   //---
   {"Форекс символ","Forex symbol"},

   {"Разрешены только операции закрытия позиций","Close only"},
   {"Нет ограничений на торговые операции","No trade restrictions"},
   {"Торговля рыночными ордерами запрещена","Trading through market orders prohibited"},
   {"Установка Limit-ордеров запрещена","Limit orders prohibited"},
   {"Установка Stop-ордеров запрещена","Stop orders prohibited"},
   {"Установка StopLimit-ордеров запрещена","StopLimit orders prohibited"},
   {"Установка StopLoss-ордеров запрещена","StopLoss orders prohibited"},
   {"Установка TakeProfit-ордеров запрещена","TakeProfit orders prohibited"},
   {"Установка CloseBy-ордеров запрещена","CloseBy orders prohibited"},
   //---
   {"Торговля по запросу","Execution by request"},
   {"Торговля по потоковым ценам","Instant execution"},
   {"Исполнение ордеров по рынку","Market execution"},
   {"Биржевое исполнение","Exchange execution"},
   //---

//--- CAccount
   {"Номер счёта","Account number"},
   {"Тип торгового счета","Account trade mode"},
   {"Размер предоставленного плеча","Account leverage"},
   {"Максимально допустимое количество действующих отложенных ордеров","Maximum allowed number of active pending orders"},
   {"Режим задания минимально допустимого уровня залоговых средств","Mode for setting minimal allowed margin"},
   {"Разрешенность торговли для текущего счета","Allowed trade for the current account"},
   {"Разрешенность торговли для эксперта","Allowed trade for Expert Advisor"},
   {"Режим расчета маржи","Margin calculation mode"},
   {"Количество знаков после запятой для валюты счета","Number of decimal places in account currency"},
   {"Тип торгового сервера","Type of trading server"},
   {"Признак закрытия позиций только по правилу FIFO","Sign of closing positions only according to FIFO rule"},
   //---
   {"Баланс счета","Account balance"},

//--- CEngine
   {"С момента последнего запуска ЕА торговых событий не было","No trade events since the last launch of EA"},
   {"Не удалось получить описание последнего торгового события","Failed to get description of the last trading event"},
   {"Не удалось получить список открытых позиций","Failed to get open positions list"},
   {"Не удалось получить список установленных ордеров","Failed to get pending orders list"},
   {"Нет открытых позиций","No open positions"},
   {"Нет установленных ордеров","No placed orders"},
   {"В терминале нет разрешения на проведение торговых операций (отключена кнопка \"Авто-торговля\")","No permission to conduct trading operations in terminal (\"AutoTrading\" button disabled)"},
   {"Для советника нет разрешения на проведение торговых операций (F7 --> Общие --> \"Разрешить автоматическую торговлю\")","EA does not have permission to conduct trading operations (F7 --> Common --> \"Allow Automatic Trading\")"},
   {"Для текущего счёта запрещена торговля","Trading prohibited for the current account"},
   {"Для советников на текущем счёте запрещена торговля на стороне торгового сервера","From the side of trade server, trading for EA on the current account prohibited"},
   {"Нет связи с торговым сервером","No connection to trade server"},
   {"Запрос отклонён до отправки на сервер по причине:","Request rejected before being sent to server due to:"},
   {"Не хватает средств на открытие позиции: ","Not enough money to open position: "},
   {"Превышен максимальный совокупный объём ордеров и позиций в одном направлении","Exceeded maximum total volume of orders and positions in one direction"},
   {"Объём в запросе меньше минимально-допустимого","Volume in request less than minimum allowable"},
   {"Объём в запросе больше максимально-допустимого","Volume in request greater than maximum allowable"},
   {"Закрытие встречным запрещено","CloseBy orders prohibited"},
   {"Объём в запросе не кратен минимальной градации шага изменения лота","Volume in request not a multiple of minimum gradation of step for changing lot"},
   {"Символы встречных позиций не равны","Symbols of two opposite positions not equal"},
   
  };

//+---------------------------------------------------------------------+
//| Array of messages for trade server return codes (10004 - 10045)     |
//| (1) in user's country language                                      |
//| (2) in the international language                                   |
//+---------------------------------------------------------------------+
string messages_ts_ret_code[][TOTAL_LANG]=
  {
   {"Реквота","Requote"},                                                                                                                          // 10004
   {"Неизвестный код возврата торгового сервера","Unknown trading server return code"},                                                   // 10005
   {"Запрос отклонен","Request rejected"},                                                                                                         // 10006
   {"Запрос отменен трейдером","Request canceled by trader"},                                                                                      // 10007
   {"Ордер размещен","Order placed"},                                                                                                              // 10008
   {"Заявка выполнена","Request completed"},                                                                                                       // 10009
   {"Заявка выполнена частично","Only part of request completed"},                                                                         // 10010
   {"Ошибка обработки запроса","Request processing error"},                                                                                        // 10011
   {"Запрос отменен по истечению времени","Request canceled by timeout"},                                                                          // 10012
   {"Неправильный запрос","Invalid request"},                                                                                                      // 10013
   {"Неправильный объем в запросе","Invalid volume in request"},                                                                                   // 10014
   {"Неправильная цена в запросе","Invalid price in request"},                                                                                     // 10015
   {"Неправильные стопы в запросе","Invalid stops in request"},                                                                                    // 10016
   {"Торговля запрещена","Trading disabled"},                                                                                                      // 10017
   {"Рынок закрыт","Market closed"},                                                                                                               // 10018
   {"Нет достаточных денежных средств для выполнения запроса","Not enough money to complete request"},                                     // 10019
   {"Цены изменились","Prices changed"},                                                                                                           // 10020
   {"Отсутствуют котировки для обработки запроса","No quotes to process request"},                                                         // 10021
   {"Неверная дата истечения ордера в запросе","Invalid order expiration date in request"},                                                        // 10022
   {"Состояние ордера изменилось","Order state changed"},                                                                                          // 10023
   {"Слишком частые запросы","Too frequent requests"},                                                                                             // 10024
   {"В запросе нет изменений","No changes in request"},                                                                                            // 10025
   {"Автотрейдинг запрещен сервером","Autotrading disabled by server"},                                                                            // 10026
   {"Автотрейдинг запрещен клиентским терминалом","Autotrading disabled by client terminal"},                                                      // 10027
   {"Запрос заблокирован для обработки","Request locked for processing"},                                                                          // 10028
   {"Ордер или позиция заморожены","Order or position frozen"},                                                                                    // 10029
   {"Указан неподдерживаемый тип исполнения ордера по остатку","Invalid order filling type"},                                                      // 10030
   {"Нет соединения с торговым сервером","No connection with trade server"},                                                                       // 10031
   {"Операция разрешена только для реальных счетов","Operation allowed only for live accounts"},                                                   // 10032
   {"Достигнут лимит на количество отложенных ордеров","Number of pending orders reached limit"},                                           // 10033
   {"Достигнут лимит на объем ордеров и позиций для данного символа","Volume of orders and positions for symbol reached limit"},            // 10034
   {"Неверный или запрещённый тип ордера","Incorrect or prohibited order type"},                                                                   // 10035
   {"Позиция с указанным идентификатором уже закрыта","Position with specified identifier already closed"},                                 // 10036
   {"Неизвестный код возврата торгового сервера","Unknown trading server return code"},                                                     // 10037
   {"Закрываемый объем превышает текущий объем позиции","Close volume exceeds the current position volume"},                                       // 10038
   {"Для указанной позиции уже есть ордер на закрытие","Close order already exists for specified position"},                                       // 10039
   {"Достигнут лимит на количество открытых позиций","Number of positions reached limit"},                                                  // 10040
   {
    "Запрос на активацию отложенного ордера отклонен, а сам ордер отменен",                                                                        // 10041
    "Pending order activation request rejected, order canceled"
   },
   {
    "Запрос отклонен, так как на символе установлено правило \"Разрешены только длинные позиции\"",                                                // 10042
    "Request rejected, because \"Only long positions are allowed\" rule set for symbol"
   },
   {
    "Запрос отклонен, так как на символе установлено правило \"Разрешены только короткие позиции\"",                                               // 10043
    "Request rejected, because \"Only short positions are allowed\" rule set for symbol"
   },
   {
    "Запрос отклонен, так как на символе установлено правило \"Разрешено только закрывать существующие позиции\"",                                 // 10044
    "Request rejected because \"Only position closing is allowed\" rule set for symbol"
   },
   {
    "Запрос отклонен, так как для торгового счета установлено правило \"Разрешено закрывать существующие позиции только по правилу FIFO\"",        // 10045
    "Request rejected, because \"Position closing is allowed only by FIFO rule\" flag set for trading account"
   },
  };
//+------------------------------------------------------------------+

Agora vamos modificar a classe de mensagens localizada no arquivo \MQL5\Include\DoEasy\Services\Message.mqh.

Na seção pública da classe declaramos um método para parar de reproduzir qualquer arquivo de som:

public:
//--- (1) Display a text message in the journal, send a push notification and e-mail,
//--- (2) Display a message by ID, send a push notification and e-mail,
//--- (3) play an audio file
//--- (4) Stop playing any sound
   static bool       Out(const string text,const bool push=false,const bool mail=false,const string subject=NULL);
   static bool       OutByID(const int msg_id,const bool code=true);
   static bool       PlaySound(const string file_name);
   static bool       StopPlaySound(void);

E fora do corpo da classe, escrevemos sua implementação:

//+------------------------------------------------------------------+
//| Stop playing any sound                                           |
//+------------------------------------------------------------------+
bool CMessage::StopPlaySound(void)
  {
   bool res=::PlaySound(NULL);
   CMessage::m_global_error=(res ? ERR_SUCCESS : ::GetLastError());
   return res;
  }
//+------------------------------------------------------------------+

Aqui tudo é simples, isto é, ao transferir como nome de arquivo a constante NULL, a função padrão PlaySound() finaliza a reprodução do arquivo de som que está sendo reproduzido.

Para podermos reproduzir os arquivos de som padrão anexados aos que vem com o terminal, precisamos especificar o nome do arquivo no nome do arquivo (para reproduzir sons a partir do local padrão do arquivo: pasta_do_terminal\Sounds) ou especificar o nome do arquivo com o prefixo contendo uma barra dupla e a subpasta na qual estão localizados os arquivos de som não padrão.
Por isso, modificaremos o método PlaySound():

//+------------------------------------------------------------------+
//| Play an audio file                                               |
//+------------------------------------------------------------------+
bool CMessage::PlaySound(const string file_name)
  {
   if(file_name==NULL)
      return true;
   string pref=(file_name==SND_ALERT       || file_name==SND_ALERT2   || file_name==SND_CONNECT  || 
                file_name==SND_DISCONNECT  || file_name==SND_EMAIL    || file_name==SND_EXPERT   ||
                file_name==SND_NEWS        || file_name==SND_OK       || file_name==SND_REQUEST  || 
                file_name==SND_STOPS       || file_name==SND_TICK     || file_name==SND_TIMEOUT  ||
                file_name==SND_WAIT        ?  "" : "\\Files\\");
   bool res=::PlaySound(pref+file_name);
   CMessage::m_global_error=(res ? ERR_SUCCESS : ::GetLastError());
   return res;
  }

O que temos aqui:

Se como nome do arquivo foi transferido o nome do arquivo de som padrão, no prefixo do nome do arquivo escrevemos uma linha vazia.
Caso contrário,
no prefixo escrevemos uma barra dupla e o nome da subpasta onde localizados os sons da biblioteca.
Depois, o nome do arquivo é composto pelo prefixo e pelo nome transferido ao método.
Agora ao transferir o nome à função PlaySound(), será automaticamente selecionado o local do arquivo de som (diretório padrão de sons ou pasta de arquivos de som da biblioteca) e o arquivo correspondente será reproduzido.

Como agora adicionamos um novo código de retorno de servidor de negociação, no método que permite obter mensagens do array de textos por identificador
void CMessage::GetTextByID() aumentamos os limites dos códigos de retorno do servidor de negociação em 1 (era 10044, ficou 10045):

      //--- Runtime errors (Economic calendar 5400 - 5402)
      msg_id>5399 && msg_id<5403    ?  messages_runtime_calendar[msg_id-5400][m_lang_num]         :
      //--- Trade server return codes (10004 - 10045)
      msg_id>10003 && msg_id<10046  ?  messages_ts_ret_code[msg_id-10004][m_lang_num]             :
     #else // MQL4
      msg_id>0 && msg_id<10         ?  messages_ts_ret_code_mql4[msg_id][m_lang_num]              :
      msg_id>63 && msg_id<66        ?  messages_ts_ret_code_mql4[msg_id-54][m_lang_num]           :
      msg_id>127 && msg_id<151      ?  messages_ts_ret_code_mql4[msg_id-116][m_lang_num]          :
      msg_id<4000                   ?  messages_ts_ret_code_mql4[26][m_lang_num]                  :
      //--- MQL4 runtime errors (4000 - 4030)
      msg_id<4031                   ?  messages_runtime_4000_4030[msg_id-4000][m_lang_num]        :
      //--- MQL4 runtime errors (4050 - 4075)
      msg_id>4049 && msg_id<4076    ?  messages_runtime_4050_4075[msg_id-4050][m_lang_num]        :
      //--- MQL4 runtime errors (4099 - 4112)
      msg_id>4098 && msg_id<4113    ?  messages_runtime_4099_4112[msg_id-4099][m_lang_num]        :
      //--- MQL4 runtime errors (4200 - 4220)
      msg_id>4199 && msg_id<4221    ?  messages_runtime_4200_4220[msg_id-4200][m_lang_num]        :
      //--- MQL4 runtime errors (4250 - 4266)
      msg_id>4249 && msg_id<4267    ?  messages_runtime_4250_4266[msg_id-4250][m_lang_num]        :
      //--- MQL4 runtime errors (5001 - 5029)
      msg_id>5000 && msg_id<5030    ?  messages_runtime_5001_5029[msg_id-5001][m_lang_num]        :
      //--- MQL4 runtime errors (5200 - 5203)
      msg_id>5199 && msg_id<5204    ?  messages_runtime_5200_5203[msg_id-5200][m_lang_num]        :
     #endif 
      //--- Library messages (ERR_USER_ERROR_FIRST)
      msg_id>ERR_USER_ERROR_FIRST-1 ?  messages_library[msg_id-ERR_USER_ERROR_FIRST][m_lang_num]  : 
      messages_library[MSG_LIB_SYS_ERROR_CODE_OUT_OF_RANGE-ERR_USER_ERROR_FIRST][m_lang_num]
     );

Essas são todas as alterações na classe de mensagens da biblioteca.

Às vezes, precisamos saber, segundo o tipo de ordem, em que direção será aberta a posição quando ativada essa ordem. Por exemplo, se colocarmos uma ordem pendente do tipo ORDER_TYPE_BUY_LIMIT. Ao ser ativada, será colocada uma ordem a mercado ORDER_TYPE_BUY, que gerará uma transação DEAL_ENTRY_IN de tipo DEAL_TYPE_BUY, e esta, por sua vez, dará lugar a uma posição de tipo POSITION_TYPE_BUY.

Portanto, para saber, segundo o tipo de ordem pendente, em que direção será aberta a posição, precisaremos ter o tipo de ordem a mercado (neste exemplo) ORDER_TYPE_BUY.
Anteriormente, nós a determinávamos com a ajuda do operador ternário, comparando-o com o tipo de ordem pendente. Mas é possível fazer isso com mais facilidade, basta dividir o tipo de pedido a ser verificado por 2. Para pedidos pares, sempre será retornado o tipo 0 (ORDER_TYPE_BUY), já para pedidos ímpares, o tipo 1 (ORDER_TYPE_SELL). Foi isso o que fizemos em algumas funções e métodos.
Na classe abstrata da ordem (\MQL5\Include\DoEasy\Objects\Orders\Order.mqh):

//+------------------------------------------------------------------+
//| Return the type by direction                                     |
//+------------------------------------------------------------------+
long COrder::OrderTypeByDirection(void) const
  {
   ENUM_ORDER_STATUS status=(ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS);
   if(status==ORDER_STATUS_MARKET_POSITION)
     {
      return (ENUM_ORDER_TYPE)this.OrderType();
     }
   else if(status==ORDER_STATUS_MARKET_PENDING || status==ORDER_STATUS_HISTORY_PENDING)
     {
      return ENUM_ORDER_TYPE(this.OrderType()%2);
     }
   else if(status==ORDER_STATUS_MARKET_ORDER || status==ORDER_STATUS_HISTORY_ORDER)
     {
      return this.OrderType();
     }
   else if(status==ORDER_STATUS_DEAL)
     {
      return
        (
         (ENUM_DEAL_TYPE)this.TypeOrder()==DEAL_TYPE_BUY ? ORDER_TYPE_BUY   :
         (ENUM_DEAL_TYPE)this.TypeOrder()==DEAL_TYPE_SELL ? ORDER_TYPE_SELL : WRONG_VALUE
        );
     }
   return WRONG_VALUE;
  }
//+------------------------------------------------------------------+

e na biblioteca de funções de serviço (\MQL5\Include\DoEasy\Services\DELib.mqh):

//+------------------------------------------------------------------+
//| Return position type by order type                               |
//+------------------------------------------------------------------+
ENUM_POSITION_TYPE PositionTypeByOrderType(ENUM_ORDER_TYPE type_order)
  {
   if(type_order==ORDER_TYPE_CLOSE_BY)
      return WRONG_VALUE;
   return ENUM_POSITION_TYPE(type_order%2);
  }
//+------------------------------------------------------------------+

No mesmo arquivo de funções de serviço, a função que retorna o nome do pedido passou por algumas alterações.
Foi adicionado o sinalizador para exibir uma descrição da ordem, além disso, ao tipo de ordem a mercado retornado - dependendo deste sinalizador - é adicionada uma descrição indicando se trata de uma ordem a mercado ou não. Adicionalmente, ao tipo de ordem pendente a ser retornado foram adicionadas descrições do tipo de ordem:

//+------------------------------------------------------------------+
//| Return the order name                                            |
//+------------------------------------------------------------------+
string OrderTypeDescription(const ENUM_ORDER_TYPE type,bool as_order=true,bool need_prefix=true)
  {
   string pref=
     (
      !need_prefix ? "" :
      #ifdef __MQL5__ CMessage::Text(MSG_ORD_MARKET) 
      #else/*__MQL4__*/(as_order ? CMessage::Text(MSG_ORD_MARKET) : CMessage::Text(MSG_ORD_POSITION)) #endif 
     );
   return
     (
      type==ORDER_TYPE_BUY_LIMIT       ?  CMessage::Text(MSG_ORD_PENDING)+" Buy Limit"       :
      type==ORDER_TYPE_BUY_STOP        ?  CMessage::Text(MSG_ORD_PENDING)+" Buy Stop"        :
      type==ORDER_TYPE_SELL_LIMIT      ?  CMessage::Text(MSG_ORD_PENDING)+" Sell Limit"      :
      type==ORDER_TYPE_SELL_STOP       ?  CMessage::Text(MSG_ORD_PENDING)+" Sell Stop"       :
   #ifdef __MQL5__
      type==ORDER_TYPE_BUY_STOP_LIMIT  ?  CMessage::Text(MSG_ORD_PENDING)+" Buy Stop Limit"  :
      type==ORDER_TYPE_SELL_STOP_LIMIT ?  CMessage::Text(MSG_ORD_PENDING)+" Sell Stop Limit" :
      type==ORDER_TYPE_CLOSE_BY        ?  CMessage::Text(MSG_ORD_CLOSE_BY)                   :  
   #else 
      type==ORDER_TYPE_BALANCE         ?  CMessage::Text(MSG_LIB_PROP_BALANCE)               :
      type==ORDER_TYPE_CREDIT          ?  CMessage::Text(MSG_LIB_PROP_CREDIT)                :
   #endif 
      type==ORDER_TYPE_BUY             ?  pref+" Buy"                                        :
      type==ORDER_TYPE_SELL            ?  pref+" Sell"                                       :  
      CMessage::Text(MSG_ORD_UNKNOWN_TYPE)
     );
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+

Devido às novas propriedades para objetos de símbolo e de conta, precisamos adicionar essas propriedades aos objetos.

Abrimos o arquivo \MQL5\Include\DoEasy\Objects\Symbols\Symbol.mqh e inserimos nele as alterações necessárias.
Na seção protegida da classe, inserimos a definição de métodos para obter duas novas propriedades:

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

//--- Get and return integer properties of a selected symbol from its parameters
   bool              SymbolExists(const string name)     const;
   long              SymbolExists(void)                  const;
   long              SymbolCustom(void)                  const;
   long              SymbolChartMode(void)               const;
   long              SymbolMarginHedgedUseLEG(void)      const;
   long              SymbolOrderFillingMode(void)        const;
   long              SymbolOrderMode(void)               const;
   long              SymbolExpirationMode(void)          const;
   long              SymbolOrderGTCMode(void)            const;
   long              SymbolOptionMode(void)              const;
   long              SymbolOptionRight(void)             const;
   long              SymbolBackgroundColor(void)         const;
   long              SymbolCalcMode(void)                const;
   long              SymbolSwapMode(void)                const;
   long              SymbolDigitsLot(void);
   int               SymbolDigitsBySwap(void);
//--- Get and return real properties of a selected symbol from its parameters
   double            SymbolBidHigh(void)                 const;
   double            SymbolBidLow(void)                  const;
   double            SymbolVolumeReal(void)              const;
   double            SymbolVolumeHighReal(void)          const;
   double            SymbolVolumeLowReal(void)           const;
   double            SymbolOptionStrike(void)            const;
   double            SymbolTradeAccruedInterest(void)    const;
   double            SymbolTradeFaceValue(void)          const;
   double            SymbolTradeLiquidityRate(void)      const;
   double            SymbolMarginHedged(void)            const;
   bool              SymbolMarginLong(void);
   bool              SymbolMarginShort(void);
   bool              SymbolMarginBuyStop(void);
   bool              SymbolMarginBuyLimit(void);
   bool              SymbolMarginBuyStopLimit(void);
   bool              SymbolMarginSellStop(void);
   bool              SymbolMarginSellLimit(void);
   bool              SymbolMarginSellStopLimit(void);
//--- Get and return string properties of a selected symbol from its parameters
   string            SymbolBasis(void)                   const;
   string            SymbolBank(void)                    const;
   string            SymbolISIN(void)                    const;
   string            SymbolFormula(void)                 const;
   string            SymbolPage(void)                    const;
   string            SymbolCategory(void)                const;
   string            SymbolExchange(void)                const;
//--- Search for a symbol and return the flag indicating its presence on the server
   bool              Exist(void)                         const;

public:

Na seção pública da classe, no bloco para obter simplificadas as propriedades do objeto, inserimos a definição de dois novos métodos:

public:
//+------------------------------------------------------------------+
//| Methods of a simplified access to the order object properties    |
//+------------------------------------------------------------------+
//--- Integer properties
   long              Status(void)                                 const { return this.GetProperty(SYMBOL_PROP_STATUS);                                      }
   int               IndexInMarketWatch(void)                     const { return (int)this.GetProperty(SYMBOL_PROP_INDEX_MW);                               }
   bool              IsCustom(void)                               const { return (bool)this.GetProperty(SYMBOL_PROP_CUSTOM);                                }
   color             ColorBackground(void)                        const { return (color)this.GetProperty(SYMBOL_PROP_BACKGROUND_COLOR);                     }
   ENUM_SYMBOL_CHART_MODE ChartMode(void)                         const { return (ENUM_SYMBOL_CHART_MODE)this.GetProperty(SYMBOL_PROP_CHART_MODE);          }
   bool              IsExist(void)                                const { return (bool)this.GetProperty(SYMBOL_PROP_EXIST);                                 }
   bool              IsExist(const string name)                   const { return this.SymbolExists(name);                                                   }
   bool              IsSelect(void)                               const { return (bool)this.GetProperty(SYMBOL_PROP_SELECT);                                }
   bool              IsVisible(void)                              const { return (bool)this.GetProperty(SYMBOL_PROP_VISIBLE);                               }
   long              SessionDeals(void)                           const { return this.GetProperty(SYMBOL_PROP_SESSION_DEALS);                               }
   long              SessionBuyOrders(void)                       const { return this.GetProperty(SYMBOL_PROP_SESSION_BUY_ORDERS);                          }
   long              SessionSellOrders(void)                      const { return this.GetProperty(SYMBOL_PROP_SESSION_SELL_ORDERS);                         }
   long              Volume(void)                                 const { return this.GetProperty(SYMBOL_PROP_VOLUME);                                      }
   long              VolumeHigh(void)                             const { return this.GetProperty(SYMBOL_PROP_VOLUMEHIGH);                                  }
   long              VolumeLow(void)                              const { return this.GetProperty(SYMBOL_PROP_VOLUMELOW);                                   }
   datetime          Time(void)                                   const { return (datetime)this.GetProperty(SYMBOL_PROP_TIME);                              }
   int               Digits(void)                                 const { return (int)this.GetProperty(SYMBOL_PROP_DIGITS);                                 }
   int               DigitsLot(void)                              const { return (int)this.GetProperty(SYMBOL_PROP_DIGITS_LOTS);                            }
   int               Spread(void)                                 const { return (int)this.GetProperty(SYMBOL_PROP_SPREAD);                                 }
   bool              IsSpreadFloat(void)                          const { return (bool)this.GetProperty(SYMBOL_PROP_SPREAD_FLOAT);                          }
   int               TicksBookdepth(void)                         const { return (int)this.GetProperty(SYMBOL_PROP_TICKS_BOOKDEPTH);                        }
   ENUM_SYMBOL_CALC_MODE TradeCalcMode(void)                      const { return (ENUM_SYMBOL_CALC_MODE)this.GetProperty(SYMBOL_PROP_TRADE_CALC_MODE);      }
   ENUM_SYMBOL_TRADE_MODE TradeMode(void)                         const { return (ENUM_SYMBOL_TRADE_MODE)this.GetProperty(SYMBOL_PROP_TRADE_MODE);          }
   datetime          StartTime(void)                              const { return (datetime)this.GetProperty(SYMBOL_PROP_START_TIME);                        }
   datetime          ExpirationTime(void)                         const { return (datetime)this.GetProperty(SYMBOL_PROP_EXPIRATION_TIME);                   }
   int               TradeStopLevel(void)                         const { return (int)this.GetProperty(SYMBOL_PROP_TRADE_STOPS_LEVEL);                      }
   int               TradeFreezeLevel(void)                       const { return (int)this.GetProperty(SYMBOL_PROP_TRADE_FREEZE_LEVEL);                     }
   ENUM_SYMBOL_TRADE_EXECUTION TradeExecutionMode(void)           const { return (ENUM_SYMBOL_TRADE_EXECUTION)this.GetProperty(SYMBOL_PROP_TRADE_EXEMODE);  }
   ENUM_SYMBOL_SWAP_MODE SwapMode(void)                           const { return (ENUM_SYMBOL_SWAP_MODE)this.GetProperty(SYMBOL_PROP_SWAP_MODE);            }
   ENUM_DAY_OF_WEEK  SwapRollover3Days(void)                      const { return (ENUM_DAY_OF_WEEK)this.GetProperty(SYMBOL_PROP_SWAP_ROLLOVER3DAYS);        }
   bool              IsMarginHedgedUseLeg(void)                   const { return (bool)this.GetProperty(SYMBOL_PROP_MARGIN_HEDGED_USE_LEG);                 }
   int               ExpirationModeFlags(void)                    const { return (int)this.GetProperty(SYMBOL_PROP_EXPIRATION_MODE);                        }
   int               FillingModeFlags(void)                       const { return (int)this.GetProperty(SYMBOL_PROP_FILLING_MODE);                           }
   int               OrderModeFlags(void)                         const { return (int)this.GetProperty(SYMBOL_PROP_ORDER_MODE);                             }
   ENUM_SYMBOL_ORDER_GTC_MODE OrderModeGTC(void)                  const { return (ENUM_SYMBOL_ORDER_GTC_MODE)this.GetProperty(SYMBOL_PROP_ORDER_GTC_MODE);  }
   ENUM_SYMBOL_OPTION_MODE OptionMode(void)                       const { return (ENUM_SYMBOL_OPTION_MODE)this.GetProperty(SYMBOL_PROP_OPTION_MODE);        }
   ENUM_SYMBOL_OPTION_RIGHT OptionRight(void)                     const { return (ENUM_SYMBOL_OPTION_RIGHT)this.GetProperty(SYMBOL_PROP_OPTION_RIGHT);      }
//--- Real properties
   double            Bid(void)                                    const { return this.GetProperty(SYMBOL_PROP_BID);                                         }
   double            BidHigh(void)                                const { return this.GetProperty(SYMBOL_PROP_BIDHIGH);                                     }
   double            BidLow(void)                                 const { return this.GetProperty(SYMBOL_PROP_BIDLOW);                                      }
   double            Ask(void)                                    const { return this.GetProperty(SYMBOL_PROP_ASK);                                         }
   double            AskHigh(void)                                const { return this.GetProperty(SYMBOL_PROP_ASKHIGH);                                     }
   double            AskLow(void)                                 const { return this.GetProperty(SYMBOL_PROP_ASKLOW);                                      }
   double            Last(void)                                   const { return this.GetProperty(SYMBOL_PROP_LAST);                                        }
   double            LastHigh(void)                               const { return this.GetProperty(SYMBOL_PROP_LASTHIGH);                                    }
   double            LastLow(void)                                const { return this.GetProperty(SYMBOL_PROP_LASTLOW);                                     }
   double            VolumeReal(void)                             const { return this.GetProperty(SYMBOL_PROP_VOLUME_REAL);                                 }
   double            VolumeHighReal(void)                         const { return this.GetProperty(SYMBOL_PROP_VOLUMEHIGH_REAL);                             }
   double            VolumeLowReal(void)                          const { return this.GetProperty(SYMBOL_PROP_VOLUMELOW_REAL);                              }
   double            OptionStrike(void)                           const { return this.GetProperty(SYMBOL_PROP_OPTION_STRIKE);                               }
   double            Point(void)                                  const { return this.GetProperty(SYMBOL_PROP_POINT);                                       }
   double            TradeTickValue(void)                         const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE);                            }
   double            TradeTickValueProfit(void)                   const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT);                     }
   double            TradeTickValueLoss(void)                     const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS);                       }
   double            TradeTickSize(void)                          const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_SIZE);                             }
   double            TradeContractSize(void)                      const { return this.GetProperty(SYMBOL_PROP_TRADE_CONTRACT_SIZE);                         }
   double            TradeAccuredInterest(void)                   const { return this.GetProperty(SYMBOL_PROP_TRADE_ACCRUED_INTEREST);                      }
   double            TradeFaceValue(void)                         const { return this.GetProperty(SYMBOL_PROP_TRADE_FACE_VALUE);                            }
   double            TradeLiquidityRate(void)                     const { return this.GetProperty(SYMBOL_PROP_TRADE_LIQUIDITY_RATE);                        }
   double            LotsMin(void)                                const { return this.GetProperty(SYMBOL_PROP_VOLUME_MIN);                                  }
   double            LotsMax(void)                                const { return this.GetProperty(SYMBOL_PROP_VOLUME_MAX);                                  }
   double            LotsStep(void)                               const { return this.GetProperty(SYMBOL_PROP_VOLUME_STEP);                                 }
   double            VolumeLimit(void)                            const { return this.GetProperty(SYMBOL_PROP_VOLUME_LIMIT);                                }
   double            SwapLong(void)                               const { return this.GetProperty(SYMBOL_PROP_SWAP_LONG);                                   }
   double            SwapShort(void)                              const { return this.GetProperty(SYMBOL_PROP_SWAP_SHORT);                                  }
   double            MarginInitial(void)                          const { return this.GetProperty(SYMBOL_PROP_MARGIN_INITIAL);                              }
   double            MarginMaintenance(void)                      const { return this.GetProperty(SYMBOL_PROP_MARGIN_MAINTENANCE);                          }
   double            MarginLongInitial(void)                      const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG_INITIAL);                         }
   double            MarginBuyStopInitial(void)                   const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL);                     }
   double            MarginBuyLimitInitial(void)                  const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL);                    }
   double            MarginBuyStopLimitInitial(void)              const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL);                }
   double            MarginLongMaintenance(void)                  const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE);                     }
   double            MarginBuyStopMaintenance(void)               const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE);                 }
   double            MarginBuyLimitMaintenance(void)              const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE);                }
   double            MarginBuyStopLimitMaintenance(void)          const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE);            }
   double            MarginShortInitial(void)                     const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT_INITIAL);                        }
   double            MarginSellStopInitial(void)                  const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL);                    }
   double            MarginSellLimitInitial(void)                 const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL);                   }
   double            MarginSellStopLimitInitial(void)             const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL);               }
   double            MarginShortMaintenance(void)                 const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE);                    }
   double            MarginSellStopMaintenance(void)              const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE);                }
   double            MarginSellLimitMaintenance(void)             const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE);               }
   double            MarginSellStopLimitMaintenance(void)         const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE);           }
   double            SessionVolume(void)                          const { return this.GetProperty(SYMBOL_PROP_SESSION_VOLUME);                              }
   double            SessionTurnover(void)                        const { return this.GetProperty(SYMBOL_PROP_SESSION_TURNOVER);                            }
   double            SessionInterest(void)                        const { return this.GetProperty(SYMBOL_PROP_SESSION_INTEREST);                            }
   double            SessionBuyOrdersVolume(void)                 const { return this.GetProperty(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME);                   }
   double            SessionSellOrdersVolume(void)                const { return this.GetProperty(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME);                  }
   double            SessionOpen(void)                            const { return this.GetProperty(SYMBOL_PROP_SESSION_OPEN);                                }
   double            SessionClose(void)                           const { return this.GetProperty(SYMBOL_PROP_SESSION_CLOSE);                               }
   double            SessionAW(void)                              const { return this.GetProperty(SYMBOL_PROP_SESSION_AW);                                  }
   double            SessionPriceSettlement(void)                 const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT);                    }
   double            SessionPriceLimitMin(void)                   const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN);                     }
   double            SessionPriceLimitMax(void)                   const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX);                     }
   double            MarginHedged(void)                           const { return this.GetProperty(SYMBOL_PROP_MARGIN_HEDGED);                               }
   double            NormalizedPrice(const double price)          const;
   double            NormalizedLot(const double volume)           const;
   double            BidLast(void)                                const;
   double            BidLastHigh(void)                            const;
   double            BidLastLow(void)                             const;
//--- String properties
   string            Name(void)                                   const { return this.GetProperty(SYMBOL_PROP_NAME);                                        }
   string            Basis(void)                                  const { return this.GetProperty(SYMBOL_PROP_BASIS);                                       }
   string            CurrencyBase(void)                           const { return this.GetProperty(SYMBOL_PROP_CURRENCY_BASE);                               }
   string            CurrencyProfit(void)                         const { return this.GetProperty(SYMBOL_PROP_CURRENCY_PROFIT);                             }
   string            CurrencyMargin(void)                         const { return this.GetProperty(SYMBOL_PROP_CURRENCY_MARGIN);                             }
   string            Bank(void)                                   const { return this.GetProperty(SYMBOL_PROP_BANK);                                        }
   string            Description(void)                            const { return this.GetProperty(SYMBOL_PROP_DESCRIPTION);                                 }
   string            Formula(void)                                const { return this.GetProperty(SYMBOL_PROP_FORMULA);                                     }
   string            ISIN(void)                                   const { return this.GetProperty(SYMBOL_PROP_ISIN);                                        }
   string            Page(void)                                   const { return this.GetProperty(SYMBOL_PROP_PAGE);                                        }
   string            Path(void)                                   const { return this.GetProperty(SYMBOL_PROP_PATH);                                        }
   string            Category(void)                               const { return this.GetProperty(SYMBOL_PROP_CATEGORY);                                    }
   string            Exchange(void)                               const { return this.GetProperty(SYMBOL_PROP_EXCHANGE);                                    }
   
//+------------------------------------------------------------------+

No construtor paramétrico fechado da classe, digitamos o recebimento destas novas propriedades:

   this.m_string_prop[this.IndexProp(SYMBOL_PROP_NAME)]                             = this.m_name;
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_BASE)]                    = ::SymbolInfoString(this.m_name,SYMBOL_CURRENCY_BASE);
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_PROFIT)]                  = ::SymbolInfoString(this.m_name,SYMBOL_CURRENCY_PROFIT);
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_MARGIN)]                  = ::SymbolInfoString(this.m_name,SYMBOL_CURRENCY_MARGIN);
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_DESCRIPTION)]                      = ::SymbolInfoString(this.m_name,SYMBOL_DESCRIPTION);
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_PATH)]                             = ::SymbolInfoString(this.m_name,SYMBOL_PATH);
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_BASIS)]                            = this.SymbolBasis();
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_BANK)]                             = this.SymbolBank();
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_ISIN)]                             = this.SymbolISIN();
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_FORMULA)]                          = this.SymbolFormula();
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_PAGE)]                             = this.SymbolPage();
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_CATEGORY)]                         = this.SymbolCategory();
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_EXCHANGE)]                         = this.SymbolExchange();
//--- Save additional integer properties

Fora do corpo da classe, escrevemos a implementação de métodos para obter duas novas propriedades:

//+------------------------------------------------------------------+
//| Return a symbol category                                         |
//+------------------------------------------------------------------+
string CSymbol::SymbolCategory(void) const
  {
   return
     (
      #ifdef __MQL5__ 
         (
          ::TerminalInfoInteger(TERMINAL_BUILD)<2155 ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_2155) :
          ::SymbolInfoString(this.m_name,SYMBOL_CATEGORY)
         ) 
      #else 
         ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MQL4)
      #endif
     );
  }
//+------------------------------------------------------------------+
//| Return an exchange name                                          |
//| a symbol is traded on                                            |
//+------------------------------------------------------------------+
string CSymbol::SymbolExchange(void) const
  {
   return
     (
      #ifdef __MQL5__ 
         (
          ::TerminalInfoInteger(TERMINAL_BUILD)<2155 ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_2155) :
          ::SymbolInfoString(this.m_name,SYMBOL_EXCHANGE)
         ) 
      #else 
         ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MQL4)
      #endif
     );
  }
//+------------------------------------------------------------------+

Neste caso, para MQL5, verificamos qual a compilação do terminal e, se for menor que 2155, retornamos uma mensagem informando que esta propriedade não é suportada na versão inferior a 2155, caso contrário, retornamos a nova propriedade SYMBOL_EXCHANGE.
Para MQL4, retornamos imediatamente uma mensagem indicando que a propriedade não é suportada em MQL4.

À implementação do método que retorna a descrição da propriedade de string do símbolo adicionamos um retorno de descrições de duas novas propriedades:

//+------------------------------------------------------------------+
//| Return the description of a symbol string property               |
//+------------------------------------------------------------------+
string CSymbol::GetPropertyDescription(ENUM_SYMBOL_PROP_STRING property)
  {
   return
     (
      property==SYMBOL_PROP_NAME             ?  CMessage::Text(MSG_SYM_PROP_NAME)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.GetProperty(property)
         )  :
      property==SYMBOL_PROP_BASIS            ?  CMessage::Text(MSG_SYM_PROP_BASIS)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"")
         )  :
      property==SYMBOL_PROP_CURRENCY_BASE    ?  CMessage::Text(MSG_SYM_PROP_CURRENCY_BASE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"")
         )  :
      property==SYMBOL_PROP_CURRENCY_PROFIT  ?  CMessage::Text(MSG_SYM_PROP_CURRENCY_PROFIT)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"")
         )  :
      property==SYMBOL_PROP_CURRENCY_MARGIN  ?  CMessage::Text(MSG_SYM_PROP_CURRENCY_MARGIN)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"")
         )  :
      property==SYMBOL_PROP_BANK             ?  CMessage::Text(MSG_SYM_PROP_BANK)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"")
         )  :
      property==SYMBOL_PROP_DESCRIPTION      ?  CMessage::Text(MSG_SYM_PROP_DESCRIPTION)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"")
         )  :
      property==SYMBOL_PROP_FORMULA          ?  CMessage::Text(MSG_SYM_PROP_FORMULA)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"")
         )  :
      property==SYMBOL_PROP_ISIN             ?  CMessage::Text(MSG_SYM_PROP_ISIN)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"")
         )  :
      property==SYMBOL_PROP_PAGE             ?  CMessage::Text(MSG_SYM_PROP_PAGE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"")
         )  :
      property==SYMBOL_PROP_PATH             ?  CMessage::Text(MSG_SYM_PROP_PATH)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"")
         )  :
      property==SYMBOL_PROP_CATEGORY         ?  CMessage::Text(MSG_SYM_PROP_CAYEGORY)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"")
         )  :
      property==SYMBOL_PROP_EXCHANGE         ?  CMessage::Text(MSG_SYM_PROP_EXCHANGE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"")
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+

Agora, terminamos de escrever uma nova propriedade para o objeto-conta no arquivo \MQL5\Include\DoEasy\Objects\Accounts\Account.mqh.

Na estrutura das propriedades da conta acrescentamos um novo campo:

//+------------------------------------------------------------------+
//| Account class                                                    |
//+------------------------------------------------------------------+
class CAccount : public CBaseObj
  {
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 decimal places for the account currency)
      int            server_type;                  // Trade server type (MetaTrader 5, MetaTrader 4)
      bool           fifo_close;                   // The flag indicating that positions can be closed only by the FIFO rule
      //--- Account real properties
      double         balance;                      // ACCOUNT_BALANCE (Account balance in a deposit currency)
      double         credit;                       // ACCOUNT_CREDIT (Credit in a deposit currency)
      double         profit;                       // ACCOUNT_PROFIT (Current profit on an account in the account currency)
      double         equity;                       // ACCOUNT_EQUITY (Equity on an account in the deposit currency)
      double         margin;                       // ACCOUNT_MARGIN (Reserved margin on an account in a deposit currency)
      double         margin_free;                  // ACCOUNT_MARGIN_FREE (Free funds available for opening a position in a deposit currency)
      double         margin_level;                 // ACCOUNT_MARGIN_LEVEL (Margin level on an account in %)
      double         margin_so_call;               // ACCOUNT_MARGIN_SO_CALL (MarginCall)
      double         margin_so_so;                 // ACCOUNT_MARGIN_SO_SO (StopOut)
      double         margin_initial;               // ACCOUNT_MARGIN_INITIAL (Funds reserved on an account to ensure a guarantee amount for all pending orders)
      double         margin_maintenance;           // ACCOUNT_MARGIN_MAINTENANCE (Funds reserved on an account to ensure a minimum amount for all open positions)
      double         assets;                       // ACCOUNT_ASSETS (Current assets on an account)
      double         liabilities;                  // ACCOUNT_LIABILITIES (Current liabilities on an account)
      double         comission_blocked;            // ACCOUNT_COMMISSION_BLOCKED (Current sum of blocked commissions on an account)
      //--- 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                                     // Структура объекта-аккаунта

À seção pública da classe, no bloco de métodos de acesso simplificado às propriedades do objeto, digitamos o método que retorna uma nova propriedade:

//+------------------------------------------------------------------+
//| Methods of a simplified access to the account object properties  |
//+------------------------------------------------------------------+
//--- Return the account's integer properties
   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 { return this.GetProperty(ACCOUNT_PROP_LOGIN);                                         }
   long              Leverage(void)                                  const { return this.GetProperty(ACCOUNT_PROP_LEVERAGE);                                      }
   long              LimitOrders(void)                               const { return this.GetProperty(ACCOUNT_PROP_LIMIT_ORDERS);                                  }
   long              TradeAllowed(void)                              const { return this.GetProperty(ACCOUNT_PROP_TRADE_ALLOWED);                                 }
   long              TradeExpert(void)                               const { return this.GetProperty(ACCOUNT_PROP_TRADE_EXPERT);                                  }
   long              CurrencyDigits(void)                            const { return this.GetProperty(ACCOUNT_PROP_CURRENCY_DIGITS);                               }
   long              ServerType(void)                                const { return this.GetProperty(ACCOUNT_PROP_SERVER_TYPE);                                   }
   long              FIFOClose(void)                                 const { return this.GetProperty(ACCOUNT_PROP_FIFO_CLOSE);                                    }
//--- Return the account's real properties

No construtor da classe, inserimos o armazenamento da nova propriedade de objeto-conta:

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CAccount::CAccount(void)
  {
//--- Initialize control data
   this.SetControlDataArraySizeLong(ACCOUNT_PROP_INTEGER_TOTAL);
   this.SetControlDataArraySizeDouble(ACCOUNT_PROP_DOUBLE_TOTAL);
   this.ResetChangesParams();
   this.ResetControlsParams();
  
//--- Save integer properties
   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);
   this.m_long_prop[ACCOUNT_PROP_FIFO_CLOSE]                         = (#ifdef __MQL5__::TerminalInfoInteger(TERMINAL_BUILD)<2155 ? false : ::AccountInfoInteger(ACCOUNT_FIFO_CLOSE) #else false #endif );
   
//--- Save real properties

Se a versão do terminal estiver abaixo de 2155, digitamos false, caso contrário, o valor da propriedade de conta ACCOUNT_FIFO_CLOSE.

No método para atualizar a propriedade de conta Refresh() também inserimos a preservação desta propriedade:

//+------------------------------------------------------------------+
//| Update all account data                                          |
//+------------------------------------------------------------------+
void CAccount::Refresh(void)
  {
//--- Initialize event data
   this.m_is_event=false;
   this.m_hash_sum=0;
//--- Update integer properties
   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);
   this.m_long_prop[ACCOUNT_PROP_FIFO_CLOSE]                            = (#ifdef __MQL5__::TerminalInfoInteger(TERMINAL_BUILD)<2155 ? false : ::AccountInfoInteger(ACCOUNT_FIFO_CLOSE) #else false #endif );
   
//--- Update real properties

No método para criar o objeto-conta a partir da estrutura escrevemos o preenchimento de uma nova propriedade:

//+------------------------------------------------------------------+
//| Create the account object from the structure                     |
//+------------------------------------------------------------------+
void CAccount::StructToObject(void)
  {
//--- Save integer properties
   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;
   this.m_long_prop[ACCOUNT_PROP_FIFO_CLOSE]                         = this.m_struct_obj.fifo_close;
//--- Save real properties

No método que retorna a descrição das propriedades de número inteiro do objeto-conta inserimos a exibição da descrição da nova propriedade:

//| Return the description of the account integer property           |
//+------------------------------------------------------------------+
string CAccount::GetPropertyDescription(ENUM_ACCOUNT_PROP_INTEGER property)
  {
   return
     (
      property==ACCOUNT_PROP_LOGIN           ?  CMessage::Text(MSG_ACC_PROP_LOGIN)+": "+(string)this.GetProperty(property)                            :
      property==ACCOUNT_PROP_TRADE_MODE      ?  CMessage::Text(MSG_ACC_PROP_TRADE_MODE)+": "+this.TradeModeDescription()                              :
      property==ACCOUNT_PROP_LEVERAGE        ?  CMessage::Text(MSG_ACC_PROP_LEVERAGE)+": "+(string)this.GetProperty(property)                         :
      property==ACCOUNT_PROP_LIMIT_ORDERS    ?  CMessage::Text(MSG_ACC_PROP_LIMIT_ORDERS)+": "+(string)this.GetProperty(property)                     :
      property==ACCOUNT_PROP_MARGIN_SO_MODE  ?  CMessage::Text(MSG_ACC_PROP_MARGIN_SO_MODE)+": "+this.MarginSOModeDescription()                       :
      property==ACCOUNT_PROP_TRADE_ALLOWED   ?  CMessage::Text(MSG_ACC_PROP_TRADE_ALLOWED)+": "+
                                                   (this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))  :
      property==ACCOUNT_PROP_TRADE_EXPERT    ?  CMessage::Text(MSG_ACC_PROP_TRADE_EXPERT)+": "+
                                                   (this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))  :
      property==ACCOUNT_PROP_MARGIN_MODE     ?  CMessage::Text(MSG_ACC_PROP_MARGIN_MODE)+": "+this.MarginModeDescription()                            :
      property==ACCOUNT_PROP_CURRENCY_DIGITS ?  CMessage::Text(MSG_ACC_PROP_CURRENCY_DIGITS)+": "+(string)this.GetProperty(property)                  :
      property==ACCOUNT_PROP_SERVER_TYPE     ?  CMessage::Text(MSG_ACC_PROP_SERVER_TYPE)+": "+(string)this.GetProperty(property)                      :
      property==ACCOUNT_PROP_FIFO_CLOSE      ?  CMessage::Text(MSG_ACC_PROP_FIFO_CLOSE)+": "+(string)this.GetProperty(property)                       :
      ""
     );
  }
//+------------------------------------------------------------------+

É necessário considerar que a inclusão de uma nova propriedade no objeto-conta torna inválidos os objetos-conta salvos anteriormente na pasta compartilhada de terminais, e para que não haja erros de leitura, é necessário por conta própria excluir todos os arquivos de contas criados anteriormente na pasta compartilhada de terminais na subpasta \DoEasy\Accounts\. Mais tarde, ao alterar a conta para uma nova, a própria biblioteca salvará os objetos-conta num novo formato.
Para abrir a pasta compartilhada de terminais, é preciso usar o menu do editor "Arquivo -> Abrir pasta de dados comum", e na janela que aparece entrar na pasta Files, logo, na subpasta da biblioteca \DoEasy\Accounts\

Para trabalhar com a classe de negociação criada hoje, precisaremos obter a margem necessária para abrir uma posição ou colocar uma ordem.

Na seção pública da classe, inserimos a definição do método que retorna a margem necessária para abrir a posição especificada ou posicionar uma ordem pendente:

public:
//--- Constructor
                     CAccount(void);
//--- Set account's (1) integer, (2) real and (3) string properties
   void              SetProperty(ENUM_ACCOUNT_PROP_INTEGER property,long value)        { this.m_long_prop[property]=value;                                  }
   void              SetProperty(ENUM_ACCOUNT_PROP_DOUBLE property,double value)       { this.m_double_prop[this.IndexProp(property)]=value;                }
   void              SetProperty(ENUM_ACCOUNT_PROP_STRING property,string value)       { this.m_string_prop[this.IndexProp(property)]=value;                }
//--- Return (1) integer, (2) real and (3) string order properties from the account string property
   long              GetProperty(ENUM_ACCOUNT_PROP_INTEGER property)             const { return this.m_long_prop[property];                                 }
   double            GetProperty(ENUM_ACCOUNT_PROP_DOUBLE property)              const { return this.m_double_prop[this.IndexProp(property)];               }
   string            GetProperty(ENUM_ACCOUNT_PROP_STRING property)              const { return this.m_string_prop[this.IndexProp(property)];               }
//--- Return the flag of calculating MarginCall and StopOut levels in %
   bool              IsPercentsForSOLevels(void)                                 const { return this.MarginSOMode()==ACCOUNT_STOPOUT_MODE_PERCENT;          }
//--- Return the flag of supporting the property by the account object
   virtual bool      SupportProperty(ENUM_ACCOUNT_PROP_INTEGER property)               { return true; }
   virtual bool      SupportProperty(ENUM_ACCOUNT_PROP_DOUBLE property)                { return true; }
   virtual bool      SupportProperty(ENUM_ACCOUNT_PROP_STRING property)                { return true; }

//--- Compare CAccount objects by all possible properties (for sorting the lists by a specified account object property)
   virtual int       Compare(const CObject *node,const int mode=0) const;
//--- Compare CAccount objects by account properties (to search for equal account objects)
   bool              IsEqual(CAccount* compared_account) const;
//--- Update all account data
   virtual void      Refresh(void);
//--- (1) Save the account object to the file, (2), download the account object from the file
   virtual bool      Save(const int file_handle);
   virtual bool      Load(const int file_handle);
 
//--- Return the margin required for opening a position or placing a pending order
   double            MarginForAction(const ENUM_ORDER_TYPE action,const string symbol,const double volume,const double price) const;

//+------------------------------------------------------------------+

E fora do corpo da classe, escrevemos sua implementação:

//+------------------------------------------------------------------+
//| Return the margin required for opening a position                |
//| or placing a pending order                                       |
//+------------------------------------------------------------------+
double CAccount::MarginForAction(const ENUM_ORDER_TYPE action,const string symbol,const double volume,const double price) const
  {
   double margin=EMPTY_VALUE;
   #ifdef __MQL5__
      return(!::OrderCalcMargin(action,symbol,volume,price,margin) ? EMPTY_VALUE : margin);
   #else 
      return this.MarginFree()-::AccountFreeMarginCheck(symbol,action,volume);
   #endif
  }
//+------------------------------------------------------------------+

Neste caso, para MQL5 obtemos, com a ajuda da função OrderCalcMargin(), o tamanho da margem necessária para abrir uma nova posição ou colocar uma ordem pendente. Além disso, se, por algum motivo, a função retornar um erro, retornaremos o valor máximo DBL_MAX (este valor tem a constante EMPTY_VALUE), caso contrário, o tamanho calculado da margem necessária.
Para o MQL4, retornamos o tamanho da margem livre disponível menos os fundos que restam após abrir a posição especificada ou colocar a ordem, calculados usando a função AccountFreeMarginCheck().

Assim, concluímos a modificação da classe objeto-conta.

Agora vamos aprimorar a classe do objeto básico de negociação. Precisamos acrescentar a ele a capacidade de definir qualquer som para sonorizar eventos de negociação.
Para armazenar dados, na seção privada da classe criamos uma estrutura que armazene sinalizadores que permitam usar sons e nomes de arquivos de som para diferentes eventos:

//+------------------------------------------------------------------+
//| Trading object class                                             |
//+------------------------------------------------------------------+
class CTradeObj
  {
private:
   struct SActionsFlags
     {
   private:
      bool                    m_use_sound_open;          // The flag of using the position opening/order placing sound
      bool                    m_use_sound_close;         // The flag of using the position closing/order removal sound
      bool                    m_use_sound_modify_sl;     // The flag of using the StopLoss position/order modification sound
      bool                    m_use_sound_modify_tp;     // The flag of using the TakeProfit position/order modification sound
      bool                    m_use_sound_modify_price;  // The flag of using the order placement price modification sound
      //---
      string                  m_sound_open;              // Position opening/order placing sound
      string                  m_sound_close;             // Position closing/order removal sound
      string                  m_sound_modify_sl;         // StopLoss position/order modification sound
      string                  m_sound_modify_tp;         // TakeProfit position/order modification sound
      string                  m_sound_modify_price;      // Order placement price modification sound
      //---
      string                  m_sound_open_err;          // Position opening/order placing error sound
      string                  m_sound_close_err;         // Position closing/order removal error sound
      string                  m_sound_modify_sl_err;     // StopLoss position/order modification error sound
      string                  m_sound_modify_tp_err;     // TakeProfit position/order modification error sound
      string                  m_sound_modify_price_err;  // Order placement price modification error sound
   public:
      //--- Method of placing/accessing flags and file names
      void                    UseSoundOpen(const bool flag)                      { this.m_use_sound_open=flag;             }
      void                    UseSoundClose(const bool flag)                     { this.m_use_sound_close=flag;            }
      void                    UseSoundModifySL(const bool flag)                  { this.m_use_sound_modify_sl=flag;        }
      void                    UseSoundModifyTP(const bool flag)                  { this.m_use_sound_modify_tp=flag;        }
      void                    UseSoundModifyPrice(const bool flag)               { this.m_use_sound_modify_price=flag;     }
      bool                    UseSoundOpen(void)                           const { return this.m_use_sound_open;           }
      bool                    UseSoundClose(void)                          const { return this.m_use_sound_close;          }
      bool                    UseSoundModifySL(void)                       const { return this.m_use_sound_modify_sl;      }
      bool                    UseSoundModifyTP(void)                       const { return this.m_use_sound_modify_tp;      }
      bool                    UseSoundModifyPrice(void)                    const { return this.m_use_sound_modify_price;   }
      //---
      void                    SoundOpen(const string sound)                      { this.m_sound_open=sound;                }
      void                    SoundClose(const string sound)                     { this.m_sound_close=sound;               }
      void                    SoundModifySL(const string sound)                  { this.m_sound_modify_sl=sound;           }
      void                    SoundModifyTP(const string sound)                  { this.m_sound_modify_tp=sound;           }
      void                    SoundModifyPrice(const string sound)               { this.m_sound_modify_price=sound;        }
      string                  SoundOpen(void)                              const { return this.m_sound_open;               }
      string                  SoundClose(void)                             const { return this.m_sound_close;              }
      string                  SoundModifySL(void)                          const { return this.m_sound_modify_sl;          }
      string                  SoundModifyTP(void)                          const { return this.m_sound_modify_tp;          }
      string                  SoundModifyPrice(void)                       const { return this.m_sound_modify_price;       }
      //---
      void                    SoundErrorOpen(const string sound)                 { this.m_sound_open_err=sound;            }
      void                    SoundErrorClose(const string sound)                { this.m_sound_close_err=sound;           }
      void                    SoundErrorModifySL(const string sound)             { this.m_sound_modify_sl_err=sound;       }
      void                    SoundErrorModifyTP(const string sound)             { this.m_sound_modify_tp_err=sound;       }
      void                    SoundErrorModifyPrice(const string sound)          { this.m_sound_modify_price_err=sound;    }
      string                  SoundErrorOpen(void)                         const { return this.m_sound_open_err;           }
      string                  SoundErrorClose(void)                        const { return this.m_sound_close_err;          }
      string                  SoundErrorModifySL(void)                     const { return this.m_sound_modify_sl_err;      }
      string                  SoundErrorModifyTP(void)                     const { return this.m_sound_modify_tp_err;      }
      string                  SoundErrorModifyPrice(void)                  const { return this.m_sound_modify_price_err;   }
     };
   struct SActions
     {
      SActionsFlags           Buy;
      SActionsFlags           BuyStop;
      SActionsFlags           BuyLimit;
      SActionsFlags           BuyStopLimit;
      SActionsFlags           Sell;
      SActionsFlags           SellStop;
      SActionsFlags           SellLimit;
      SActionsFlags           SellStopLimit;
     };
   SActions                   m_datas;

A estrutura consiste em duas estruturas aninhadas: uma estrutura SActionsFlags contendo dados sobre sinalizadores e sobre nomes dos arquivos, e outra estrutura SActionsm_data que inclui dados sobre o tipo de estrutura SActionsFlags para cada um dos tipos de posições e ordens. Desse modo, sempre podemos, para qualquer ordem ou posição, endereçar-nos ao campo da sua estrutura com os sinalizadores e nomes de arquivos, o que nos dá uma grande flexibilidade na configuração e no uso de sons para qualquer evento.

Aqui também,
na seção privada da classe, declaramos uma variável-membro da classe que armazena o sinalizador para o objeto de negociação usar sons durante eventos de negociação:

   bool                       m_use_sound;                   // The flag of using sounds of the object trading events

Este sinalizador será um botão de alternância comum que permitirá usar sons para todos os eventos de negociação do objeto de negociação do símbolo. Com a ajuda deste sinalizador, será possível ativar/desativar o uso de sons para eventos de negociação de cada símbolo de uma vez.

Na seção pública da classe declararemos todos os métodos necessários para definir e receber sinalizadores que permitem o uso de sons e nomes de arquivos de som para todos os eventos de negociação do objeto básico de negociação do símbolo:

public:
//--- Constructor
                              CTradeObj();

//--- Set default values
   void                       Init(const string symbol,
                                   const ulong magic,
                                   const double volume,
                                   const ulong deviation,
                                   const int stoplimit,
                                   const datetime expiration,
                                   const bool async_mode,
                                   const ENUM_ORDER_TYPE_FILLING type_filling,
                                   const ENUM_ORDER_TYPE_TIME type_expiration,
                                   ENUM_LOG_LEVEL log_level);
                                   
//--- Set default sounds and flags of using sounds,
   void                       InitSounds(const bool use_sound=false,
                                         const string sound_open=NULL,
                                         const string sound_close=NULL,
                                         const string sound_sl=NULL,
                                         const string sound_tp=NULL,
                                         const string sound_price=NULL,
                                         const string sound_error=NULL);
//--- Allow working with sounds and set standard sounds
   void                       SetSoundsStandart(void);
//--- Set the flag of using the sound of (1) opening/placing a specified position/order type,
//--- (2) closing/removal of a specified position/order type, (3) StopLoss modification for a specified position/order type,
//--- (4) TakeProfit modification for a specified position/order type, (5) placement price modification for a specified order type
   void                       UseSoundOpen(const ENUM_ORDER_TYPE action,const bool flag);
   void                       UseSoundClose(const ENUM_ORDER_TYPE action,const bool flag);
   void                       UseSoundModifySL(const ENUM_ORDER_TYPE action,const bool flag);
   void                       UseSoundModifyTP(const ENUM_ORDER_TYPE action,const bool flag);
   void                       UseSoundModifyPrice(const ENUM_ORDER_TYPE action,const bool flag);
//--- Return the flag of using the sound of (1) opening/placing a specified position/order type,
//--- (2) closing/removal of a specified position/order type, (3) StopLoss modification for a specified position/order type,
//--- (4) TakeProfit modification for a specified position/order type, (5) placement price modification for a specified order type
   bool                       UseSoundOpen(const ENUM_ORDER_TYPE action)            const;
   bool                       UseSoundClose(const ENUM_ORDER_TYPE action)           const;
   bool                       UseSoundModifySL(const ENUM_ORDER_TYPE action)        const;
   bool                       UseSoundModifyTP(const ENUM_ORDER_TYPE action)        const;
   bool                       UseSoundModifyPrice(const ENUM_ORDER_TYPE action)     const;

//--- Set the sound of (1) opening/placing a specified position/order type,
//--- (2) closing/removal of a specified position/order type, (3) StopLoss modification for a specified position/order type,
//--- (4) TakeProfit modification for a specified position/order type, (5) placement price modification for a specified order type
   void                       SetSoundOpen(const ENUM_ORDER_TYPE action,const string sound);
   void                       SetSoundClose(const ENUM_ORDER_TYPE action,const string sound);
   void                       SetSoundModifySL(const ENUM_ORDER_TYPE action,const string sound);
   void                       SetSoundModifyTP(const ENUM_ORDER_TYPE action,const string sound);
   void                       SetSoundModifyPrice(const ENUM_ORDER_TYPE action,const string sound);
//--- Set the error sound of (1) opening/placing a specified position/order type,
//--- (2) closing/removal of a specified position/order type, (3) StopLoss modification for a specified position/order type,
//--- (4) TakeProfit modification for a specified position/order type, (5) placement price modification for a specified order type
   void                       SetSoundErrorOpen(const ENUM_ORDER_TYPE action,const string sound);
   void                       SetSoundErrorClose(const ENUM_ORDER_TYPE action,const string sound);
   void                       SetSoundErrorModifySL(const ENUM_ORDER_TYPE action,const string sound);
   void                       SetSoundErrorModifyTP(const ENUM_ORDER_TYPE action,const string sound);
   void                       SetSoundErrorModifyPrice(const ENUM_ORDER_TYPE action,const string sound);

//--- Return the sound of (1) opening/placing a specified position/order type,
//--- (2) closing/removal of a specified position/order type, (3) StopLoss modification for a specified position/order type,
//--- (4) TakeProfit modification for a specified position/order type, (5) placement price modification for a specified order type
   string                     GetSoundOpen(const ENUM_ORDER_TYPE action)               const;
   string                     GetSoundClose(const ENUM_ORDER_TYPE action)              const;
   string                     GetSoundModifySL(const ENUM_ORDER_TYPE action)           const;
   string                     GetSoundModifyTP(const ENUM_ORDER_TYPE action)           const;
   string                     GetSoundModifyPrice(const ENUM_ORDER_TYPE action)        const;
//--- Return the error sound of (1) opening/placing a specified position/order type,
//--- (2) closing/removal of a specified position/order type, (3) StopLoss modification for a specified position/order type,
//--- (4) TakeProfit modification for a specified position/order type, (5) placement price modification for a specified order type
   string                     GetSoundErrorOpen(const ENUM_ORDER_TYPE action)          const;
   string                     GetSoundErrorClose(const ENUM_ORDER_TYPE action)         const;
   string                     GetSoundErrorModifySL(const ENUM_ORDER_TYPE action)      const;
   string                     GetSoundErrorModifyTP(const ENUM_ORDER_TYPE action)      const;
   string                     GetSoundErrorModifyPrice(const ENUM_ORDER_TYPE action)   const;
   
//--- Play the sound of (1) opening/placing a specified position/order type,
//--- (2) closing/removal of a specified position/order type, (3) StopLoss modification for a specified position/order type,
//--- (4) TakeProfit modification for a specified position/order type, (5) placement price modification for a specified order type
   void                       PlaySoundOpen(const ENUM_ORDER_TYPE action);
   void                       PlaySoundClose(const ENUM_ORDER_TYPE action);
   void                       PlaySoundModifySL(const ENUM_ORDER_TYPE action);
   void                       PlaySoundModifyTP(const ENUM_ORDER_TYPE action);
   void                       PlaySoundModifyPrice(const ENUM_ORDER_TYPE action);
//--- Play the error sound of (1) opening/placing a specified position/order type,
//--- (2) closing/removal of a specified position/order type, (3) StopLoss modification for a specified position/order type,
//--- (4) TakeProfit modification for a specified position/order type, (5) placement price modification for a specified order type
   void                       PlaySoundErrorOpen(const ENUM_ORDER_TYPE action);
   void                       PlaySoundErrorClose(const ENUM_ORDER_TYPE action);
   void                       PlaySoundErrorModifySL(const ENUM_ORDER_TYPE action);
   void                       PlaySoundErrorModifyTP(const ENUM_ORDER_TYPE action);
   void                       PlaySoundErrorModifyPrice(const ENUM_ORDER_TYPE action);

//--- Set/return the flag of using sounds
   void                       SetUseSound(const bool flag)                             { this.m_use_sound=flag;               }
   bool                       IsUseSound(void)                                   const { return this.m_use_sound;             }

//--- (1) Return the margin calculation mode, (2) hedge account flag

No construtor da classe redefinimos o sinalizador comum para usar sons, e inicializamos os sinalizadores para usar sons e arquivos de som com valores padrão como a não permissão de sons e de nomes de arquivos vazios:

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CTradeObj::CTradeObj(void) : m_magic(0),
                             m_deviation(5),
                             m_stop_limit(0),
                             m_expiration(0),
                             m_async_mode(false),
                             m_type_filling(ORDER_FILLING_FOK),
                             m_type_expiration(ORDER_TIME_GTC),
                             m_comment(::MQLInfoString(MQL_PROGRAM_NAME)+" by DoEasy"),
                             m_log_level(LOG_LEVEL_ERROR_MSG)
  {
   //--- Margin calculation mode
   this.m_margin_mode=
     (
      #ifdef __MQL5__ (ENUM_ACCOUNT_MARGIN_MODE)::AccountInfoInteger(ACCOUNT_MARGIN_MODE)
      #else /* MQL4 */ ACCOUNT_MARGIN_MODE_RETAIL_HEDGING #endif 
     );
   //--- Set default sounds and flags of using sounds
   this.m_use_sound=false;
   this.InitSounds();
  }
//+------------------------------------------------------------------+

Fora do corpo da classe, escrevemos uma implementação do método para inicializar os sinalizadores para usar sons e definir os nomes dos arquivos de som:

//+------------------------------------------------------------------+
//| Set default sounds and flags of using sounds                     |
//+------------------------------------------------------------------+
void CTradeObj::InitSounds(const bool use_sound=false,
                           const string sound_open=NULL,
                           const string sound_close=NULL,
                           const string sound_sl=NULL,
                           const string sound_tp=NULL,
                           const string sound_price=NULL,
                           const string sound_error=NULL)
  {
   this.m_datas.Buy.UseSoundOpen(use_sound);
   this.m_datas.Buy.UseSoundClose(use_sound);
   this.m_datas.Buy.UseSoundModifySL(use_sound);
   this.m_datas.Buy.UseSoundModifyTP(use_sound);
   this.m_datas.Buy.UseSoundModifyPrice(use_sound);
   this.m_datas.Buy.SoundOpen(sound_open);
   this.m_datas.Buy.SoundClose(sound_close);
   this.m_datas.Buy.SoundModifySL(sound_sl);
   this.m_datas.Buy.SoundModifyTP(sound_tp);
   this.m_datas.Buy.SoundModifyPrice(sound_price);
   this.m_datas.Buy.SoundErrorClose(sound_error);
   this.m_datas.Buy.SoundErrorOpen(sound_error);
   this.m_datas.Buy.SoundErrorModifySL(sound_error);
   this.m_datas.Buy.SoundErrorModifyTP(sound_error);
   this.m_datas.Buy.SoundErrorModifyPrice(sound_error);
   
   this.m_datas.BuyStop.UseSoundOpen(use_sound);
   this.m_datas.BuyStop.UseSoundClose(use_sound);
   this.m_datas.BuyStop.UseSoundModifySL(use_sound);
   this.m_datas.BuyStop.UseSoundModifyTP(use_sound);
   this.m_datas.BuyStop.UseSoundModifyPrice(use_sound);
   this.m_datas.BuyStop.SoundOpen(sound_open);
   this.m_datas.BuyStop.SoundClose(sound_close);
   this.m_datas.BuyStop.SoundModifySL(sound_sl);
   this.m_datas.BuyStop.SoundModifyTP(sound_tp);
   this.m_datas.BuyStop.SoundModifyPrice(sound_price);
   this.m_datas.BuyStop.SoundErrorClose(sound_error);
   this.m_datas.BuyStop.SoundErrorOpen(sound_error);
   this.m_datas.BuyStop.SoundErrorModifySL(sound_error);
   this.m_datas.BuyStop.SoundErrorModifyTP(sound_error);
   this.m_datas.BuyStop.SoundErrorModifyPrice(sound_error);
   
   this.m_datas.BuyLimit.UseSoundOpen(use_sound);
   this.m_datas.BuyLimit.UseSoundClose(use_sound);
   this.m_datas.BuyLimit.UseSoundModifySL(use_sound);
   this.m_datas.BuyLimit.UseSoundModifyTP(use_sound);
   this.m_datas.BuyLimit.UseSoundModifyPrice(use_sound);
   this.m_datas.BuyLimit.SoundOpen(sound_open);
   this.m_datas.BuyLimit.SoundClose(sound_close);
   this.m_datas.BuyLimit.SoundModifySL(sound_sl);
   this.m_datas.BuyLimit.SoundModifyTP(sound_tp);
   this.m_datas.BuyLimit.SoundModifyPrice(sound_price);
   this.m_datas.BuyLimit.SoundErrorClose(sound_error);
   this.m_datas.BuyLimit.SoundErrorOpen(sound_error);
   this.m_datas.BuyLimit.SoundErrorModifySL(sound_error);
   this.m_datas.BuyLimit.SoundErrorModifyTP(sound_error);
   this.m_datas.BuyLimit.SoundErrorModifyPrice(sound_error);
   
   this.m_datas.BuyStopLimit.UseSoundOpen(use_sound);
   this.m_datas.BuyStopLimit.UseSoundClose(use_sound);
   this.m_datas.BuyStopLimit.UseSoundModifySL(use_sound);
   this.m_datas.BuyStopLimit.UseSoundModifyTP(use_sound);
   this.m_datas.BuyStopLimit.UseSoundModifyPrice(use_sound);
   this.m_datas.BuyStopLimit.SoundOpen(sound_open);
   this.m_datas.BuyStopLimit.SoundClose(sound_close);
   this.m_datas.BuyStopLimit.SoundModifySL(sound_sl);
   this.m_datas.BuyStopLimit.SoundModifyTP(sound_tp);
   this.m_datas.BuyStopLimit.SoundModifyPrice(sound_price);
   this.m_datas.BuyStopLimit.SoundErrorClose(sound_error);
   this.m_datas.BuyStopLimit.SoundErrorOpen(sound_error);
   this.m_datas.BuyStopLimit.SoundErrorModifySL(sound_error);
   this.m_datas.BuyStopLimit.SoundErrorModifyTP(sound_error);
   this.m_datas.BuyStopLimit.SoundErrorModifyPrice(sound_error);
   
   this.m_datas.Sell.UseSoundOpen(use_sound);
   this.m_datas.Sell.UseSoundClose(use_sound);
   this.m_datas.Sell.UseSoundModifySL(use_sound);
   this.m_datas.Sell.UseSoundModifyTP(use_sound);
   this.m_datas.Sell.UseSoundModifyPrice(use_sound);
   this.m_datas.Sell.SoundOpen(sound_open);
   this.m_datas.Sell.SoundClose(sound_close);
   this.m_datas.Sell.SoundModifySL(sound_sl);
   this.m_datas.Sell.SoundModifyTP(sound_tp);
   this.m_datas.Sell.SoundModifyPrice(sound_price);
   this.m_datas.Sell.SoundErrorClose(sound_error);
   this.m_datas.Sell.SoundErrorOpen(sound_error);
   this.m_datas.Sell.SoundErrorModifySL(sound_error);
   this.m_datas.Sell.SoundErrorModifyTP(sound_error);
   this.m_datas.Sell.SoundErrorModifyPrice(sound_error);
   
   this.m_datas.SellStop.UseSoundOpen(use_sound);
   this.m_datas.SellStop.UseSoundClose(use_sound);
   this.m_datas.SellStop.UseSoundModifySL(use_sound);
   this.m_datas.SellStop.UseSoundModifyTP(use_sound);
   this.m_datas.SellStop.UseSoundModifyPrice(use_sound);
   this.m_datas.SellStop.SoundOpen(sound_open);
   this.m_datas.SellStop.SoundClose(sound_close);
   this.m_datas.SellStop.SoundModifySL(sound_sl);
   this.m_datas.SellStop.SoundModifyTP(sound_tp);
   this.m_datas.SellStop.SoundModifyPrice(sound_price);
   this.m_datas.SellStop.SoundErrorClose(sound_error);
   this.m_datas.SellStop.SoundErrorOpen(sound_error);
   this.m_datas.SellStop.SoundErrorModifySL(sound_error);
   this.m_datas.SellStop.SoundErrorModifyTP(sound_error);
   this.m_datas.SellStop.SoundErrorModifyPrice(sound_error);
   
   this.m_datas.SellLimit.UseSoundOpen(use_sound);
   this.m_datas.SellLimit.UseSoundClose(use_sound);
   this.m_datas.SellLimit.UseSoundModifySL(use_sound);
   this.m_datas.SellLimit.UseSoundModifyTP(use_sound);
   this.m_datas.SellLimit.UseSoundModifyPrice(use_sound);
   this.m_datas.SellLimit.SoundOpen(sound_open);
   this.m_datas.SellLimit.SoundClose(sound_close);
   this.m_datas.SellLimit.SoundModifySL(sound_sl);
   this.m_datas.SellLimit.SoundModifyTP(sound_tp);
   this.m_datas.SellLimit.SoundModifyPrice(sound_price);
   this.m_datas.SellLimit.SoundErrorClose(sound_error);
   this.m_datas.SellLimit.SoundErrorOpen(sound_error);
   this.m_datas.SellLimit.SoundErrorModifySL(sound_error);
   this.m_datas.SellLimit.SoundErrorModifyTP(sound_error);
   this.m_datas.SellLimit.SoundErrorModifyPrice(sound_error);
   
   this.m_datas.SellStopLimit.UseSoundOpen(use_sound);
   this.m_datas.SellStopLimit.UseSoundClose(use_sound);
   this.m_datas.SellStopLimit.UseSoundModifySL(use_sound);
   this.m_datas.SellStopLimit.UseSoundModifyTP(use_sound);
   this.m_datas.SellStopLimit.UseSoundModifyPrice(use_sound);
   this.m_datas.SellStopLimit.SoundOpen(sound_open);
   this.m_datas.SellStopLimit.SoundClose(sound_close);
   this.m_datas.SellStopLimit.SoundModifySL(sound_sl);
   this.m_datas.SellStopLimit.SoundModifyTP(sound_tp);
   this.m_datas.SellStopLimit.SoundModifyPrice(sound_price);
   this.m_datas.SellStopLimit.SoundErrorClose(sound_error);
   this.m_datas.SellStopLimit.SoundErrorOpen(sound_error);
   this.m_datas.SellStopLimit.SoundErrorModifySL(sound_error);
   this.m_datas.SellStopLimit.SoundErrorModifyTP(sound_error);
   this.m_datas.SellStopLimit.SoundErrorModifyPrice(sound_error);
  }  
//+------------------------------------------------------------------+

Ao método são transferidos o sinalizador para usar os sons dos eventos do objeto de negociação, os nomes de arquivo, os sons de abertura, de fechamento, de modificação do StopLoss e de modificação do TakeProfit, os preços de colocação de pedidos e os sons de erro. Em seguida, preenchemos com os valores transferidos os campos da estrutura para cada evento de negociação para cada tipo de ordem enviada ao servidor.

O sinalizador para o uso de sons e o nome do arquivo de som de erro são definidos aqui para todos os eventos de negociação listados, mas para os eventos de negociação para cada som são definidos individualmente. No entanto, se desejarmos, também podemos não apenas definir sons individuais para os sons de erro de eventos específicos usando os métodos anunciados acima, mas também definir o sinalizador para usar o som para cada evento de negociação do objeto individualmente. Por padrão, não são permitidos os sons e os nomes de arquivos vazios.

Na classe também é fornecido um método que permite definir simultaneamente para todos os eventos de negociação do objeto sons padrão e possibilitar seu uso para cada evento de negociação:

//+------------------------------------------------------------------+
//| Allow working with sounds and set standard sounds                |
//+------------------------------------------------------------------+
void CTradeObj::SetSoundsStandart(void)
  {
   this.m_datas.Buy.UseSoundClose(true);
   this.m_datas.Buy.UseSoundOpen(true);
   this.m_datas.Buy.UseSoundModifySL(true);
   this.m_datas.Buy.UseSoundModifyTP(true);
   this.m_datas.Buy.UseSoundModifyPrice(true);
   this.m_datas.Buy.SoundOpen(SND_OK);
   this.m_datas.Buy.SoundClose(SND_OK);
   this.m_datas.Buy.SoundModifySL(SND_OK);
   this.m_datas.Buy.SoundModifyTP(SND_OK);
   this.m_datas.Buy.SoundModifyPrice(SND_OK);
   this.m_datas.Buy.SoundErrorClose(SND_TIMEOUT);
   this.m_datas.Buy.SoundErrorOpen(SND_TIMEOUT);
   this.m_datas.Buy.SoundErrorModifySL(SND_TIMEOUT);
   this.m_datas.Buy.SoundErrorModifyTP(SND_TIMEOUT);
   this.m_datas.Buy.SoundErrorModifyPrice(SND_TIMEOUT);
   
   this.m_datas.BuyStop.UseSoundClose(true);
   this.m_datas.BuyStop.UseSoundOpen(true);
   this.m_datas.BuyStop.UseSoundModifySL(true);
   this.m_datas.BuyStop.UseSoundModifyTP(true);
   this.m_datas.BuyStop.UseSoundModifyPrice(true);
   this.m_datas.BuyStop.SoundOpen(SND_OK);
   this.m_datas.BuyStop.SoundClose(SND_OK);
   this.m_datas.BuyStop.SoundModifySL(SND_OK);
   this.m_datas.BuyStop.SoundModifyTP(SND_OK);
   this.m_datas.BuyStop.SoundModifyPrice(SND_OK);
   this.m_datas.BuyStop.SoundErrorClose(SND_TIMEOUT);
   this.m_datas.BuyStop.SoundErrorOpen(SND_TIMEOUT);
   this.m_datas.BuyStop.SoundErrorModifySL(SND_TIMEOUT);
   this.m_datas.BuyStop.SoundErrorModifyTP(SND_TIMEOUT);
   this.m_datas.BuyStop.SoundErrorModifyPrice(SND_TIMEOUT);
   
   this.m_datas.BuyLimit.UseSoundClose(true);
   this.m_datas.BuyLimit.UseSoundOpen(true);
   this.m_datas.BuyLimit.UseSoundModifySL(true);
   this.m_datas.BuyLimit.UseSoundModifyTP(true);
   this.m_datas.BuyLimit.UseSoundModifyPrice(true);
   this.m_datas.BuyLimit.SoundOpen(SND_OK);
   this.m_datas.BuyLimit.SoundClose(SND_OK);
   this.m_datas.BuyLimit.SoundModifySL(SND_OK);
   this.m_datas.BuyLimit.SoundModifyTP(SND_OK);
   this.m_datas.BuyLimit.SoundModifyPrice(SND_OK);
   this.m_datas.BuyLimit.SoundErrorClose(SND_TIMEOUT);
   this.m_datas.BuyLimit.SoundErrorOpen(SND_TIMEOUT);
   this.m_datas.BuyLimit.SoundErrorModifySL(SND_TIMEOUT);
   this.m_datas.BuyLimit.SoundErrorModifyTP(SND_TIMEOUT);
   this.m_datas.BuyLimit.SoundErrorModifyPrice(SND_TIMEOUT);
   
   this.m_datas.BuyStopLimit.UseSoundClose(true);
   this.m_datas.BuyStopLimit.UseSoundOpen(true);
   this.m_datas.BuyStopLimit.UseSoundModifySL(true);
   this.m_datas.BuyStopLimit.UseSoundModifyTP(true);
   this.m_datas.BuyStopLimit.UseSoundModifyPrice(true);
   this.m_datas.BuyStopLimit.SoundOpen(SND_OK);
   this.m_datas.BuyStopLimit.SoundClose(SND_OK);
   this.m_datas.BuyStopLimit.SoundModifySL(SND_OK);
   this.m_datas.BuyStopLimit.SoundModifyTP(SND_OK);
   this.m_datas.BuyStopLimit.SoundModifyPrice(SND_OK);
   this.m_datas.BuyStopLimit.SoundErrorClose(SND_TIMEOUT);
   this.m_datas.BuyStopLimit.SoundErrorOpen(SND_TIMEOUT);
   this.m_datas.BuyStopLimit.SoundErrorModifySL(SND_TIMEOUT);
   this.m_datas.BuyStopLimit.SoundErrorModifyTP(SND_TIMEOUT);
   this.m_datas.BuyStopLimit.SoundErrorModifyPrice(SND_TIMEOUT);
   
   this.m_datas.Sell.UseSoundClose(true);
   this.m_datas.Sell.UseSoundOpen(true);
   this.m_datas.Sell.UseSoundModifySL(true);
   this.m_datas.Sell.UseSoundModifyTP(true);
   this.m_datas.Sell.UseSoundModifyPrice(true);
   this.m_datas.Sell.SoundOpen(SND_OK);
   this.m_datas.Sell.SoundClose(SND_OK);
   this.m_datas.Sell.SoundModifySL(SND_OK);
   this.m_datas.Sell.SoundModifyTP(SND_OK);
   this.m_datas.Sell.SoundModifyPrice(SND_OK);
   this.m_datas.Sell.SoundErrorClose(SND_TIMEOUT);
   this.m_datas.Sell.SoundErrorOpen(SND_TIMEOUT);
   this.m_datas.Sell.SoundErrorModifySL(SND_TIMEOUT);
   this.m_datas.Sell.SoundErrorModifyTP(SND_TIMEOUT);
   this.m_datas.Sell.SoundErrorModifyPrice(SND_TIMEOUT);
   
   this.m_datas.SellStop.UseSoundClose(true);
   this.m_datas.SellStop.UseSoundOpen(true);
   this.m_datas.SellStop.UseSoundModifySL(true);
   this.m_datas.SellStop.UseSoundModifyTP(true);
   this.m_datas.SellStop.UseSoundModifyPrice(true);
   this.m_datas.SellStop.SoundOpen(SND_OK);
   this.m_datas.SellStop.SoundClose(SND_OK);
   this.m_datas.SellStop.SoundModifySL(SND_OK);
   this.m_datas.SellStop.SoundModifyTP(SND_OK);
   this.m_datas.SellStop.SoundModifyPrice(SND_OK);
   this.m_datas.SellStop.SoundErrorClose(SND_TIMEOUT);
   this.m_datas.SellStop.SoundErrorOpen(SND_TIMEOUT);
   this.m_datas.SellStop.SoundErrorModifySL(SND_TIMEOUT);
   this.m_datas.SellStop.SoundErrorModifyTP(SND_TIMEOUT);
   this.m_datas.SellStop.SoundErrorModifyPrice(SND_TIMEOUT);
   
   this.m_datas.SellLimit.UseSoundClose(true);
   this.m_datas.SellLimit.UseSoundOpen(true);
   this.m_datas.SellLimit.UseSoundModifySL(true);
   this.m_datas.SellLimit.UseSoundModifyTP(true);
   this.m_datas.SellLimit.UseSoundModifyPrice(true);
   this.m_datas.SellLimit.SoundOpen(SND_OK);
   this.m_datas.SellLimit.SoundClose(SND_OK);
   this.m_datas.SellLimit.SoundModifySL(SND_OK);
   this.m_datas.SellLimit.SoundModifyTP(SND_OK);
   this.m_datas.SellLimit.SoundModifyPrice(SND_OK);
   this.m_datas.SellLimit.SoundErrorClose(SND_TIMEOUT);
   this.m_datas.SellLimit.SoundErrorOpen(SND_TIMEOUT);
   this.m_datas.SellLimit.SoundErrorModifySL(SND_TIMEOUT);
   this.m_datas.SellLimit.SoundErrorModifyTP(SND_TIMEOUT);
   this.m_datas.SellLimit.SoundErrorModifyPrice(SND_TIMEOUT);
   
   this.m_datas.SellStopLimit.UseSoundClose(true);
   this.m_datas.SellStopLimit.UseSoundOpen(true);
   this.m_datas.SellStopLimit.UseSoundModifySL(true);
   this.m_datas.SellStopLimit.UseSoundModifyTP(true);
   this.m_datas.SellStopLimit.UseSoundModifyPrice(true);
   this.m_datas.SellStopLimit.SoundOpen(SND_OK);
   this.m_datas.SellStopLimit.SoundClose(SND_OK);
   this.m_datas.SellStopLimit.SoundModifySL(SND_OK);
   this.m_datas.SellStopLimit.SoundModifyTP(SND_OK);
   this.m_datas.SellStopLimit.SoundModifyPrice(SND_OK);
   this.m_datas.SellStopLimit.SoundErrorClose(SND_TIMEOUT);
   this.m_datas.SellStopLimit.SoundErrorOpen(SND_TIMEOUT);
   this.m_datas.SellStopLimit.SoundErrorModifySL(SND_TIMEOUT);
   this.m_datas.SellStopLimit.SoundErrorModifyTP(SND_TIMEOUT);
   this.m_datas.SellStopLimit.SoundErrorModifyPrice(SND_TIMEOUT);
  }
//+------------------------------------------------------------------+

Fora do corpo da classe, escrevemos métodos para reproduzir sons e definir sinalizadores e sons para um tipo específico de evento de negociação:

//+------------------------------------------------------------------+
//| Set the flag of using sounds                                     |
//| of opening/placing a specified position/order type               |
//+------------------------------------------------------------------+
void CTradeObj::UseSoundOpen(const ENUM_ORDER_TYPE action,const bool flag)
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   this.m_datas.Buy.UseSoundOpen(flag);           break;
      case ORDER_TYPE_BUY_STOP         :   this.m_datas.BuyStop.UseSoundOpen(flag);       break;
      case ORDER_TYPE_BUY_LIMIT        :   this.m_datas.BuyLimit.UseSoundOpen(flag);      break;
      case ORDER_TYPE_SELL             :   this.m_datas.Sell.UseSoundOpen(flag);          break;
      case ORDER_TYPE_SELL_STOP        :   this.m_datas.SellStop.UseSoundOpen(flag);      break;
      case ORDER_TYPE_SELL_LIMIT       :   this.m_datas.SellLimit.UseSoundOpen(flag);     break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   this.m_datas.BuyStopLimit.UseSoundOpen(flag);  break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   this.m_datas.SellStopLimit.UseSoundOpen(flag); break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Set the flag of using a sound                                    |
//| of closing/removal of a specified position/order type            |
//+------------------------------------------------------------------+
void CTradeObj::UseSoundClose(const ENUM_ORDER_TYPE action,const bool flag)
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   this.m_datas.Buy.UseSoundClose(flag);             break;
      case ORDER_TYPE_BUY_STOP         :   this.m_datas.BuyStop.UseSoundClose(flag);         break;
      case ORDER_TYPE_BUY_LIMIT        :   this.m_datas.BuyLimit.UseSoundClose(flag);        break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   this.m_datas.BuyStopLimit.UseSoundClose(flag);    break;
      case ORDER_TYPE_SELL             :   this.m_datas.Sell.UseSoundClose(flag);            break;
      case ORDER_TYPE_SELL_STOP        :   this.m_datas.SellStop.UseSoundClose(flag);        break;
      case ORDER_TYPE_SELL_LIMIT       :   this.m_datas.SellLimit.UseSoundClose(flag);       break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   this.m_datas.SellStopLimit.UseSoundClose(flag);   break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Set the flag of using a sound                                    |
//| of StopLoss modification for a specified position/order type     |
//+------------------------------------------------------------------+
void CTradeObj::UseSoundModifySL(const ENUM_ORDER_TYPE action,const bool flag)
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   this.m_datas.Buy.UseSoundModifySL(flag);             break;
      case ORDER_TYPE_BUY_STOP         :   this.m_datas.BuyStop.UseSoundModifySL(flag);         break;
      case ORDER_TYPE_BUY_LIMIT        :   this.m_datas.BuyLimit.UseSoundModifySL(flag);        break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   this.m_datas.BuyStopLimit.UseSoundModifySL(flag);    break;
      case ORDER_TYPE_SELL             :   this.m_datas.Sell.UseSoundModifySL(flag);            break;
      case ORDER_TYPE_SELL_STOP        :   this.m_datas.SellStop.UseSoundModifySL(flag);        break;
      case ORDER_TYPE_SELL_LIMIT       :   this.m_datas.SellLimit.UseSoundModifySL(flag);       break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   this.m_datas.SellStopLimit.UseSoundModifySL(flag);   break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Set the flag of using a sound                                    |
//| of TakeProfit modification for a specified position/order type   |
//+------------------------------------------------------------------+
void CTradeObj::UseSoundModifyTP(const ENUM_ORDER_TYPE action,const bool flag)
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   this.m_datas.Buy.UseSoundModifyTP(flag);             break;
      case ORDER_TYPE_BUY_STOP         :   this.m_datas.BuyStop.UseSoundModifyTP(flag);         break;
      case ORDER_TYPE_BUY_LIMIT        :   this.m_datas.BuyLimit.UseSoundModifyTP(flag);        break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   this.m_datas.BuyStopLimit.UseSoundModifyTP(flag);    break;
      case ORDER_TYPE_SELL             :   this.m_datas.Sell.UseSoundModifyTP(flag);            break;
      case ORDER_TYPE_SELL_STOP        :   this.m_datas.SellStop.UseSoundModifyTP(flag);        break;
      case ORDER_TYPE_SELL_LIMIT       :   this.m_datas.SellLimit.UseSoundModifyTP(flag);       break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   this.m_datas.SellStopLimit.UseSoundModifyTP(flag);   break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Set the flag of using a modification sound                       |
//| of the placement price for a specified order type                |
//+------------------------------------------------------------------+
void CTradeObj::UseSoundModifyPrice(const ENUM_ORDER_TYPE action,const bool flag)
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY_STOP         :   this.m_datas.BuyStop.UseSoundModifyPrice(flag);         break;
      case ORDER_TYPE_BUY_LIMIT        :   this.m_datas.BuyLimit.UseSoundModifyPrice(flag);        break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   this.m_datas.BuyStopLimit.UseSoundModifyPrice(flag);    break;
      case ORDER_TYPE_SELL_STOP        :   this.m_datas.SellStop.UseSoundModifyPrice(flag);        break;
      case ORDER_TYPE_SELL_LIMIT       :   this.m_datas.SellLimit.UseSoundModifyPrice(flag);       break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   this.m_datas.SellStopLimit.UseSoundModifyPrice(flag);   break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Return the flag of using the sound of opening/placing            |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
bool CTradeObj::UseSoundOpen(const ENUM_ORDER_TYPE action) const
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   return this.m_datas.Buy.UseSoundOpen();
      case ORDER_TYPE_BUY_STOP         :   return this.m_datas.BuyStop.UseSoundOpen();
      case ORDER_TYPE_BUY_LIMIT        :   return this.m_datas.BuyLimit.UseSoundOpen();
      case ORDER_TYPE_BUY_STOP_LIMIT   :   return this.m_datas.BuyStopLimit.UseSoundOpen();
      case ORDER_TYPE_SELL             :   return this.m_datas.Sell.UseSoundOpen();
      case ORDER_TYPE_SELL_STOP        :   return this.m_datas.SellStop.UseSoundOpen();
      case ORDER_TYPE_SELL_LIMIT       :   return this.m_datas.SellLimit.UseSoundOpen();
      case ORDER_TYPE_SELL_STOP_LIMIT  :   return this.m_datas.SellStopLimit.UseSoundOpen();
      default: return false;
     }
  }
//+------------------------------------------------------------------+
//| Return the flag of using the sound of closing/removal of         |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
bool CTradeObj::UseSoundClose(const ENUM_ORDER_TYPE action) const
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   return this.m_datas.Buy.UseSoundClose();
      case ORDER_TYPE_BUY_STOP         :   return this.m_datas.BuyStop.UseSoundClose();
      case ORDER_TYPE_BUY_LIMIT        :   return this.m_datas.BuyLimit.UseSoundClose();
      case ORDER_TYPE_BUY_STOP_LIMIT   :   return this.m_datas.BuyStopLimit.UseSoundClose();
      case ORDER_TYPE_SELL             :   return this.m_datas.Sell.UseSoundClose();
      case ORDER_TYPE_SELL_STOP        :   return this.m_datas.SellStop.UseSoundClose();
      case ORDER_TYPE_SELL_LIMIT       :   return this.m_datas.SellLimit.UseSoundClose();
      case ORDER_TYPE_SELL_STOP_LIMIT  :   return this.m_datas.SellStopLimit.UseSoundClose();
      default: return false;
     }
  }
//+------------------------------------------------------------------+
//| Return the flag of using a sound                                 |
//| of StopLoss modification for a specified position/order type     |
//+------------------------------------------------------------------+
bool CTradeObj::UseSoundModifySL(const ENUM_ORDER_TYPE action) const
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   return this.m_datas.Buy.UseSoundModifySL();
      case ORDER_TYPE_BUY_STOP         :   return this.m_datas.BuyStop.UseSoundModifySL();
      case ORDER_TYPE_BUY_LIMIT        :   return this.m_datas.BuyLimit.UseSoundModifySL();
      case ORDER_TYPE_BUY_STOP_LIMIT   :   return this.m_datas.BuyStopLimit.UseSoundModifySL();
      case ORDER_TYPE_SELL             :   return this.m_datas.Sell.UseSoundModifySL();
      case ORDER_TYPE_SELL_STOP        :   return this.m_datas.SellStop.UseSoundModifySL();
      case ORDER_TYPE_SELL_LIMIT       :   return this.m_datas.SellLimit.UseSoundModifySL();
      case ORDER_TYPE_SELL_STOP_LIMIT  :   return this.m_datas.SellStopLimit.UseSoundModifySL();
      default: return false;
     }
  }
//+------------------------------------------------------------------+
//| Return the flag of using a sound                                 |
//| of TakeProfit modification for a specified position/order type   |
//+------------------------------------------------------------------+
bool CTradeObj::UseSoundModifyTP(const ENUM_ORDER_TYPE action) const
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   return this.m_datas.Buy.UseSoundModifyTP();
      case ORDER_TYPE_BUY_STOP         :   return this.m_datas.BuyStop.UseSoundModifyTP();
      case ORDER_TYPE_BUY_LIMIT        :   return this.m_datas.BuyLimit.UseSoundModifyTP();
      case ORDER_TYPE_BUY_STOP_LIMIT   :   return this.m_datas.BuyStopLimit.UseSoundModifyTP();
      case ORDER_TYPE_SELL             :   return this.m_datas.Sell.UseSoundModifyTP();
      case ORDER_TYPE_SELL_STOP        :   return this.m_datas.SellStop.UseSoundModifyTP();
      case ORDER_TYPE_SELL_LIMIT       :   return this.m_datas.SellLimit.UseSoundModifyTP();
      case ORDER_TYPE_SELL_STOP_LIMIT  :   return this.m_datas.SellStopLimit.UseSoundModifyTP();
      default: return false;
     }
  }
//+------------------------------------------------------------------+
//| Return the flag of using a modification sound                    |
//| of the placement price for a specified order type                |
//+------------------------------------------------------------------+
bool CTradeObj::UseSoundModifyPrice(const ENUM_ORDER_TYPE action) const
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY_STOP         :   return this.m_datas.BuyStop.UseSoundModifyPrice();
      case ORDER_TYPE_BUY_LIMIT        :   return this.m_datas.BuyLimit.UseSoundModifyPrice();
      case ORDER_TYPE_BUY_STOP_LIMIT   :   return this.m_datas.BuyStopLimit.UseSoundModifyPrice();
      case ORDER_TYPE_SELL_STOP        :   return this.m_datas.SellStop.UseSoundModifyPrice();
      case ORDER_TYPE_SELL_LIMIT       :   return this.m_datas.SellLimit.UseSoundModifyPrice();
      case ORDER_TYPE_SELL_STOP_LIMIT  :   return this.m_datas.SellStopLimit.UseSoundModifyPrice();
      default: return false;
     }
  }
//+------------------------------------------------------------------+
//| Set the sound of opening/placing                                 |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
void CTradeObj::SetSoundOpen(const ENUM_ORDER_TYPE action,const string sound)
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   this.m_datas.Buy.SoundOpen(sound);             break;
      case ORDER_TYPE_BUY_STOP         :   this.m_datas.BuyStop.SoundOpen(sound);         break;
      case ORDER_TYPE_BUY_LIMIT        :   this.m_datas.BuyLimit.SoundOpen(sound);        break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   this.m_datas.BuyStopLimit.SoundOpen(sound);    break;
      case ORDER_TYPE_SELL             :   this.m_datas.Sell.SoundOpen(sound);            break;
      case ORDER_TYPE_SELL_STOP        :   this.m_datas.SellStop.SoundOpen(sound);        break;
      case ORDER_TYPE_SELL_LIMIT       :   this.m_datas.SellLimit.SoundOpen(sound);       break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   this.m_datas.SellStopLimit.SoundOpen(sound);   break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Set the sound of closing/removal of                              |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
void CTradeObj::SetSoundClose(const ENUM_ORDER_TYPE action,const string sound)
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   this.m_datas.Buy.SoundClose(sound);            break;
      case ORDER_TYPE_BUY_STOP         :   this.m_datas.BuyStop.SoundClose(sound);        break;
      case ORDER_TYPE_BUY_LIMIT        :   this.m_datas.BuyLimit.SoundClose(sound);       break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   this.m_datas.BuyStopLimit.SoundClose(sound);   break;
      case ORDER_TYPE_SELL             :   this.m_datas.Sell.SoundClose(sound);           break;
      case ORDER_TYPE_SELL_STOP        :   this.m_datas.SellStop.SoundClose(sound);       break;
      case ORDER_TYPE_SELL_LIMIT       :   this.m_datas.SellLimit.SoundClose(sound);      break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   this.m_datas.SellStopLimit.SoundClose(sound);  break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Set StopLoss modification sound of                               |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
void CTradeObj::SetSoundModifySL(const ENUM_ORDER_TYPE action,const string sound)
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   this.m_datas.Buy.SoundModifySL(sound);            break;
      case ORDER_TYPE_BUY_STOP         :   this.m_datas.BuyStop.SoundModifySL(sound);        break;
      case ORDER_TYPE_BUY_LIMIT        :   this.m_datas.BuyLimit.SoundModifySL(sound);       break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   this.m_datas.BuyStopLimit.SoundModifySL(sound);   break;
      case ORDER_TYPE_SELL             :   this.m_datas.Sell.SoundModifySL(sound);           break;
      case ORDER_TYPE_SELL_STOP        :   this.m_datas.SellStop.SoundModifySL(sound);       break;
      case ORDER_TYPE_SELL_LIMIT       :   this.m_datas.SellLimit.SoundModifySL(sound);      break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   this.m_datas.SellStopLimit.SoundModifySL(sound);  break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Set TakeProfit modification sound of                             |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
void CTradeObj::SetSoundModifyTP(const ENUM_ORDER_TYPE action,const string sound)
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   this.m_datas.Buy.SoundModifyTP(sound);            break;
      case ORDER_TYPE_BUY_STOP         :   this.m_datas.BuyStop.SoundModifyTP(sound);        break;
      case ORDER_TYPE_BUY_LIMIT        :   this.m_datas.BuyLimit.SoundModifyTP(sound);       break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   this.m_datas.BuyStopLimit.SoundModifyTP(sound);   break;
      case ORDER_TYPE_SELL             :   this.m_datas.Sell.SoundModifyTP(sound);           break;
      case ORDER_TYPE_SELL_STOP        :   this.m_datas.SellStop.SoundModifyTP(sound);       break;
      case ORDER_TYPE_SELL_LIMIT       :   this.m_datas.SellLimit.SoundModifyTP(sound);      break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   this.m_datas.SellStopLimit.SoundModifyTP(sound);  break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Set price modification sound                                     |
//| for a specified order type                                       |
//+------------------------------------------------------------------+
void CTradeObj::SetSoundModifyPrice(const ENUM_ORDER_TYPE action,const string sound)
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY_STOP         :   this.m_datas.BuyStop.SoundModifyPrice(sound);        break;
      case ORDER_TYPE_BUY_LIMIT        :   this.m_datas.BuyLimit.SoundModifyPrice(sound);       break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   this.m_datas.BuyStopLimit.SoundModifyPrice(sound);   break;
      case ORDER_TYPE_SELL_STOP        :   this.m_datas.SellStop.SoundModifyPrice(sound);       break;
      case ORDER_TYPE_SELL_LIMIT       :   this.m_datas.SellLimit.SoundModifyPrice(sound);      break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   this.m_datas.SellStopLimit.SoundModifyPrice(sound);  break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Set the error sound of opening/placing                           |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
void CTradeObj::SetSoundErrorOpen(const ENUM_ORDER_TYPE action,const string sound)
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   this.m_datas.Buy.SoundErrorOpen(sound);             break;
      case ORDER_TYPE_BUY_STOP         :   this.m_datas.BuyStop.SoundErrorOpen(sound);         break;
      case ORDER_TYPE_BUY_LIMIT        :   this.m_datas.BuyLimit.SoundErrorOpen(sound);        break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   this.m_datas.BuyStopLimit.SoundErrorOpen(sound);    break;
      case ORDER_TYPE_SELL             :   this.m_datas.Sell.SoundErrorOpen(sound);            break;
      case ORDER_TYPE_SELL_STOP        :   this.m_datas.SellStop.SoundErrorOpen(sound);        break;
      case ORDER_TYPE_SELL_LIMIT       :   this.m_datas.SellLimit.SoundErrorOpen(sound);       break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   this.m_datas.SellStopLimit.SoundErrorOpen(sound);   break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Set the error sound of closing/removal of                        |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
void CTradeObj::SetSoundErrorClose(const ENUM_ORDER_TYPE action,const string sound)
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   this.m_datas.Buy.SoundErrorClose(sound);            break;
      case ORDER_TYPE_BUY_STOP         :   this.m_datas.BuyStop.SoundErrorClose(sound);        break;
      case ORDER_TYPE_BUY_LIMIT        :   this.m_datas.BuyLimit.SoundErrorClose(sound);       break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   this.m_datas.BuyStopLimit.SoundErrorClose(sound);   break;
      case ORDER_TYPE_SELL             :   this.m_datas.Sell.SoundErrorClose(sound);           break;
      case ORDER_TYPE_SELL_STOP        :   this.m_datas.SellStop.SoundErrorClose(sound);       break;
      case ORDER_TYPE_SELL_LIMIT       :   this.m_datas.SellLimit.SoundErrorClose(sound);      break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   this.m_datas.SellStopLimit.SoundErrorClose(sound);  break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Set StopLoss modification error sound of                         |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
void CTradeObj::SetSoundErrorModifySL(const ENUM_ORDER_TYPE action,const string sound)
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   this.m_datas.Buy.SoundErrorModifySL(sound);            break;
      case ORDER_TYPE_BUY_STOP         :   this.m_datas.BuyStop.SoundErrorModifySL(sound);        break;
      case ORDER_TYPE_BUY_LIMIT        :   this.m_datas.BuyLimit.SoundErrorModifySL(sound);       break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   this.m_datas.BuyStopLimit.SoundErrorModifySL(sound);   break;
      case ORDER_TYPE_SELL             :   this.m_datas.Sell.SoundErrorModifySL(sound);           break;
      case ORDER_TYPE_SELL_STOP        :   this.m_datas.SellStop.SoundErrorModifySL(sound);       break;
      case ORDER_TYPE_SELL_LIMIT       :   this.m_datas.SellLimit.SoundErrorModifySL(sound);      break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   this.m_datas.SellStopLimit.SoundErrorModifySL(sound);  break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Set TakeProfit modification error sound of                       |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
void CTradeObj::SetSoundErrorModifyTP(const ENUM_ORDER_TYPE action,const string sound)
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   this.m_datas.Buy.SoundErrorModifyTP(sound);            break;
      case ORDER_TYPE_BUY_STOP         :   this.m_datas.BuyStop.SoundErrorModifyTP(sound);        break;
      case ORDER_TYPE_BUY_LIMIT        :   this.m_datas.BuyLimit.SoundErrorModifyTP(sound);       break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   this.m_datas.BuyStopLimit.SoundErrorModifyTP(sound);   break;
      case ORDER_TYPE_SELL             :   this.m_datas.Sell.SoundErrorModifyTP(sound);           break;
      case ORDER_TYPE_SELL_STOP        :   this.m_datas.SellStop.SoundErrorModifyTP(sound);       break;
      case ORDER_TYPE_SELL_LIMIT       :   this.m_datas.SellLimit.SoundErrorModifyTP(sound);      break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   this.m_datas.SellStopLimit.SoundErrorModifyTP(sound);  break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Set price modification error sound                               |
//| for a specified order type                                       |
//+------------------------------------------------------------------+
void CTradeObj::SetSoundErrorModifyPrice(const ENUM_ORDER_TYPE action,const string sound)
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY_STOP         :   this.m_datas.BuyStop.SoundErrorModifyPrice(sound);        break;
      case ORDER_TYPE_BUY_LIMIT        :   this.m_datas.BuyLimit.SoundErrorModifyPrice(sound);       break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   this.m_datas.BuyStopLimit.SoundErrorModifyPrice(sound);   break;
      case ORDER_TYPE_SELL_STOP        :   this.m_datas.SellStop.SoundErrorModifyPrice(sound);       break;
      case ORDER_TYPE_SELL_LIMIT       :   this.m_datas.SellLimit.SoundErrorModifyPrice(sound);      break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   this.m_datas.SellStopLimit.SoundErrorModifyPrice(sound);  break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Return the sound of opening/placing                              |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
string CTradeObj::GetSoundOpen(const ENUM_ORDER_TYPE action) const
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   return this.m_datas.Buy.SoundOpen();
      case ORDER_TYPE_BUY_STOP         :   return this.m_datas.BuyStop.SoundOpen();
      case ORDER_TYPE_BUY_LIMIT        :   return this.m_datas.BuyLimit.SoundOpen();
      case ORDER_TYPE_BUY_STOP_LIMIT   :   return this.m_datas.BuyStopLimit.SoundOpen();
      case ORDER_TYPE_SELL             :   return this.m_datas.Sell.SoundOpen();
      case ORDER_TYPE_SELL_STOP        :   return this.m_datas.SellStop.SoundOpen();
      case ORDER_TYPE_SELL_LIMIT       :   return this.m_datas.SellLimit.SoundOpen();
      case ORDER_TYPE_SELL_STOP_LIMIT  :   return this.m_datas.SellStopLimit.SoundOpen();
      default: return NULL;
     }
  }
//+------------------------------------------------------------------+
//| Return the sound of closing/removal of                           |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
string CTradeObj::GetSoundClose(const ENUM_ORDER_TYPE action) const
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   return this.m_datas.Buy.SoundClose();
      case ORDER_TYPE_BUY_STOP         :   return this.m_datas.BuyStop.SoundClose();
      case ORDER_TYPE_BUY_LIMIT        :   return this.m_datas.BuyLimit.SoundClose();
      case ORDER_TYPE_BUY_STOP_LIMIT   :   return this.m_datas.BuyStopLimit.SoundClose();
      case ORDER_TYPE_SELL             :   return this.m_datas.Sell.SoundClose();
      case ORDER_TYPE_SELL_STOP        :   return this.m_datas.SellStop.SoundClose();
      case ORDER_TYPE_SELL_LIMIT       :   return this.m_datas.SellLimit.SoundClose();
      case ORDER_TYPE_SELL_STOP_LIMIT  :   return this.m_datas.SellStopLimit.SoundClose();
      default: return NULL;
     }
  }
//+------------------------------------------------------------------+
//| Return StopLoss modification sound of                            |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
string CTradeObj::GetSoundModifySL(const ENUM_ORDER_TYPE action) const
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   return this.m_datas.Buy.SoundModifySL();
      case ORDER_TYPE_BUY_STOP         :   return this.m_datas.BuyStop.SoundModifySL();
      case ORDER_TYPE_BUY_LIMIT        :   return this.m_datas.BuyLimit.SoundModifySL();
      case ORDER_TYPE_BUY_STOP_LIMIT   :   return this.m_datas.BuyStopLimit.SoundModifySL();
      case ORDER_TYPE_SELL             :   return this.m_datas.Sell.SoundModifySL();
      case ORDER_TYPE_SELL_STOP        :   return this.m_datas.SellStop.SoundModifySL();
      case ORDER_TYPE_SELL_LIMIT       :   return this.m_datas.SellLimit.SoundModifySL();
      case ORDER_TYPE_SELL_STOP_LIMIT  :   return this.m_datas.SellStopLimit.SoundModifySL();
      default: return NULL;
     }
  }
//+------------------------------------------------------------------+
//| Return TakeProfit modification sound of                          |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
string CTradeObj::GetSoundModifyTP(const ENUM_ORDER_TYPE action) const
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   return this.m_datas.Buy.SoundModifyTP();
      case ORDER_TYPE_BUY_STOP         :   return this.m_datas.BuyStop.SoundModifyTP();
      case ORDER_TYPE_BUY_LIMIT        :   return this.m_datas.BuyLimit.SoundModifyTP();
      case ORDER_TYPE_BUY_STOP_LIMIT   :   return this.m_datas.BuyStopLimit.SoundModifyTP();
      case ORDER_TYPE_SELL             :   return this.m_datas.Sell.SoundModifyTP();
      case ORDER_TYPE_SELL_STOP        :   return this.m_datas.SellStop.SoundModifyTP();
      case ORDER_TYPE_SELL_LIMIT       :   return this.m_datas.SellLimit.SoundModifyTP();
      case ORDER_TYPE_SELL_STOP_LIMIT  :   return this.m_datas.SellStopLimit.SoundModifyTP();
      default: return NULL;
     }
  }
//+------------------------------------------------------------------+
//| Return price modification sound                                  |
//| for a specified order type                                       |
//+------------------------------------------------------------------+
string CTradeObj::GetSoundModifyPrice(const ENUM_ORDER_TYPE action) const
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY_STOP         :   return this.m_datas.BuyStop.SoundModifyPrice();
      case ORDER_TYPE_BUY_LIMIT        :   return this.m_datas.BuyLimit.SoundModifyPrice();
      case ORDER_TYPE_BUY_STOP_LIMIT   :   return this.m_datas.BuyStopLimit.SoundModifyPrice();
      case ORDER_TYPE_SELL_STOP        :   return this.m_datas.SellStop.SoundModifyPrice();
      case ORDER_TYPE_SELL_LIMIT       :   return this.m_datas.SellLimit.SoundModifyPrice();
      case ORDER_TYPE_SELL_STOP_LIMIT  :   return this.m_datas.SellStopLimit.SoundModifyPrice();
      default: return NULL;
     }
  }
//+------------------------------------------------------------------+
//| Return the error sound of opening/placing                        |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
string CTradeObj::GetSoundErrorOpen(const ENUM_ORDER_TYPE action) const
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   return this.m_datas.Buy.SoundErrorOpen();
      case ORDER_TYPE_BUY_STOP         :   return this.m_datas.BuyStop.SoundErrorOpen();
      case ORDER_TYPE_BUY_LIMIT        :   return this.m_datas.BuyLimit.SoundErrorOpen();
      case ORDER_TYPE_BUY_STOP_LIMIT   :   return this.m_datas.BuyStopLimit.SoundErrorOpen();
      case ORDER_TYPE_SELL             :   return this.m_datas.Sell.SoundErrorOpen();
      case ORDER_TYPE_SELL_STOP        :   return this.m_datas.SellStop.SoundErrorOpen();
      case ORDER_TYPE_SELL_LIMIT       :   return this.m_datas.SellLimit.SoundErrorOpen();
      case ORDER_TYPE_SELL_STOP_LIMIT  :   return this.m_datas.SellStopLimit.SoundErrorOpen();
      default: return NULL;
     }
  }
//+------------------------------------------------------------------+
//| Return the error sound of closing/removal of                     |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
string CTradeObj::GetSoundErrorClose(const ENUM_ORDER_TYPE action) const
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   return this.m_datas.Buy.SoundErrorClose();
      case ORDER_TYPE_BUY_STOP         :   return this.m_datas.BuyStop.SoundErrorClose();
      case ORDER_TYPE_BUY_LIMIT        :   return this.m_datas.BuyLimit.SoundErrorClose();
      case ORDER_TYPE_BUY_STOP_LIMIT   :   return this.m_datas.BuyStopLimit.SoundErrorClose();
      case ORDER_TYPE_SELL             :   return this.m_datas.Sell.SoundErrorClose();
      case ORDER_TYPE_SELL_STOP        :   return this.m_datas.SellStop.SoundErrorClose();
      case ORDER_TYPE_SELL_LIMIT       :   return this.m_datas.SellLimit.SoundErrorClose();
      case ORDER_TYPE_SELL_STOP_LIMIT  :   return this.m_datas.SellStopLimit.SoundErrorClose();
      default: return NULL;
     }
  }
//+------------------------------------------------------------------+
//| Return StopLoss modification error sound of                      |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
string CTradeObj::GetSoundErrorModifySL(const ENUM_ORDER_TYPE action) const
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   return this.m_datas.Buy.SoundErrorModifySL();
      case ORDER_TYPE_BUY_STOP         :   return this.m_datas.BuyStop.SoundErrorModifySL();
      case ORDER_TYPE_BUY_LIMIT        :   return this.m_datas.BuyLimit.SoundErrorModifySL();
      case ORDER_TYPE_BUY_STOP_LIMIT   :   return this.m_datas.BuyStopLimit.SoundErrorModifySL();
      case ORDER_TYPE_SELL             :   return this.m_datas.Sell.SoundErrorModifySL();
      case ORDER_TYPE_SELL_STOP        :   return this.m_datas.SellStop.SoundErrorModifySL();
      case ORDER_TYPE_SELL_LIMIT       :   return this.m_datas.SellLimit.SoundErrorModifySL();
      case ORDER_TYPE_SELL_STOP_LIMIT  :   return this.m_datas.SellStopLimit.SoundErrorModifySL();
      default: return NULL;
     }
  }
//+------------------------------------------------------------------+
//| Return TakeProfit modification error sound of                    |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
string CTradeObj::GetSoundErrorModifyTP(const ENUM_ORDER_TYPE action) const
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   return this.m_datas.Buy.SoundErrorModifyTP();
      case ORDER_TYPE_BUY_STOP         :   return this.m_datas.BuyStop.SoundErrorModifyTP();
      case ORDER_TYPE_BUY_LIMIT        :   return this.m_datas.BuyLimit.SoundErrorModifyTP();
      case ORDER_TYPE_BUY_STOP_LIMIT   :   return this.m_datas.BuyStopLimit.SoundErrorModifyTP();
      case ORDER_TYPE_SELL             :   return this.m_datas.Sell.SoundErrorModifyTP();
      case ORDER_TYPE_SELL_STOP        :   return this.m_datas.SellStop.SoundErrorModifyTP();
      case ORDER_TYPE_SELL_LIMIT       :   return this.m_datas.SellLimit.SoundErrorModifyTP();
      case ORDER_TYPE_SELL_STOP_LIMIT  :   return this.m_datas.SellStopLimit.SoundErrorModifyTP();
      default: return NULL;
     }
  }
//+------------------------------------------------------------------+
//| Return price modification error sound                            |
//| for a specified order type                                       |
//+------------------------------------------------------------------+
string CTradeObj::GetSoundErrorModifyPrice(const ENUM_ORDER_TYPE action) const
  {
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY_STOP         :   return this.m_datas.BuyStop.SoundErrorModifyPrice();
      case ORDER_TYPE_BUY_LIMIT        :   return this.m_datas.BuyLimit.SoundErrorModifyPrice();
      case ORDER_TYPE_BUY_STOP_LIMIT   :   return this.m_datas.BuyStopLimit.SoundErrorModifyPrice();
      case ORDER_TYPE_SELL_STOP        :   return this.m_datas.SellStop.SoundErrorModifyPrice();
      case ORDER_TYPE_SELL_LIMIT       :   return this.m_datas.SellLimit.SoundErrorModifyPrice();
      case ORDER_TYPE_SELL_STOP_LIMIT  :   return this.m_datas.SellStopLimit.SoundErrorModifyPrice();
      default: return NULL;
     }
  }
//+------------------------------------------------------------------+
//| Play the sound of opening/placing                                |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
void CTradeObj::PlaySoundOpen(const ENUM_ORDER_TYPE action)
  {
   if(!this.m_use_sound)
      return;
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   CMessage::PlaySound(this.m_datas.Buy.SoundOpen());            break;
      case ORDER_TYPE_BUY_STOP         :   CMessage::PlaySound(this.m_datas.BuyStop.SoundOpen());        break;
      case ORDER_TYPE_BUY_LIMIT        :   CMessage::PlaySound(this.m_datas.BuyLimit.SoundOpen());       break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   CMessage::PlaySound(this.m_datas.BuyStopLimit.SoundOpen());   break;
      case ORDER_TYPE_SELL             :   CMessage::PlaySound(this.m_datas.Sell.SoundOpen());           break;
      case ORDER_TYPE_SELL_STOP        :   CMessage::PlaySound(this.m_datas.SellStop.SoundOpen());       break;
      case ORDER_TYPE_SELL_LIMIT       :   CMessage::PlaySound(this.m_datas.SellLimit.SoundOpen());      break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   CMessage::PlaySound(this.m_datas.SellStopLimit.SoundOpen());  break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Play the sound of closing/removal of                             |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
void CTradeObj::PlaySoundClose(const ENUM_ORDER_TYPE action)
  {
   if(!this.m_use_sound)
      return;
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   CMessage::PlaySound(this.m_datas.Buy.SoundClose());           break;
      case ORDER_TYPE_BUY_STOP         :   CMessage::PlaySound(this.m_datas.BuyStop.SoundClose());       break;
      case ORDER_TYPE_BUY_LIMIT        :   CMessage::PlaySound(this.m_datas.BuyLimit.SoundClose());      break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   CMessage::PlaySound(this.m_datas.BuyStopLimit.SoundClose());  break;
      case ORDER_TYPE_SELL             :   CMessage::PlaySound(this.m_datas.Sell.SoundClose());          break;
      case ORDER_TYPE_SELL_STOP        :   CMessage::PlaySound(this.m_datas.SellStop.SoundClose());      break;
      case ORDER_TYPE_SELL_LIMIT       :   CMessage::PlaySound(this.m_datas.SellLimit.SoundClose());     break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   CMessage::PlaySound(this.m_datas.SellStopLimit.SoundClose()); break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Play StopLoss modification sound of                              |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
void CTradeObj::PlaySoundModifySL(const ENUM_ORDER_TYPE action)
  {
   if(!this.m_use_sound)
      return;
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   CMessage::PlaySound(this.m_datas.Buy.SoundModifySL());           break;
      case ORDER_TYPE_BUY_STOP         :   CMessage::PlaySound(this.m_datas.BuyStop.SoundModifySL());       break;
      case ORDER_TYPE_BUY_LIMIT        :   CMessage::PlaySound(this.m_datas.BuyLimit.SoundModifySL());      break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   CMessage::PlaySound(this.m_datas.BuyStopLimit.SoundModifySL());  break;
      case ORDER_TYPE_SELL             :   CMessage::PlaySound(this.m_datas.Sell.SoundModifySL());          break;
      case ORDER_TYPE_SELL_STOP        :   CMessage::PlaySound(this.m_datas.SellStop.SoundModifySL());      break;
      case ORDER_TYPE_SELL_LIMIT       :   CMessage::PlaySound(this.m_datas.SellLimit.SoundModifySL());     break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   CMessage::PlaySound(this.m_datas.SellStopLimit.SoundModifySL()); break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Play TakeProfit modification sound of                            |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
void CTradeObj::PlaySoundModifyTP(const ENUM_ORDER_TYPE action)
  {
   if(!this.m_use_sound)
      return;
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   CMessage::PlaySound(this.m_datas.Buy.SoundModifyTP());           break;
      case ORDER_TYPE_BUY_STOP         :   CMessage::PlaySound(this.m_datas.BuyStop.SoundModifyTP());       break;
      case ORDER_TYPE_BUY_LIMIT        :   CMessage::PlaySound(this.m_datas.BuyLimit.SoundModifyTP());      break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   CMessage::PlaySound(this.m_datas.BuyStopLimit.SoundModifyTP());  break;
      case ORDER_TYPE_SELL             :   CMessage::PlaySound(this.m_datas.Sell.SoundModifyTP());          break;
      case ORDER_TYPE_SELL_STOP        :   CMessage::PlaySound(this.m_datas.SellStop.SoundModifyTP());      break;
      case ORDER_TYPE_SELL_LIMIT       :   CMessage::PlaySound(this.m_datas.SellLimit.SoundModifyTP());     break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   CMessage::PlaySound(this.m_datas.SellStopLimit.SoundModifyTP()); break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Play price modification sound                                    |
//| for a specified order type                                       |
//+------------------------------------------------------------------+
void CTradeObj::PlaySoundModifyPrice(const ENUM_ORDER_TYPE action)
  {
   if(!this.m_use_sound)
      return;
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY_STOP         :   CMessage::PlaySound(this.m_datas.BuyStop.SoundModifyPrice());       break;
      case ORDER_TYPE_BUY_LIMIT        :   CMessage::PlaySound(this.m_datas.BuyLimit.SoundModifyPrice());      break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   CMessage::PlaySound(this.m_datas.BuyStopLimit.SoundModifyPrice());  break;
      case ORDER_TYPE_SELL_STOP        :   CMessage::PlaySound(this.m_datas.SellStop.SoundModifyPrice());      break;
      case ORDER_TYPE_SELL_LIMIT       :   CMessage::PlaySound(this.m_datas.SellLimit.SoundModifyPrice());     break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   CMessage::PlaySound(this.m_datas.SellStopLimit.SoundModifyPrice()); break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Play the error sound of opening/placing                          |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
void CTradeObj::PlaySoundErrorOpen(const ENUM_ORDER_TYPE action)
  {
   if(!this.m_use_sound)
      return;
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   CMessage::PlaySound(this.m_datas.Buy.SoundErrorOpen());             break;
      case ORDER_TYPE_BUY_STOP         :   CMessage::PlaySound(this.m_datas.BuyStop.SoundErrorOpen());         break;
      case ORDER_TYPE_BUY_LIMIT        :   CMessage::PlaySound(this.m_datas.BuyLimit.SoundErrorOpen());        break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   CMessage::PlaySound(this.m_datas.BuyStopLimit.SoundErrorOpen());    break;
      case ORDER_TYPE_SELL             :   CMessage::PlaySound(this.m_datas.Sell.SoundErrorOpen());            break;
      case ORDER_TYPE_SELL_STOP        :   CMessage::PlaySound(this.m_datas.SellStop.SoundErrorOpen());        break;
      case ORDER_TYPE_SELL_LIMIT       :   CMessage::PlaySound(this.m_datas.SellLimit.SoundErrorOpen());       break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   CMessage::PlaySound(this.m_datas.SellStopLimit.SoundErrorOpen());   break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Play the error sound of closing/removal of                       |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
void CTradeObj::PlaySoundErrorClose(const ENUM_ORDER_TYPE action)
  {
   if(!this.m_use_sound)
      return;
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   CMessage::PlaySound(this.m_datas.Buy.SoundErrorClose());            break;
      case ORDER_TYPE_BUY_STOP         :   CMessage::PlaySound(this.m_datas.BuyStop.SoundErrorClose());        break;
      case ORDER_TYPE_BUY_LIMIT        :   CMessage::PlaySound(this.m_datas.BuyLimit.SoundErrorClose());       break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   CMessage::PlaySound(this.m_datas.BuyStopLimit.SoundErrorClose());   break;
      case ORDER_TYPE_SELL             :   CMessage::PlaySound(this.m_datas.Sell.SoundErrorClose());           break;
      case ORDER_TYPE_SELL_STOP        :   CMessage::PlaySound(this.m_datas.SellStop.SoundErrorClose());       break;
      case ORDER_TYPE_SELL_LIMIT       :   CMessage::PlaySound(this.m_datas.SellLimit.SoundErrorClose());      break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   CMessage::PlaySound(this.m_datas.SellStopLimit.SoundErrorClose());  break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Play StopLoss modification error sound of                        |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
void CTradeObj::PlaySoundErrorModifySL(const ENUM_ORDER_TYPE action)
  {
   if(!this.m_use_sound)
      return;
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   CMessage::PlaySound(this.m_datas.Buy.SoundErrorModifySL());            break;
      case ORDER_TYPE_BUY_STOP         :   CMessage::PlaySound(this.m_datas.BuyStop.SoundErrorModifySL());        break;
      case ORDER_TYPE_BUY_LIMIT        :   CMessage::PlaySound(this.m_datas.BuyLimit.SoundErrorModifySL());       break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   CMessage::PlaySound(this.m_datas.BuyStopLimit.SoundErrorModifySL());   break;
      case ORDER_TYPE_SELL             :   CMessage::PlaySound(this.m_datas.Sell.SoundErrorModifySL());           break;
      case ORDER_TYPE_SELL_STOP        :   CMessage::PlaySound(this.m_datas.SellStop.SoundErrorModifySL());       break;
      case ORDER_TYPE_SELL_LIMIT       :   CMessage::PlaySound(this.m_datas.SellLimit.SoundErrorModifySL());      break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   CMessage::PlaySound(this.m_datas.SellStopLimit.SoundErrorModifySL());  break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Play TakeProfit modification error sound of                      |
//| a specified position/order type                                  |
//+------------------------------------------------------------------+
void CTradeObj::PlaySoundErrorModifyTP(const ENUM_ORDER_TYPE action)
  {
   if(!this.m_use_sound)
      return;
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY              :   CMessage::PlaySound(this.m_datas.Buy.SoundErrorModifyTP());            break;
      case ORDER_TYPE_BUY_STOP         :   CMessage::PlaySound(this.m_datas.BuyStop.SoundErrorModifyTP());        break;
      case ORDER_TYPE_BUY_LIMIT        :   CMessage::PlaySound(this.m_datas.BuyLimit.SoundErrorModifyTP());       break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   CMessage::PlaySound(this.m_datas.BuyStopLimit.SoundErrorModifyTP());   break;
      case ORDER_TYPE_SELL             :   CMessage::PlaySound(this.m_datas.Sell.SoundErrorModifyTP());           break;
      case ORDER_TYPE_SELL_STOP        :   CMessage::PlaySound(this.m_datas.SellStop.SoundErrorModifyTP());       break;
      case ORDER_TYPE_SELL_LIMIT       :   CMessage::PlaySound(this.m_datas.SellLimit.SoundErrorModifyTP());      break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   CMessage::PlaySound(this.m_datas.SellStopLimit.SoundErrorModifyTP());  break;
      default: break;
     }
  }
//+------------------------------------------------------------------+
//| Play price modification error sound                              |
//| for a specified order type                                       |
//+------------------------------------------------------------------+
void CTradeObj::PlaySoundErrorModifyPrice(const ENUM_ORDER_TYPE action)
  {
   if(!this.m_use_sound)
      return;
   int index=action;
   switch(index)
     {
      case ORDER_TYPE_BUY_STOP         :   CMessage::PlaySound(this.m_datas.BuyStop.SoundErrorModifyPrice());        break;
      case ORDER_TYPE_BUY_LIMIT        :   CMessage::PlaySound(this.m_datas.BuyLimit.SoundErrorModifyPrice());       break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :   CMessage::PlaySound(this.m_datas.BuyStopLimit.SoundErrorModifyPrice());   break;
      case ORDER_TYPE_SELL_STOP        :   CMessage::PlaySound(this.m_datas.SellStop.SoundErrorModifyPrice());       break;
      case ORDER_TYPE_SELL_LIMIT       :   CMessage::PlaySound(this.m_datas.SellLimit.SoundErrorModifyPrice());      break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :   CMessage::PlaySound(this.m_datas.SellStopLimit.SoundErrorModifyPrice());  break;
      default: break;
     }
  }
//+------------------------------------------------------------------+

Aqui tudo é o mesmo para todos os métodos, e tudo fica claro à primeira vista: ao método que tem um nome indicando o tipo de evento de negociação é transferido o tipo de ordem (quanto à posição, é transferido o tipo de ordem a mercado) cujo evento deve ser definido, retornado ou reproduzido. Em seguida, com base no tipo de posição/ordem é definido/retornado/reproduzido o som do evento de negociação especificado.

Assim fica concluído o aprimoramento do objeto básico de negociação do símbolo e passamos a criar uma classe básica de negociação.

Quero salientar que, para o funcionamento adequado da classe de negociação, vamos transferir ponteiros para as coleções que criamos anteriormente. Para fazer isso, em cada classe da coleção adicionaremos um método que retornará um ponteiro para um objeto-coleção:

Para um objeto de coleção histórica:

public:
//--- Return itself
   CHistoryCollection *GetObject(void)                                                                   { return &this;   }

Para um objeto de coleção de mercado:

public:
//--- Return itself
   CMarketCollection *GetObject(void)                                                                    { return &this;   }

Para uma coleção de símbolos:

public:
//--- Return itself
   CSymbolsCollection *GetObject(void)                                                                   { return &this;   }

A classe de negociação que criamos fornecerá acesso centralizado às operações de negociação. Ela acumulará todas as verificações antes de enviar a ordem de negociação, o processamento de respostas do servidor de negociação e a tomada de decisões sobre ações adicionais, dependendo da resposta do servidor de negociação e das configurações do comportamento dos métodos de negociação da classe.

Hoje criaremos a base da classe que continuaremos desenvolvendo mais tarde. Enquanto isso, vamos tratar da verificação de restrições para negociação por parte do programa, terminal, conta e símbolo.

Classe de negociação

Na pasta principal da biblioteca \MQL5\Include\DoEasy\ criamos a nova classe CTrading no arquivo Trading.mqh.
Como, para a classe funcionar corretamente, serão necessárias as listas das coleções que criamos previamente, e, para armazenar erros durante a verificação de permissões, precisaremos do objeto da matriz dinâmica de variáveis do tipo int ou uint da biblioteca padrão,
vamos diretamente anexá-los no arquivo da classe:

//+------------------------------------------------------------------+
//|                                                      Trading.mqh |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include <Arrays\ArrayInt.mqh>
#include "Objects\Trade\TradeObj.mqh"
#include "Collections\AccountsCollection.mqh"
#include "Collections\SymbolsCollection.mqh"
#include "Collections\MarketCollection.mqh"
#include "Collections\HistoryCollection.mqh"
//+------------------------------------------------------------------+
//| Trading class                                                    |
//+------------------------------------------------------------------+

Vejamos a listagem completa do corpo da classe e analisemos seu conteúdo:

//+------------------------------------------------------------------+
//|                                                      Trading.mqh |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include <Arrays\ArrayInt.mqh>
#include "Objects\Trade\TradeObj.mqh"
#include "Collections\AccountsCollection.mqh"
#include "Collections\SymbolsCollection.mqh"
#include "Collections\MarketCollection.mqh"
#include "Collections\HistoryCollection.mqh"
//+------------------------------------------------------------------+
//| Trading class                                                    |
//+------------------------------------------------------------------+
class CTrading
  {
private:
   CAccount            *m_account;           // Pointer to the current account object
   CSymbolsCollection  *m_symbols;           // Pointer to the symbol collection list
   CMarketCollection   *m_market;            // Pointer to the list of the collection of market orders and positions
   CHistoryCollection  *m_history;           // Pointer to the list of the collection of historical orders and deals
   CArrayInt            m_list_errors;       // Error list
   bool                 m_is_trade_enable;   // Flag enabling trading
   ENUM_LOG_LEVEL       m_log_level;         // Logging level

//--- Add the error code to the list
   bool                 AddErrorCodeToList(const int error_code);
//--- Return the symbol object by (1) position, (2) order ticket
   CSymbol             *GetSymbolObjByPosition(const ulong ticket,const string source_method);
   CSymbol             *GetSymbolObjByOrder(const ulong ticket,const string source_method);
//--- Return a symbol trading object by (1) position, (2) order ticket, (3) symbol name
   CTradeObj           *GetTradeObjByPosition(const ulong ticket,const string source_method);
   CTradeObj           *GetTradeObjByOrder(const ulong ticket,const string source_method);
   CTradeObj           *GetTradeObjBySymbol(const string symbol,const string source_method);
//--- Return the number of (1) all positions, (2) buy, (3) sell positions
   int                  PositionsTotalAll(void)          const;
   int                  PositionsTotalLong(void)         const;
   int                  PositionsTotalShort(void)        const;
//--- Return the number of (1) all pending orders, (2) buy, (3) sell pending orders
   int                  OrdersTotalAll(void)             const;
   int                  OrdersTotalLong(void)            const;
   int                  OrdersTotalShort(void)           const;
//--- Return the total volume of (1) buy, (2) sell positions
   double               PositionsTotalVolumeLong(void)   const;
   double               PositionsTotalVolumeShort(void)  const;
//--- Return the total volume of (1) buy, (2) sell orders
   double               OrdersTotalVolumeLong(void)      const;
   double               OrdersTotalVolumeShort(void)     const;
//--- Return the order direction by an operation type
   ENUM_ORDER_TYPE      DirectionByActionType(ENUM_ACTION_TYPE action) const;
//--- Check the presence of a (1) position, (2) order by ticket
   bool                 CheckPositionAvailablity(const ulong ticket,const string source_method);
   bool                 CheckOrderAvailablity(const ulong ticket,const string source_method);
//--- Set the desired sound for a trading object
   void                 SetSoundByMode(const ENUM_MODE_SET_SOUND mode,const ENUM_ORDER_TYPE action,const string sound,CTradeObj *trade_obj);
public:
//--- Constructor
                        CTrading();
//--- Get the pointers to the lists (make sure to call the method in program's OnInit() since the symbol collection list is created there)
   void                 OnInit(CAccount *account,CSymbolsCollection *symbols,CMarketCollection *market,CHistoryCollection *history)
                          {
                           this.m_account=account;
                           this.m_symbols=symbols;
                           this.m_market=market;
                           this.m_history=history;
                          }
//--- Return the error list
   CArrayInt           *GetListErrors(void)                                { return &this.m_list_errors; }
//--- Check trading limitations
   bool                 CheckTradeConstraints(const double volume,
                                              const ENUM_ACTION_TYPE action_type,
                                              const CSymbol *symbol_obj,
                                              const string source_method,
                                              double sl=0,
                                              double tp=0);
//--- Check if the funds are sufficient
   bool                 CheckMoneyFree(const ENUM_ORDER_TYPE order_type,const double volume,const double price,const CSymbol *symbol_obj,const string source_method) const;

//--- Set the following for symbol trading objects:
//--- (1) correct filling policy, (2) filling policy,
//--- (3) correct order expiration type, (4) order expiration type,
//--- (5) magic number, (6) comment, (7) slippage, (8) volume, (9) order expiration date,
//--- (10) the flag of asynchronous sending of a trading request, (11) logging level
   void                 SetCorrectTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol=NULL);
   void                 SetTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol=NULL);
   void                 SetCorrectTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol=NULL);
   void                 SetTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol=NULL);
   void                 SetMagic(const ulong magic,const string symbol=NULL);
   void                 SetComment(const string comment,const string symbol=NULL);
   void                 SetDeviation(const ulong deviation,const string symbol=NULL);
   void                 SetVolume(const double volume=0,const string symbol=NULL);
   void                 SetExpiration(const datetime expiration=0,const string symbol=NULL);
   void                 SetAsyncMode(const bool mode=false,const string symbol=NULL);
   void                 SetLogLevel(const ENUM_LOG_LEVEL log_level=LOG_LEVEL_ERROR_MSG,const string symbol=NULL);

//--- Set standard sounds (1 symbol=NULL) for trading objects of all symbols, (2 symbol!=NULL) for a symbol trading object
   void                 SetSoundsStandart(const string symbol=NULL);
//--- Set a sound for a specified order/position type and symbol
//--- 'mode' specifies an event a sound is set for
//--- (symbol=NULL) for trading objects of all symbols,
//--- (symbol!=NULL) for a trading object of a specified symbol
   void                 SetSound(const ENUM_MODE_SET_SOUND mode,const ENUM_ORDER_TYPE action,const string sound,const string symbol=NULL);

//--- Open (1) Buy, (2) Sell position
   bool                 OpenBuy(const double volume,const string symbol,const ulong magic=ULONG_MAX,double sl=0,double tp=0,const string comment=NULL);
   bool                 OpenSell(const double volume,const string symbol,const ulong magic=ULONG_MAX,double sl=0,double tp=0,const string comment=NULL);
//--- Modify a position
   bool                 ModifyPosition(const ulong ticket,const double sl=WRONG_VALUE,const double tp=WRONG_VALUE);
//--- Close a position (1) fully, (2) partially, (3) by an opposite one
   bool                 ClosePosition(const ulong ticket);
   bool                 ClosePositionPartially(const ulong ticket,const double volume);
   bool                 ClosePositionBy(const ulong ticket,const ulong ticket_by);
//--- Set (1) BuyStop, (2) BuyLimit, (3) BuyStopLimit pending order
   bool                 PlaceBuyStop(const double volume,
                                     const string symbol,
                                     const double price,
                                     const double sl=0,
                                     const double tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC);
   bool                 PlaceBuyLimit(const double volume,
                                     const string symbol,
                                     const double price,
                                     const double sl=0,
                                     const double tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC);
   bool                 PlaceBuyStopLimit(const double volume,
                                     const string symbol,
                                     const double price_stop,
                                     const double price_limit,
                                     const double sl=0,
                                     const double tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC);
//--- Set (1) SellStop, (2) SellLimit, (3) SellStopLimit pending order
   bool                 PlaceSellStop(const double volume,
                                     const string symbol,
                                     const double price,
                                     const double sl=0,
                                     const double tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC);
   bool                 PlaceSellLimit(const double volume,
                                     const string symbol,
                                     const double price,
                                     const double sl=0,
                                     const double tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC);
   bool                 PlaceSellStopLimit(const double volume,
                                     const string symbol,
                                     const double price_stop,
                                     const double price_limit,
                                     const double sl=0,
                                     const double tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC);
//--- Modify a pending order
   bool                 ModifyOrder(const ulong ticket,
                                    const double price=WRONG_VALUE,
                                    const double sl=WRONG_VALUE,
                                    const double tp=WRONG_VALUE,
                                    const double stoplimit=WRONG_VALUE,
                                    datetime expiration=WRONG_VALUE,
                                    ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE);
//--- Remove a pending order
   bool                 DeleteOrder(const ulong ticket);
  };
//+------------------------------------------------------------------+

Cada um dos métodos da classe tem um comentário explicativo. Eu espero que o conteúdo dos métodos da classe não precise de explicações adicionais.

Os métodos de negociação da classe têm quase a mesma assinatura que os métodos do objeto básico de negociação do símbolo. A única diferença está na presença do nome do símbolo, no qual é necessário realizar operações de negociação, nos métodos de abertura de posição e de colocação de ordem pendente.

Vejamos a implementação dos métodos da classe.

Como pode haver várias restrições ao mesmo tempo durante a verificação, é necessário colocar o código de cada erro na lista para exibi-los todos e, em seguida, após verificar todas as condições necessárias, é preciso exibir uma lista mostrando as restrições detectadas. Para não colocar duas vezes na lista o mesmo valor de restrição encontrado em locais diferentes do código de verificação, é necessário verificar se tal restrição existe na lista e adicioná-la apenas se não estiver presente. Assim, cada tipo de restrição estará na lista uma vez.
Para verificar o tipo de restrição na lista e adicioná-lo à lista, foi criado o método:

//| Add the error code to the list                                   |
//+------------------------------------------------------------------+
bool CTrading::AddErrorCodeToList(const int error_code)
  {
   this.m_list_errors.Sort();
   if(this.m_list_errors.Search(error_code)==WRONG_VALUE)
      return this.m_list_errors.Add(error_code);
   return false;
  }
//+------------------------------------------------------------------+

Ao método é transferido o código de erro, que é o motivo da restrição na negociação. Para a lista é definido um sinalizador de lista classificada, é verificado se tal código existe na lista, e, se a verificação for bem-sucedida, será retornado o resultado da adição do código à lista pelo método Add().
Se o código já estiver na lista, retornamos false.

Como os objetos de negociação pertencem ao símbolo (cada símbolo tem seu próprio objeto de negociação e muitos métodos de negociação funcionam com o ticket da ordem ou da posição), precisamos pelo ticket determinar o símbolo em que existe tal posição ou ordem.
Para isso, existem métodos que retornam um objeto-símbolo de acordo com o ticket da posição:

//+------------------------------------------------------------------+
//| Return a symbol object by a position ticket                      |
//+------------------------------------------------------------------+
CSymbol *CTrading::GetSymbolObjByPosition(const ulong ticket,const string source_method)
  {
   //--- Get the list of open positions
   CArrayObj *list=this.m_market.GetList();
   list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_POSITION,EQUAL);
   //--- If failed to get the list of open positions, display the message and return NULL
   if(list==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_ENG_FAILED_GET_MARKET_POS_LIST));
      return NULL;
     }
   //--- If the list is empty (no open positions), display the message and return NULL
   if(list.Total()==0)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(source_method,CMessage::Text(MSG_ENG_NO_OPEN_POSITIONS));
      return NULL;
     }
   //--- Sort the list by a ticket 
   list=CSelect::ByOrderProperty(list,ORDER_PROP_TICKET,ticket,EQUAL);
   //--- If failed to get the list of open positions, display the message and return NULL
   if(list==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_ENG_FAILED_GET_MARKET_POS_LIST));
      return NULL;
     }
   //--- If the list is empty (no required ticket), display the message and return NULL
   if(list.Total()==0)
     {
      //--- Error. No open position with #ticket
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(source_method,CMessage::Text(MSG_LIB_SYS_ERROR_NO_OPEN_POSITION_WITH_TICKET),(string)ticket);
      return NULL;
     }
   //--- Get a position with #ticket from the obtained list
   COrder *pos=list.At(0);
   //--- If failed to get the position object, display the message and return NULL
   if(pos==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_POS_OBJ));
      return NULL;
     }
   //--- Get a symbol object by name
   CSymbol * symbol_obj=this.m_symbols.GetSymbolObjByName(pos.Symbol());
   //--- If failed to get the symbol object, display the message and return NULL
   if(symbol_obj==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return NULL;
     }
   //--- Return a symbol object
   return symbol_obj;
  }
//+------------------------------------------------------------------+

e pelo ticket da ordem:

//+------------------------------------------------------------------+
//| Return a symbol object by an order ticket                        |
//+------------------------------------------------------------------+
CSymbol *CTrading::GetSymbolObjByOrder(const ulong ticket,const string source_method)
  {
   //--- Get the list of placed orders
   CArrayObj *list=this.m_market.GetList();
   list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_PENDING,EQUAL);
   //--- If failed to get the list of placed orders, display the message and return NULL
   if(list==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_ENG_FAILED_GET_PENDING_ORD_LIST));
      return NULL;
     }
   //--- If the list is empty (no placed orders), display the message and return NULL
   if(list.Total()==0)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(source_method,CMessage::Text(MSG_ENG_NO_PLACED_ORDERS));
      return NULL;
     }
   //--- Sort the list by a ticket 
   list=CSelect::ByOrderProperty(list,ORDER_PROP_TICKET,ticket,EQUAL);
   //--- If failed to get the list of placed orders, display the message and return NULL
   if(list==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_ENG_FAILED_GET_PENDING_ORD_LIST));
      return NULL;
     }
   //--- If the list is empty (no required ticket), display the message and return NULL
   if(list.Total()==0)
     {
      //--- Error. No placed order with #ticket
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(source_method,CMessage::Text(MSG_LIB_SYS_ERROR_NO_PLACED_ORDER_WITH_TICKET),(string)ticket);
      return NULL;
     }
   //--- Get an order with #ticket from the obtained list
   COrder *ord=list.At(0);
   //--- If failed to get an object order, display the message and return NULL
   if(ord==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_ORD_OBJ));
      return NULL;
     }
   //--- Get a symbol object by name
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(ord.Symbol());
   //--- If failed to get the symbol object, display the message and return NULL
   if(symbol_obj==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return NULL;
     }
   //--- Return a symbol object
   return symbol_obj;
  }
//+------------------------------------------------------------------+

Estes dois métodos são quase idênticos. A única diferença é que, no primeiro, procuramos uma posição pelo ticket, já no segundo, uma ordem. Ao método é transferido o ticket da posição ou da ordem procurada e o nome do método a partir do qual foi chamado o método em questão (para que, não importa qual erro acontecer, possamos imprimir no log o nome desse método), afinal, se imprimirmos o nome deste método auxiliar, este não fornecerá informações para determinar o local em que ocorreu a falha (precisamos indicar de qual método foi chamada a pesquisa do objeto-símbolo).

Para os métodos de classe funcionarem, é necessário obter o objeto de negociação do símbolo pelo ticekt da posição, pelo ticket da ordem ou pelo nome do símbolo:

//+------------------------------------------------------------------+
//| Return a symbol trading object by a position ticket              |
//+------------------------------------------------------------------+
CTradeObj *CTrading::GetTradeObjByPosition(const ulong ticket,const string source_method)
  {
   //--- Get a symbol object by a position ticket
   CSymbol * symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN);
   //--- If failed to get the symbol object, display the message and return NULL
   if(symbol_obj==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return NULL;
     }
   //--- Get and return the trading object from the symbol object
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   return trade_obj;
  }
//+------------------------------------------------------------------+
//| Return a symbol trading object by an order ticket                |
//+------------------------------------------------------------------+
CTradeObj *CTrading::GetTradeObjByOrder(const ulong ticket,const string source_method)
  {
   //--- Get a symbol object by an order ticket
   CSymbol * symbol_obj=this.GetSymbolObjByOrder(ticket,source_method);
   //--- If failed to get the symbol object, display the message and return NULL
   if(symbol_obj==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return NULL;
     }
   //--- Get and return the trading object from the symbol object
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   return trade_obj;
  }
//+------------------------------------------------------------------+
//| Return a symbol trading object by a symbol name                  |
//+------------------------------------------------------------------+
CTradeObj *CTrading::GetTradeObjBySymbol(const string symbol,const string source_method)
  {
   //--- Get a symbol object by its name
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
   //--- If failed to get the symbol object, display the message and return NULL
   if(symbol_obj==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_NOT_SYMBOL_ON_LIST));
      return NULL;
     }
   //--- Get and return the trading object from the symbol object
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   return trade_obj;
  }
//+------------------------------------------------------------------+

Todos os três métodos auxiliares retornam um objeto de negociação para trabalho adicional com ele. Nas listagens de métodos, todas as ações estão comentadas.

Para verificar algumas restrições e tomar decisões de negociação, precisamos saber o número de posições abertas, ordens colocadas.
Método que retorna o número de posições abertas na conta:

//+------------------------------------------------------------------+
//| Return the number of positions                                   |
//+------------------------------------------------------------------+
int CTrading::PositionsTotalAll(void) const
  {
   CArrayObj *list=this.m_market.GetList();
   list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_POSITION,EQUAL);
   return(list==NULL ? 0 : list.Total());
  }
//+------------------------------------------------------------------+

Neste caso, obtemos a lista que contém todas as posições abertas e as ordens colocadas,
filtramos a lista pelo status da ordem "posição a mercado"
.
Retornamos o número de objetos na lista resultante
. Se a lista não puder ser obtida, retornamos zero.

Método que retorna o número de posições de compra abertas na conta:

//+------------------------------------------------------------------+
//| Return the number of buy positions                               |
//+------------------------------------------------------------------+
int CTrading::PositionsTotalLong(void) const
  {
   CArrayObj *list=this.m_market.GetList();
   list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_POSITION,EQUAL);
   list=CSelect::ByOrderProperty(list,ORDER_PROP_TYPE,POSITION_TYPE_BUY,EQUAL);
   return(list==NULL ? 0 : list.Total());
  }
//+------------------------------------------------------------------+

Neste caso, obtemos a lista que contém todas as posições abertas e as ordens colocadas,
filtramos a lista pelo status da ordem "posição a mercado"
.
Filtramos a lista resultante por tipo de posição de compra
.
Retornamos o número de objetos na lista resultante. Se a lista não puder ser obtida, retornamos zero.

Método que retorna o número de posições de venda abertas na conta:

//+------------------------------------------------------------------+
//| Return the number of sell positions                              |
//+------------------------------------------------------------------+
int CTrading::PositionsTotalShort(void) const
  {
   CArrayObj *list=this.m_market.GetList();
   list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_POSITION,EQUAL);
   list=CSelect::ByOrderProperty(list,ORDER_PROP_TYPE,POSITION_TYPE_SELL,EQUAL);
   return(list==NULL ? 0 : list.Total());
  }
//+------------------------------------------------------------------+

Neste caso, obtemos a lista que contém todas as posições abertas e as ordens colocadas,
filtramos a lista pelo status da ordem "posição a mercado"
.
Filtramos a lista resultante por tipo de posição de venda
.
Retornamos o número de objetos na lista resultante. Se a lista não puder ser obtida, retornamos zero.

Métodos para obter a quantidade de ordens abertas na conta, a de ordens de venda e a de ordens de compra:

//+------------------------------------------------------------------+
//| Returns the number of pending orders                             |
//+------------------------------------------------------------------+
int CTrading::OrdersTotalAll(void) const
  {
   CArrayObj *list=this.m_market.GetList();
   list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_PENDING,EQUAL);
   return(list==NULL ? 0 : list.Total());
  }
//+------------------------------------------------------------------+
//| Return the number of buy pending orders                          |
//+------------------------------------------------------------------+
int CTrading::OrdersTotalLong(void) const
  {
   CArrayObj *list=this.m_market.GetList();
   list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_PENDING,EQUAL);
   list=CSelect::ByOrderProperty(list,ORDER_PROP_DIRECTION,ORDER_TYPE_BUY,EQUAL);
   return(list==NULL ? 0 : list.Total());
  }
//+------------------------------------------------------------------+
//| Return the number of sell pending orders                         |
//+------------------------------------------------------------------+
int CTrading::OrdersTotalShort(void) const
  {
   CArrayObj *list=this.m_market.GetList();
   list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_PENDING,EQUAL);
   list=CSelect::ByOrderProperty(list,ORDER_PROP_DIRECTION,ORDER_TYPE_SELL,EQUAL);
   return(list==NULL ? 0 : list.Total());
  }
//+------------------------------------------------------------------+

Estes três métodos auxiliares são idênticos aos três métodos discutidos acima. Só aqui filtramos a lista pelo status "ordem pendente em vigor" e pela direção do tipo de ordem de compra ou de venda.

Além disso, para determinar algumas restrições, precisamos conhecer o volume total de posições abertas e ordens pendentes colocadas.

Método que retorna o volume total de posições de compra:

//+------------------------------------------------------------------+
//| Return the total volume of buy positions                         |
//+------------------------------------------------------------------+
double CTrading::PositionsTotalVolumeLong(void) const
  {
   double vol=0;
   CArrayObj *list=this.m_market.GetList();
   list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_POSITION,EQUAL);
   list=CSelect::ByOrderProperty(list,ORDER_PROP_TYPE,POSITION_TYPE_BUY,EQUAL);
   if(list==NULL || list.Total()==0)
      return 0;
   for(int i=0;i<list.Total();i++)
     {
      COrder *obj=list.At(i);
      if(obj==NULL)
         continue;
      vol+=obj.Volume();
     }
   return vol;
  }
//+------------------------------------------------------------------+

Neste caso, obtemos a lista que contém todas as posições abertas e ordens colocadas,
filtramos a lista pelo status da ordem "posição a mercado"
.
Filtramos a lista resultante por tipo de posição de compra.
Se a lista estiver vazia , retornamos zero.
No ciclo da lista recebida, obtemos o próximo objeto-ordem e adicionamos seu volume ao valor da variável vol.
No final do ciclo, retornamos o valor recebido na variável vol.

Método que retorna o volume total de posições de vendas:

//+------------------------------------------------------------------+
//| Return the total volume of sell positions                        |
//+------------------------------------------------------------------+
double CTrading::PositionsTotalVolumeShort(void) const
  {
   double vol=0;
   CArrayObj *list=this.m_market.GetList();
   list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_POSITION,EQUAL);
   list=CSelect::ByOrderProperty(list,ORDER_PROP_TYPE,POSITION_TYPE_SELL,EQUAL);
   if(list==NULL || list.Total()==0)
      return 0;
   for(int i=0;i<list.Total();i++)
     {
      COrder *obj=list.At(i);
      if(obj==NULL)
         continue;
      vol+=obj.Volume();
     }
   return vol;
  }
//+------------------------------------------------------------------+

O método é idêntico ao anterior, exceto para filtragem por tipo de posição de venda.

Métodos que retornam a quantidade total de ordens de compra pendentes colocadas e para venda:

//+------------------------------------------------------------------+
//| Return the total volume of buy orders                            |
//+------------------------------------------------------------------+
double CTrading::OrdersTotalVolumeLong(void) const
  {
   double vol=0;
   CArrayObj *list=this.m_market.GetList();
   list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_PENDING,EQUAL);
   list=CSelect::ByOrderProperty(list,ORDER_PROP_DIRECTION,ORDER_TYPE_BUY,EQUAL);
   if(list==NULL || list.Total()==0)
      return 0;
   for(int i=0;i<list.Total();i++)
     {
      COrder *obj=list.At(i);
      if(obj==NULL)
         continue;
      vol+=obj.Volume();
     }
   return vol;
  }
//+------------------------------------------------------------------+
//| Return the total volume of sell orders                           |
//+------------------------------------------------------------------+
double CTrading::OrdersTotalVolumeShort(void) const
  {
   double vol=0;
   CArrayObj *list=this.m_market.GetList();
   list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_PENDING,EQUAL);
   list=CSelect::ByOrderProperty(list,ORDER_PROP_DIRECTION,ORDER_TYPE_SELL,EQUAL);
   if(list==NULL || list.Total()==0)
      return 0;
   for(int i=0;i<list.Total();i++)
     {
      COrder *obj=list.At(i);
      if(obj==NULL)
         continue;
      vol+=obj.Volume();
     }
   return vol;
  }
//+------------------------------------------------------------------+

Os métodos são idênticos aos métodos considerados do volume total de posições. Mas filtramos as listas de acordo com o tipo "ordem a mercado pendente" e de acordo com a direção da ordem, seja para compra ou para venda.

Método que retorna a direção da ordem pelo tipo de operação de negociação:

//+------------------------------------------------------------------+
//| Return the order direction by an operation type                  |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE CTrading::DirectionByActionType(ENUM_ACTION_TYPE action) const
  {
   if(action>ACTION_TYPE_SELL_STOP_LIMIT)
      return WRONG_VALUE;
   return ENUM_ORDER_TYPE(action%2);
  }
//+------------------------------------------------------------------+

Se o tipo de operação de negociação “fechamento pela posição contrária” ou “modificação” for passado para o método, retornamos -1, caso contrário, o restante da divisão do valor do tipo de negociação por 2, o que finalmente nos dará a direção, quer 0 (ORDER_TYPE_BUY) quer 1 (ORDER_TYPE_SELL )

Método para verificar a existência de uma posição pelo ticket:

//+------------------------------------------------------------------+
//| Check if a position is present by ticket                         |
//+------------------------------------------------------------------+
bool CTrading::CheckPositionAvailablity(const ulong ticket,const string source_method)
  {
   CArrayObj* list=this.m_market.GetList();
   list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_POSITION,EQUAL);
   list.Sort(SORT_BY_ORDER_TICKET);
   list=CSelect::ByOrderProperty(list,ORDER_PROP_TICKET,ticket,EQUAL);
   if(list.Total()==1)
      return true;
   if(this.m_log_level>LOG_LEVEL_NO_MSG)
      ::Print(source_method,CMessage::Text(MSG_LIB_SYS_ERROR_NO_OPEN_POSITION_WITH_TICKET),(string)ticket);
   return false;
  }
//+------------------------------------------------------------------+

Neste caso, ao método são transferidos o ticket da posição a ser verificada e o nome da fonte.
Recebemos uma lista contendo todas as posições abertas e ordens colocadas,
filtramos a lista pelo status da ordem "posição a mercado"
.
Definimos o sinalizador para classificar pelo ticket na lista.
Filtramos a lista resultante pelo ticket transferido pelo parâmetro de entrada.
Se a lista contiver um objeto (posição com o ticket procurado) , retornamos true.
Caso contrário, informar sobre a ausência de posição e retornamos false.

Método para verificar a existência de uma ordem pendente pelo ticket:

//+------------------------------------------------------------------+
//| Check the presence of an order by ticket                         |
//+------------------------------------------------------------------+
bool CTrading::CheckOrderAvailablity(const ulong ticket,const string source_method)
  {
   CArrayObj* list=this.m_market.GetList();
   list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_PENDING,EQUAL);
   list.Sort(SORT_BY_ORDER_TICKET);
   list=CSelect::ByOrderProperty(list,ORDER_PROP_TICKET,ticket,EQUAL);
   if(list.Total()==1)
      return true;
   if(this.m_log_level>LOG_LEVEL_NO_MSG)
      ::Print(source_method,CMessage::Text(MSG_LIB_SYS_ERROR_NO_PLACED_ORDER_WITH_TICKET),(string)ticket);
   return false;
  }
//+------------------------------------------------------------------+

O método é idêntico ao visto acima, exceto que filtramos a lista pelo status "ordem a mercado pendente".

Método que define um som para um determinado objeto de negociação :

//+------------------------------------------------------------------+
//| Set a necessary sound to a trading object                        |
//+------------------------------------------------------------------+
void CTrading::SetSoundByMode(const ENUM_MODE_SET_SOUND mode,const ENUM_ORDER_TYPE action,const string sound,CTradeObj *trade_obj)
  {
   switch(mode)
     {
      case MODE_SET_SOUND_OPEN               : trade_obj.SetSoundOpen(action,sound);               break;
      case MODE_SET_SOUND_CLOSE              : trade_obj.SetSoundClose(action,sound);              break;
      case MODE_SET_SOUND_MODIFY_SL          : trade_obj.SetSoundModifySL(action,sound);           break;
      case MODE_SET_SOUND_MODIFY_TP          : trade_obj.SetSoundModifyTP(action,sound);           break;
      case MODE_SET_SOUND_MODIFY_PRICE       : trade_obj.SetSoundModifyPrice(action,sound);        break;
      case MODE_SET_SOUND_ERROR_OPEN         : trade_obj.SetSoundErrorOpen(action,sound);          break;
      case MODE_SET_SOUND_ERROR_CLOSE        : trade_obj.SetSoundErrorClose(action,sound);         break;
      case MODE_SET_SOUND_ERROR_MODIFY_SL    : trade_obj.SetSoundErrorModifySL(action,sound);      break;
      case MODE_SET_SOUND_ERROR_MODIFY_TP    : trade_obj.SetSoundErrorModifyTP(action,sound);      break;
      case MODE_SET_SOUND_ERROR_MODIFY_PRICE : trade_obj.SetSoundErrorModifyPrice(action,sound);   break;
      default: break;
     }
  }
//+------------------------------------------------------------------+

Ao método são transferidos o modo de configuração de som (a qual evento de negociação pertencerá o som), o tipo de ordem do evento de negociação para o qual é definido o som , o nome do arquivo de som (o som que será atribuído ao evento da ordem ou da posição) e o ponteiro para o objeto de negociação no qual é necessário definir o som (para qual símbolo é definido o evento de negociação).
Dependendo do modo transferido ao método, são chamados os métodos correspondentes para definir o som do objeto de negociação.

Métodos usados para definir parâmetros de objetos de negociação de símbolos, que revisamos no último artigo, e implementados temporariamente na classe de objeto base da biblioteca CEngine:

   void                 TradingSetCorrectTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL);
   void                 TradingSetTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL);
   void                 TradingSetCorrectTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL);
   void                 TradingSetTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL);
   void                 TradingSetMagic(const ulong magic,const string symbol_name=NULL);
   void                 TradingSetComment(const string comment,const string symbol_name=NULL);
   void                 TradingSetDeviation(const ulong deviation,const string symbol_name=NULL);
   void                 TradingSetVolume(const double volume=0,const string symbol_name=NULL);
   void                 TradingSetExpiration(const datetime expiration=0,const string symbol_name=NULL);
   void                 TradingSetAsyncMode(const bool mode=false,const string symbol_name=NULL);
   void                 TradingSetLogLevel(const ENUM_LOG_LEVEL log_level=LOG_LEVEL_ERROR_MSG,const string symbol_name=NULL);

Agora estão transferidos à classe de negociação e refeitos na classe CEngine (basta chamar esses métodos localizados aqui). Já consideramos esses métodos anteriormente, pode-se ver a sua implementação nos arquivos anexados no final do artigo.

O método que define sons padrão para o objeto de negociação:

//+------------------------------------------------------------------+
//| Set standard sounds for a symbol trading object                  |
//+------------------------------------------------------------------+
void CTrading::SetSoundsStandart(const string symbol=NULL)
  {
   //--- Declare an empty symbol object
   CSymbol *symbol_obj=NULL;
   //--- If NULL is passed as a symbol name, set sounds for trading objects of all symbols
   if(symbol==NULL)
     {
      //--- Get the symbol list
      CArrayObj *list=this.m_symbols.GetList();
      if(list==NULL || list.Total()==0)
         return;
      //--- In a loop by the list of symbols
      int total=list.Total();
      for(int i=0;i<total;i++)
        {
         //--- get the next symbol object
         symbol_obj=list.At(i);
         if(symbol_obj==NULL)
            continue;
         //--- get a symbol trading object
         CTradeObj *trade_obj=symbol_obj.GetTradeObj();
         if(trade_obj==NULL)
            continue;
         //--- set standard sounds for a trading object
         trade_obj.SetSoundsStandart();
        }
     }
   //--- If a symbol name is passed
   else
     {
      //--- get a symbol trading object
      CTradeObj *trade_obj=this.GetTradeObjBySymbol(symbol,DFUN);
      if(trade_obj==NULL)
         return;
      //--- set standard sounds for a trading object
      trade_obj.SetSoundsStandart();
     }
  }
//+------------------------------------------------------------------+

Método que define um som de um determinado evento de negociação para uma ordem:

//+------------------------------------------------------------------+
//| Set a sound for a specified order/position type and symbol       |
//| 'mode' specifies an event a sound is set for                     |
//| (symbol=NULL) for trading objects of all symbols,                |
//| (symbol!=NULL) for a trading object of a specified symbol        |
//+------------------------------------------------------------------+
void CTrading::SetSound(const ENUM_MODE_SET_SOUND mode,const ENUM_ORDER_TYPE action,const string sound,const string symbol=NULL)
  {
   //--- Declare an empty symbol object
   CSymbol *symbol_obj=NULL;
   //--- If NULL is passed as a symbol name, set sounds for trading objects of all symbols
   if(symbol==NULL)
     {
      //--- Get the symbol list
      CArrayObj *list=this.m_symbols.GetList();
      if(list==NULL || list.Total()==0)
         return;
      //--- In a loop by the list of symbols
      int total=list.Total();
      for(int i=0;i<total;i++)
        {
         //--- get the next symbol object
         symbol_obj=list.At(i);
         if(symbol_obj==NULL)
            continue;
         //--- get a symbol trading object
         CTradeObj *trade_obj=symbol_obj.GetTradeObj();
         if(trade_obj==NULL)
            continue;
         //--- set a sound of a necessary event for a trading object
         this.SetSoundByMode(mode,action,sound,trade_obj);
        }
     }
   //--- If a symbol name is passed
   else
     {
      //--- get a symbol trading object
      CTradeObj *trade_obj=this.GetTradeObjBySymbol(symbol,DFUN);
      if(trade_obj==NULL)
         return;
      //--- set a sound of a necessary event for a trading object
      this.SetSoundByMode(mode,action,sound,trade_obj);
     }
  }
//+------------------------------------------------------------------+

Nos dois métodos, todas as ações são descritas nos comentários do código.

Hoje, criamos, para operações de negociação, métodos para verificação inicial de restrições na negociação. O que atribuímos a essa categoria? Aqui se verifica se há suficientes fundos para realizar uma operação de negociação. Afinal, se não houver suficiente dinheiro, não faz sentido tentar enviar nenhum pedido. A remoção deste tipo de restrição demanda tempo, uma vez que se deve esperar até os fundos disponíveis aumentarem de maneira natural. Aqui, por enquanto, a maneira mais fácil é retornar o sinalizador que indica que é impossível executar a solicitação de negociação.
Também existem outras restrições, como negociação automática restrita no terminal, negociação automática restrita para o EA em suas configurações, negociação automática restrita no lado do servidor ou de um símbolo específico, e alguns outros fatores adicionais.
Isso será tudo o que faremos hoje para a classe de negociação.

Método para verificar se há suficientes fundos para realizar uma operação de negociação:

//+------------------------------------------------------------------+
//| Check if the funds are sufficient                                |
//+------------------------------------------------------------------+
bool CTrading::CheckMoneyFree(const ENUM_ORDER_TYPE order_type,const double volume,const double price,const CSymbol *symbol_obj,const string source_method) const
  {
   ::ResetLastError();
   //--- Get the type of a market order by a trading operation type
   ENUM_ORDER_TYPE action=this.DirectionByActionType((ENUM_ACTION_TYPE)order_type);
   //--- Get the value of free funds to be left after conducting a trading operation
   double money_free=
     (
      //--- For MQL5, calculate the difference between free funds and the funds required to conduct a trading operation
      #ifdef __MQL5__  this.m_account.MarginFree()-this.m_account.MarginForAction(action,symbol_obj.Name(),volume,price)
      //--- For MQL4, use the operation result of the standard function returning the amount of funds left
      #else/*__MQL4__*/::AccountFreeMarginCheck(symbol_obj.Name(),order_type,volume) #endif 
     );
   //--- If no free funds are left, inform of that and return 'false'
   if(money_free<=0 #ifdef __MQL4__ || ::GetLastError()==134 #endif )
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
        {
         //--- create a message text
         string message=
           (
            symbol_obj.Name()+" "+::DoubleToString(volume,symbol_obj.DigitsLot())+" "+
            (
             order_type>ORDER_TYPE_SELL ? OrderTypeDescription(order_type,false,false) : 
             PositionTypeDescription(PositionTypeByOrderType(order_type))
            )+" ("+::DoubleToString(money_free,(int)this.m_account.CurrencyDigits())+")"
           );
         //--- display a journal message
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(source_method,CMessage::Text(MSG_LIB_TEXT_NOT_ENOUTH_MONEY_FOR),message);
        }
      return false;
     }
   //--- Verification successful
   return true;
  }
//+------------------------------------------------------------------+

Método para verificar restrições para a realização de operações de negociação:

//+------------------------------------------------------------------+
//| Check trading limitations                                        |
//+------------------------------------------------------------------+
bool CTrading::CheckTradeConstraints(const double volume,
                                     const ENUM_ACTION_TYPE action_type,
                                     const CSymbol *symbol_obj,
                                     const string source_method,
                                     double sl=0,
                                     double tp=0)
  {
//--- the result of conducting all checks
   bool res=true;
//--- Clear the error list (codes of found limitations)
   this.m_list_errors.Clear();
   this.m_list_errors.Sort();

//--- Check connection with the trade server (not in the test mode)
   if(!::TerminalInfoInteger(TERMINAL_CONNECTED))
     {
      if(!::MQLInfoInteger(MQL_TESTER))
        {
         //--- add the error code to the list and write 'false' to the result
         this.AddErrorCodeToList(MSG_LIB_TEXT_TERMINAL_NOT_CONNECTED);
         res &=false;
        }
     }
//--- Check if trading is enabled for an account (if there is a connection with the trade server)
   else if(!this.m_account.TradeAllowed())
     {
      //--- add the error code to the list and write 'false' to the result
      this.AddErrorCodeToList(MSG_LIB_TEXT_ACCOUNT_NOT_TRADE_ENABLED);
      res &=false;
     }
//--- Check if trading is allowed for any EAs/scripts for the current account
   if(!this.m_account.TradeExpert())
     {
      //--- add the error code to the list and write 'false' to the result
      this.AddErrorCodeToList(MSG_LIB_TEXT_ACCOUNT_EA_NOT_TRADE_ENABLED);
      res &=false;
     }
//--- Check if auto trading is allowed in the terminal.
//--- AutoTrading button (Options --> Expert Advisors --> "Allowed automated trading")
   if(!::TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
     {
      //--- add the error code to the list and write 'false' to the result
      this.AddErrorCodeToList(MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED);
      res &=false;
     }
//--- Check if auto trading is allowed for the current EA.
//--- (F7 --> Common --> Allow Automated Trading)
   if(!::MQLInfoInteger(MQL_TRADE_ALLOWED))
     {
      //--- add the error code to the list and write 'false' to the result
      this.AddErrorCodeToList(MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED);
      res &=false;
     }
//--- Check if trading is enabled on a symbol.
//--- If trading is disabled, add the error code to the list and write 'false' to the result
   if(symbol_obj.TradeMode()==SYMBOL_TRADE_MODE_DISABLED)
     {
      this.AddErrorCodeToList(MSG_SYM_TRADE_MODE_DISABLED);
      res &=false;
     }

//--- If not closing/removal/modification
   if(action_type>WRONG_VALUE && action_type<ACTION_TYPE_CLOSE_BY)
     {
      //--- In case of close-only, add the error code to the list and write 'false' to the result
      if(symbol_obj.TradeMode()==SYMBOL_TRADE_MODE_CLOSEONLY)
        {
         this.AddErrorCodeToList(MSG_SYM_TRADE_MODE_CLOSEONLY);
         res &=false;
        }
      //--- Check the minimum volume
      if(volume<symbol_obj.LotsMin())
        {
         //--- The volume in a request is less than the minimum allowed one
         //--- add the error code to the list and write 'false' to the result
         this.AddErrorCodeToList(MSG_LIB_TEXT_REQ_VOL_LESS_MIN_VOLUME);
         res &=false;
        }
      //--- Check the maximum volume
      else if(volume>symbol_obj.LotsMax())
        {
         //--- The volume in the request exceeds the maximum acceptable one
         //--- add the error code to the list and write 'false' to the result
         this.AddErrorCodeToList(MSG_LIB_TEXT_REQ_VOL_MORE_MAX_VOLUME);
         res &=false;
        }
      //--- Check the minimum volume gradation
      double step=symbol_obj.LotsStep();
      if(fabs((int)round(volume/step)*step-volume)>0.0000001)
        {
         //--- The volume in the request is not a multiple of the minimum gradation of the lot change step
         //--- add the error code to the list and write 'false' to the result
         this.AddErrorCodeToList(MSG_LIB_TEXT_INVALID_VOLUME_STEP);
         res &=false;
        }
     }

//--- When opening a position
   if(action_type>WRONG_VALUE && action_type<ACTION_TYPE_BUY_LIMIT)
     {
      //--- Check if sending market orders is allowed on a symbol.
      //--- If trading market orders is disabled, add the error code to the list and write 'false' to the result
      if(!symbol_obj.IsMarketOrdersAllowed())
        {
         this.AddErrorCodeToList(MSG_SYM_MARKET_ORDER_DISABLED);
         res &=false;
        }
     }
//--- When placing a pending order
   else if(action_type>ACTION_TYPE_SELL && action_type<ACTION_TYPE_CLOSE_BY)
     {
      //--- If there is a limitation on the number of pending orders on the account
      //--- and placing a new order exceeds the acceptable number
      if(this.m_account.LimitOrders()>0 && this.OrdersTotalAll()+1 > this.m_account.LimitOrders())
        {
         //--- The maximum number of pending orders is reached
         //--- add the error code to the list and write 'false' to the result
         this.AddErrorCodeToList(10033);
         res &=false;
        }  
      //--- Check if placing limit orders is allowed on a symbol.
      if(action_type==ACTION_TYPE_BUY_LIMIT || action_type==ACTION_TYPE_SELL_LIMIT)
        {
         //--- If it is not, add the error code to the list and write 'false' to the result
         if(!symbol_obj.IsLimitOrdersAllowed())
           {
            this.AddErrorCodeToList(MSG_SYM_LIMIT_ORDER_DISABLED);
            res &=false;
           }
        }
      //--- Check if placing stop orders is allowed on a symbol.
      else if(action_type==ACTION_TYPE_BUY_STOP || action_type==ACTION_TYPE_SELL_STOP)
        {
         //--- If placing stop orders is disabled, add the error code to the list and write 'false' to the result
         if(!symbol_obj.IsStopOrdersAllowed())
           {
            this.AddErrorCodeToList(MSG_SYM_STOP_ORDER_DISABLED);
            res &=false;
           }
        }
      //--- For MQL5, check if placing stop limit orders is allowed on a symbol.
      #ifdef __MQL5__
      else if(action_type==ACTION_TYPE_BUY_STOP_LIMIT || action_type==ACTION_TYPE_SELL_STOP_LIMIT)
        {
         //--- If it is not, add the error code to the list and write 'false' to the result
         if(!symbol_obj.IsStopLimitOrdersAllowed())
           {
            this.AddErrorCodeToList(MSG_SYM_STOP_LIMIT_ORDER_DISABLED);
            res &=false;
           }
        }
      #endif 
     }

//--- In case of opening/placing/modification
   if(action_type>WRONG_VALUE && action_type!=ACTION_TYPE_CLOSE_BY)
     {
      //--- If not modification
      if(action_type!=ACTION_TYPE_MODIFY)
        {
         //--- When buying, check if long trading is enabled on a symbol
         if(this.DirectionByActionType(action_type)==ORDER_TYPE_BUY)
           {
            //--- If only selling is allowed, add the error code to the list and write 'false' to the result
            if(symbol_obj.TradeMode()==SYMBOL_TRADE_MODE_SHORTONLY)
              {
               this.AddErrorCodeToList(MSG_SYM_TRADE_MODE_SHORTONLY);
               res &=false;
              }
            //--- If a symbol has the limitation on the total volume of an open position and pending orders in the same direction   
            if(symbol_obj.VolumeLimit()>0)
              {
               //--- (If the total volume of placed long orders and open long positions)+open volume exceed the maximum one
               if(this.OrdersTotalVolumeLong()+this.PositionsTotalVolumeLong()+volume > symbol_obj.VolumeLimit())
                 {
                  //--- Exceeded maximum allowed aggregate volume of orders and positions in one direction
                  //--- add the error code to the list and write 'false' to the result
                  this.AddErrorCodeToList(MSG_LIB_TEXT_MAX_VOLUME_LIMIT_EXCEEDED);
                  res &=false;
                 }
              }
           }
         //--- When selling, check if short trading is enabled on a symbol
         else if(this.DirectionByActionType(action_type)==ORDER_TYPE_SELL)
           {
            //--- If only buying is allowed, add the error code to the list and write 'false' to the result
            if(symbol_obj.TradeMode()==SYMBOL_TRADE_MODE_LONGONLY)
              {
               this.AddErrorCodeToList(MSG_SYM_TRADE_MODE_LONGONLY);
               res &=false;
              }
            //--- If a symbol has the limitation on the total volume of an open position and pending orders in the same direction   
            if(symbol_obj.VolumeLimit()>0)
              {
               //--- (If the total volume of placed short orders and open short positions)+open volume exceed the maximum one
               if(this.OrdersTotalVolumeShort()+this.PositionsTotalVolumeShort()+volume > symbol_obj.VolumeLimit())
                 {
                  //--- Exceeded maximum allowed aggregate volume of orders and positions in one direction
                  //--- add the error code to the list and write 'false' to the result
                  this.AddErrorCodeToList(MSG_LIB_TEXT_MAX_VOLUME_LIMIT_EXCEEDED);
                  res &=false;
                 }
              }
           }
        }
      //--- If the request features StopLoss and its placing is not allowed
      if(sl>0 && !symbol_obj.IsStopLossOrdersAllowed())
        {
         //--- add the error code to the list and write 'false' to the result
         this.AddErrorCodeToList(MSG_SYM_SL_ORDER_DISABLED);
         res &=false;
        }
      //--- If the request features TakeProfit and its placing is not allowed
      if(tp>0 && !symbol_obj.IsTakeProfitOrdersAllowed())
        {
         //--- add the error code to the list and write 'false' to the result
         this.AddErrorCodeToList(MSG_SYM_TP_ORDER_DISABLED);
         res &=false;
        }
     }

//--- When closing by an opposite position
   else if(action_type==ACTION_TYPE_CLOSE_BY)
     {
      //--- When closing by an opposite position is disabled
      if(!symbol_obj.IsCloseByOrdersAllowed())
        {
         //--- add the error code to the list and write 'false' to the result
         this.AddErrorCodeToList(MSG_LIB_TEXT_CLOSE_BY_ORDERS_DISABLED);
         res &=false;
        }
     }

//--- If there are limitations, display the header and the error list
   if(!res)
     {
      //--- Request was rejected before sending to the server due to:
      int total=this.m_list_errors.Total();
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
        {
         //--- For MQL5, first display the list header followed by the error list
         #ifdef __MQL5__
         ::Print(source_method,CMessage::Text(MSG_LIB_TEXT_REQUEST_REJECTED_DUE));
         for(int i=0;i<total;i++)
            ::Print((total>1 ? string(i+1)+". " : ""),CMessage::Text(m_list_errors.At(i)));
         //--- For MQL4, the journal messages are displayed in the reverse order: the error list is followed by the list header
         #else    
         for(int i=total-1;i>WRONG_VALUE;i--)
            ::Print((total>1 ? string(i+1)+". " : ""),CMessage::Text(m_list_errors.At(i)));
         ::Print(source_method,CMessage::Text(MSG_LIB_TEXT_REQUEST_REJECTED_DUE));
         #endif 
        }
     }
   return res;
  }
//+------------------------------------------------------------------+

O método é bastante amplo, mas monótono. Verificamos as propriedades do programa, do terminal, da conta ou do símbolo para os quais são possíveis restrições, e, se elas existirem, adicionamos o código da restrição encontrada à lista, e adicionamos false ao sinalizador de resultado. Concluídas as verificações, se a variável que armazena o resultado contiver false, exibimos o cabeçalho da lista de restrições encontradas e, num ciclo da lista de códigos de restrição, exibimos sob o cabeçalho todas as restrições, caso contrário, se a variável que armazena o resultado do teste contiver true com o qual essa variável foi inicializada, significa que todas as verificações foram aprovadas, e retornamos true.

Nesta versão da classe de negociação, nos limitaremos a isso. Além disso, ao criar métodos de tratamento de erros, todas as ações em resposta a restrições e erros serão processadas por nós nesta classe.

Métodos da classe de negociação:

//+------------------------------------------------------------------+
//| Open Buy position                                                |
//+------------------------------------------------------------------+
bool CTrading::OpenBuy(const double volume,const string symbol,const ulong magic=ULONG_MAX,double sl=0,double tp=0,const string comment=NULL)
  {
//--- Get a symbol object by a symbol name
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
   //--- If failed to get the symbol object, display the message and return 'false'
   if(symbol_obj==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- Update symbol quotes
   symbol_obj.RefreshRates();
//--- If there are trading limitations, inform of that and exit
   if(!this.CheckTradeConstraints(volume,ACTION_TYPE_BUY,symbol_obj,DFUN,sl,tp))
     {
      return false;
     }
//--- If the funds are insufficient, inform of that and exit
   if(!this.CheckMoneyFree(ORDER_TYPE_BUY,volume,symbol_obj.Ask(),symbol_obj,DFUN))
     {
      return false;
     }

//--- get a trading object from a symbol object
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Error. Failed to get trading object
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   //--- Return the result of sending a trading request in a symbol trading object
   return trade_obj.OpenPosition(POSITION_TYPE_BUY,volume,sl,tp,magic,trade_obj.GetDeviation(),comment);
  }
//+------------------------------------------------------------------+
//| Open a Sell position                                             |
//+------------------------------------------------------------------+
bool CTrading::OpenSell(const double volume,const string symbol,const ulong magic=ULONG_MAX,double sl=0,double tp=0,const string comment=NULL)
  {
//--- Get a symbol object by a symbol name
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
   //--- If failed to get the symbol object, display the message and return 'false'
   if(symbol_obj==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- Update symbol quotes
   symbol_obj.RefreshRates();
//--- If there are trading limitations, inform of that and exit
   if(!this.CheckTradeConstraints(volume,ACTION_TYPE_SELL,symbol_obj,DFUN,sl,tp))
     {
      return false;
     }
   //--- If the funds are insufficient, inform of that and exit
   if(!this.CheckMoneyFree(ORDER_TYPE_SELL,volume,symbol_obj.Bid(),symbol_obj,DFUN))
     {
      return false;
     }
//--- get a trading object from a symbol object
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Error. Failed to get trading object
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   //--- Return the result of sending a trading request in a symbol trading object
   return trade_obj.OpenPosition(POSITION_TYPE_SELL,volume,sl,tp,magic,trade_obj.GetDeviation(),comment);
  }
//+------------------------------------------------------------------+
//| Modify a position                                                |
//+------------------------------------------------------------------+
bool CTrading::ModifyPosition(const ulong ticket,const double sl=WRONG_VALUE,const double tp=WRONG_VALUE)
  {
//--- Get a symbol object by a position ticket
   CSymbol *symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN);
   //--- If failed to get the symbol object, display the message and return 'false'
   if(symbol_obj==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- Update symbol quotes
   symbol_obj.RefreshRates();
//--- If there are trading limitations, inform of that and exit
   if(!this.CheckTradeConstraints(0,ACTION_TYPE_MODIFY,symbol_obj,DFUN,sl,tp))
     {
      return false;
     }
//--- get a trading object from a symbol object
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Error. Failed to get trading object
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   //--- Return the result of sending a trading request in a symbol trading object
   return trade_obj.ModifyPosition(ticket,sl,tp);
  }
//+------------------------------------------------------------------+
//| Close a position in full                                         |
//+------------------------------------------------------------------+
bool CTrading::ClosePosition(const ulong ticket)
  {
//--- Get a symbol object by a position ticket
   CSymbol *symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN);
   //--- If failed to get the symbol object, display the message and return 'false'
   if(symbol_obj==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- Update symbol quotes
   symbol_obj.RefreshRates();
//--- If there are trading limitations, inform of that and exit
   if(!this.CheckTradeConstraints(0,WRONG_VALUE,symbol_obj,DFUN))
     {
      return false;
     }
//--- get a trading object from a symbol object
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Error. Failed to get trading object
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   //--- Return the result of sending a trading request in a symbol trading object
   return trade_obj.ClosePosition(ticket);
  }
//+------------------------------------------------------------------+
//| Close a position partially                                       |
//+------------------------------------------------------------------+
bool CTrading::ClosePositionPartially(const ulong ticket,const double volume)
  {
//--- Get a symbol object by a position ticket
   CSymbol *symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN);
   //--- If failed to get the symbol object, display the message and return 'false'
   if(symbol_obj==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- Update symbol quotes
   symbol_obj.RefreshRates();
//--- If there are trading limitations, inform of that and exit
   if(!this.CheckTradeConstraints(0,WRONG_VALUE,symbol_obj,DFUN))
     {
      return false;
     }
//--- get a trading object from a symbol object
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Error. Failed to get trading object
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   //--- Return the result of sending a trading request in a symbol trading object
   return trade_obj.ClosePositionPartially(ticket,symbol_obj.NormalizedLot(volume));
  }
//+------------------------------------------------------------------+
//| Close a position by an opposite one                              |
//+------------------------------------------------------------------+
bool CTrading::ClosePositionBy(const ulong ticket,const ulong ticket_by)
  {
//--- Get a symbol object by a position ticket
   CSymbol *symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN);
   //--- If failed to get the symbol object, display the message and return 'false'
   if(symbol_obj==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- Update symbol quotes
   symbol_obj.RefreshRates();
//--- If there are trading limitations, inform of that and exit
   if(!this.CheckTradeConstraints(0,ACTION_TYPE_CLOSE_BY,symbol_obj,DFUN))
     {
      return false;
     }
   //--- trading object of a closed position
   CTradeObj *trade_obj_pos=this.GetTradeObjByPosition(ticket,DFUN);
   if(trade_obj_pos==NULL)
     {
      //--- Error. Failed to get trading object
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   //--- check the presence of an opposite position
   if(!this.CheckPositionAvailablity(ticket_by,DFUN))
      return false;
   //--- trading object of an opposite position
   CTradeObj *trade_obj_pos_by=this.GetTradeObjByPosition(ticket_by,DFUN);
   if(trade_obj_pos_by==NULL)
     {
      //--- Error. Failed to get trading object
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   //--- If a symbol of a closed position is not equal to an opposite position's one, inform of that and exit
   if(symbol_obj.Name()!=trade_obj_pos_by.GetSymbol())
     {
      //--- Symbols of opposite positions are not equal
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_TEXT_CLOSE_BY_SYMBOLS_UNEQUAL));
      return false;
     }
   //--- Return the result of sending a trading request in a symbol trading object
   return trade_obj_pos.ClosePositionBy(ticket,ticket_by);
  }
//+------------------------------------------------------------------+
//| Place BuyStop pending order                                      |
//+------------------------------------------------------------------+
bool CTrading::PlaceBuyStop(const double volume,
                           const string symbol,
                           const double price,
                           const double sl=0,
                           const double tp=0,
                           const ulong magic=WRONG_VALUE,
                           const string comment=NULL,
                           const datetime expiration=0,
                           const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC)
  {
//--- Get a symbol object by a symbol name
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
   //--- If failed to get the symbol object, display the message and return 'false'
   if(symbol_obj==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- Update symbol quotes
   symbol_obj.RefreshRates();
//--- If there are trading limitations, inform of that and exit
   if(!this.CheckTradeConstraints(volume,ACTION_TYPE_BUY_STOP,symbol_obj,DFUN,sl,tp))
     {
      return false;
     }
   //--- get a trading object from a symbol object
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Error. Failed to get trading object
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   //--- Return the result of sending a trading request in a symbol trading object
   return trade_obj.SetOrder(ORDER_TYPE_BUY_STOP,volume,price,sl,tp,0,magic,expiration,type_time,comment);
  }
//+------------------------------------------------------------------+
//| Place BuyLimit pending order                                     |
//+------------------------------------------------------------------+
bool CTrading::PlaceBuyLimit(const double volume,
                            const string symbol,
                            const double price,
                            const double sl=0,
                            const double tp=0,
                            const ulong magic=WRONG_VALUE,
                            const string comment=NULL,
                            const datetime expiration=0,
                            const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC)
  {
//--- Get a symbol object by a symbol name
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
   //--- If failed to get the symbol object, display the message and return 'false'
   if(symbol_obj==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- Update symbol quotes
   symbol_obj.RefreshRates();
//--- If there are trading limitations, inform of that and exit
   if(!this.CheckTradeConstraints(volume,ACTION_TYPE_BUY_LIMIT,symbol_obj,DFUN,sl,tp))
     {
      return false;
     }
   //--- get a trading object from a symbol object
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Error. Failed to get trading object
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   //--- Return the result of sending a trading request in a symbol trading object
   return trade_obj.SetOrder(ORDER_TYPE_BUY_LIMIT,volume,price,sl,tp,0,magic,expiration,type_time,comment);
  }
//+------------------------------------------------------------------+
//| Place BuyStopLimit pending order                                 |
//+------------------------------------------------------------------+
bool CTrading::PlaceBuyStopLimit(const double volume,
                                const string symbol,
                                const double price_stop,
                                const double price_limit,
                                const double sl=0,
                                const double tp=0,
                                const ulong magic=WRONG_VALUE,
                                const string comment=NULL,
                                const datetime expiration=0,
                                const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC)
  {
//--- Get a symbol object by a symbol name
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
   //--- If failed to get the symbol object, display the message and return 'false'
   if(symbol_obj==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- Update symbol quotes
   symbol_obj.RefreshRates();
//--- If there are trading limitations, inform of that and exit
   if(!this.CheckTradeConstraints(volume,ACTION_TYPE_BUY_STOP_LIMIT,symbol_obj,DFUN,sl,tp))
     {
      return false;
     }
   #ifdef __MQL5__
      //--- get a trading object from a symbol object
      CTradeObj *trade_obj=symbol_obj.GetTradeObj();
      if(trade_obj==NULL)
        {
         //--- Error. Failed to get trading object
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
         return false;
        }
      //--- Return the result of sending a trading request in a symbol trading object
      return trade_obj.SetOrder(ORDER_TYPE_BUY_STOP_LIMIT,volume,price_stop,sl,tp,price_limit,magic,expiration,type_time,comment);
   //--- MQL4
   #else 
      return true;
   #endif 
  }
//+------------------------------------------------------------------+
//| Place SellStop pending order                                     |
//+------------------------------------------------------------------+
bool CTrading::PlaceSellStop(const double volume,
                            const string symbol,
                            const double price,
                            const double sl=0,
                            const double tp=0,
                            const ulong magic=WRONG_VALUE,
                            const string comment=NULL,
                            const datetime expiration=0,
                            const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC)
  {
//--- Get a symbol object by a symbol name
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
   //--- If failed to get the symbol object, display the message and return 'false'
   if(symbol_obj==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- Update symbol quotes
   symbol_obj.RefreshRates();
//--- If there are trading limitations, inform of that and exit
   if(!this.CheckTradeConstraints(volume,ACTION_TYPE_SELL_STOP,symbol_obj,DFUN,sl,tp))
     {
      return false;
     }
   //--- get a trading object from a symbol object
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Error. Failed to get trading object
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   //--- Return the result of sending a trading request in a symbol trading object
   return trade_obj.SetOrder(ORDER_TYPE_SELL_STOP,volume,price,sl,tp,0,magic,expiration,type_time,comment);
  }
//+------------------------------------------------------------------+
//| Place SellLimit pending order                                    |
//+------------------------------------------------------------------+
bool CTrading::PlaceSellLimit(const double volume,
                             const string symbol,
                             const double price,
                             const double sl=0,
                             const double tp=0,
                             const ulong magic=WRONG_VALUE,
                             const string comment=NULL,
                             const datetime expiration=0,
                             const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC)
  {
//--- Get a symbol object by a symbol name
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
   //--- If failed to get the symbol object, display the message and return 'false'
   if(symbol_obj==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- Update symbol quotes
   symbol_obj.RefreshRates();
//--- If there are trading limitations, inform of that and exit
   if(!this.CheckTradeConstraints(volume,ACTION_TYPE_SELL_LIMIT,symbol_obj,DFUN,sl,tp))
     {
      return false;
     }
   //--- get a trading object from a symbol object
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Error. Failed to get trading object
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   //--- Return the result of sending a trading request in a symbol trading object
   return trade_obj.SetOrder(ORDER_TYPE_SELL_LIMIT,volume,price,sl,tp,0,magic,expiration,type_time,comment);
  }
//+------------------------------------------------------------------+
//| Place SellStopLimit pending order                                |
//+------------------------------------------------------------------+
bool CTrading::PlaceSellStopLimit(const double volume,
                                 const string symbol,
                                 const double price_stop,
                                 const double price_limit,
                                 const double sl=0,
                                 const double tp=0,
                                 const ulong magic=WRONG_VALUE,
                                 const string comment=NULL,
                                 const datetime expiration=0,
                                 const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC)
  {
//--- Get a symbol object by a symbol name
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
   //--- If failed to get the symbol object, display the message and return 'false'
   if(symbol_obj==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- Update symbol quotes
   symbol_obj.RefreshRates();
//--- If there are trading limitations, inform of that and exit
   if(!this.CheckTradeConstraints(volume,ACTION_TYPE_SELL_STOP_LIMIT,symbol_obj,DFUN,sl,tp))
     {
      return false;
     }
   #ifdef __MQL5__
      //--- get a trading object from a symbol object
      CTradeObj *trade_obj=symbol_obj.GetTradeObj();
      if(trade_obj==NULL)
        {
         //--- Error. Failed to get trading object
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
         return false;
        }
      //--- Return the result of sending a trading request in a symbol trading object
      return trade_obj.SetOrder(ORDER_TYPE_SELL_STOP_LIMIT,volume,price_stop,sl,tp,price_limit,magic,expiration,type_time,comment);
   //--- MQL4
   #else 
      return true;
   #endif 
  }
//+------------------------------------------------------------------+
//| Modify a pending order                                           |
//+------------------------------------------------------------------+
bool CTrading::ModifyOrder(const ulong ticket,
                          const double price=WRONG_VALUE,
                          const double sl=WRONG_VALUE,
                          const double tp=WRONG_VALUE,
                          const double stoplimit=WRONG_VALUE,
                          datetime expiration=WRONG_VALUE,
                          ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE)
  {
//--- Get a symbol object by an order ticket
   CSymbol *symbol_obj=this.GetSymbolObjByOrder(ticket,DFUN);
   //--- If failed to get the symbol object, display the message and return 'false'
   if(symbol_obj==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- Update symbol quotes
   symbol_obj.RefreshRates();
//--- If there are trading limitations, inform of that and exit
   if(!this.CheckTradeConstraints(0,ACTION_TYPE_MODIFY,symbol_obj,DFUN,sl,tp))
     {
      return false;
     }
   //--- get a trading object from a symbol object
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Error. Failed to get trading object
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   //--- Return the result of sending a trading request in a symbol trading object
   return trade_obj.ModifyOrder(ticket,price,sl,tp,stoplimit,expiration,type_time);
  }
//+------------------------------------------------------------------+
//| Remove a pending order                                           |
//+------------------------------------------------------------------+
bool CTrading::DeleteOrder(const ulong ticket)
  {
//--- Get a symbol object by an order ticket
   CSymbol *symbol_obj=this.GetSymbolObjByOrder(ticket,DFUN);
   //--- If failed to get the symbol object, display the message and return 'false'
   if(symbol_obj==NULL)
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- Update symbol quotes
   symbol_obj.RefreshRates();
//--- If there are trading limitations, inform of that and exit
   if(!this.CheckTradeConstraints(0,WRONG_VALUE,symbol_obj,DFUN))
     {
      return false;
     }
   //--- get a trading object from a symbol object
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Error. Failed to get trading object
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   //--- Return the result of sending a trading request in a symbol trading object
   return trade_obj.DeleteOrder(ticket);
  }
//+------------------------------------------------------------------+

Num artigo anterior ao criar um objeto básico de negociação, vimos métodos de negociação diretamente (envio solicitações de negociação para o servidor). Aqui, métodos com uma assinatura semelhante são usados para transferir os parâmetros da solicitação de negociação, para verificar as restrições de negociação, que examinamos acima, e para chamar o método correspondente do objeto básico de negociação do símbolo. O resultado do método chamado é retornado ao programa.

Até agora,nesta fase, essas são todas as verificações realizadas antes do envio da solicitação de negociação. Mais tarde, certamente, nós os expandiremos. Afinal, precisamos verificar e processar se são corretos os parâmetros da solicitação de negociação. Agora entende-se que todos os parâmetros já estão corretos.

A classe de negociação na sua implementação atual com a funcionalidade planejada está pronta.
Agora precisamos acessar o objeto da biblioteca base CEngine, e através dele já trabalhar com os métodos de negociação da classe.

Abrimos o arquivo \MQL5\Include\DoEasy\Engine.mqh e fazemos as alterações necessárias:

Primeiro, anexamos a ele o arquivo da classe:

//+------------------------------------------------------------------+
//|                                                       Engine.mqh |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                             https://mql5.com/pt/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://mql5.com/pt/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "Services\TimerCounter.mqh"
#include "Collections\HistoryCollection.mqh"
#include "Collections\MarketCollection.mqh"
#include "Collections\EventsCollection.mqh"
#include "Collections\AccountsCollection.mqh"
#include "Collections\SymbolsCollection.mqh"
#include "Collections\ResourceCollection.mqh"
#include "Trading.mqh"
//+------------------------------------------------------------------+

E na seção privada da classe declaramos o objeto da classe de negociação:

//+------------------------------------------------------------------+
//| Library basis class                                              |
//+------------------------------------------------------------------+
class CEngine
  {
private:
   CHistoryCollection   m_history;                       // Collection of historical orders and deals
   CMarketCollection    m_market;                        // Collection of market orders and deals
   CEventsCollection    m_events;                        // Event collection
   CAccountsCollection  m_accounts;                      // Account collection
   CSymbolsCollection   m_symbols;                       // Symbol collection
   CResourceCollection  m_resource;                      // Resource list
   CTrading             m_trading;                       // Trading class object
   CArrayObj            m_list_counters;                 // List of timer counters
   int                  m_global_error;                  // Global error code
   bool                 m_first_start;                   // First launch flag
   bool                 m_is_hedge;                      // Hedge account flag
   bool                 m_is_tester;                     // Flag of working in the tester
   bool                 m_is_market_trade_event;         // Account trading event flag
   bool                 m_is_history_trade_event;        // Account history trading event flag
   bool                 m_is_account_event;              // Account change event flag
   bool                 m_is_symbol_event;               // Symbol change event flag
   ENUM_TRADE_EVENT     m_last_trade_event;              // Last account trading event
   int                  m_last_account_event;            // Last event in the account properties
   int                  m_last_symbol_event;             // Last event in the symbol properties
//--- Return the counter index by id

Métodos

//--- Set the following for the trading classes:
//--- (1) correct filling policy, (2) filling policy,
//--- (3) correct order expiration type, (4) order expiration type,
//--- (5) magic number, (6) comment, (7) slippage, (8) volume, (9) order expiration date,
//--- (10) the flag of asynchronous sending of a trading request, (11) logging level
   void                 SetTradeCorrectTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL);
   void                 SetTradeTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL);
   void                 SetTradeCorrectTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL);
   void                 SetTradeTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL);
   void                 SetTradeMagic(const ulong magic,const string symbol_name=NULL);
   void                 SetTradeComment(const string comment,const string symbol_name=NULL);
   void                 SetTradeDeviation(const ulong deviation,const string symbol_name=NULL);
   void                 SetTradeVolume(const double volume=0,const string symbol_name=NULL);
   void                 SetTradeExpiration(const datetime expiration=0,const string symbol_name=NULL);
   void                 SetTradeAsyncMode(const bool mode=false,const string symbol_name=NULL);
   void                 SetTradeLogLevel(const ENUM_LOG_LEVEL log_level=LOG_LEVEL_ERROR_MSG,const string symbol_name=NULL);

renomeamos para

//--- Set the following for the trading classes:
//--- (1) correct filling policy, (2) filling policy,
//--- (3) correct order expiration type, (4) order expiration type,
//--- (5) magic number, (6) comment, (7) slippage, (8) volume, (9) order expiration date,
//--- (10) the flag of asynchronous sending of a trading request, (11) logging level
   void                 TradingSetCorrectTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL);
   void                 TradingSetTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL);
   void                 TradingSetCorrectTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL);
   void                 TradingSetTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL);
   void                 TradingSetMagic(const ulong magic,const string symbol_name=NULL);
   void                 TradingSetComment(const string comment,const string symbol_name=NULL);
   void                 TradingSetDeviation(const ulong deviation,const string symbol_name=NULL);
   void                 TradingSetVolume(const double volume=0,const string symbol_name=NULL);
   void                 TradingSetExpiration(const datetime expiration=0,const string symbol_name=NULL);
   void                 TradingSetAsyncMode(const bool mode=false,const string symbol_name=NULL);
   void                 TradingSetLogLevel(const ENUM_LOG_LEVEL log_level=LOG_LEVEL_ERROR_MSG,const string symbol_name=NULL);

Bem, apenas para que o nome deles indique que pertença à classe de negociação.

À seção pública da classe adicionamos os métodos para configurar sons padrão, sons para o tipo especificado de posição/ordem e evento de negociação, e o método que envia à classe de negociação os ponteiros para as listas de coleções necessárias para funcionar bem, além disso, declaramos o método para reproduzir som pela sua descrição:

//--- Set standard sounds (symbol==NULL) for a symbol trading object, (symbol!=NULL) for trading objects of all symbols
   void                 SetSoundsStandart(const string symbol=NULL)
                          {
                           this.m_trading.SetSoundsStandart(symbol);
                          }

//--- Set a sound for a specified order/position type and symbol. 'mode' specifies an event a sound is set for
//--- (symbol=NULL) for trading objects of all symbols, (symbol!=NULL) for a trading object of a specified symbol
   void                 SetSound(const ENUM_MODE_SET_SOUND mode,const ENUM_ORDER_TYPE action,const string sound,const string symbol=NULL)
                          {
                           this.m_trading.SetSound(mode,action,sound,symbol);
                          }
//--- Play a sound by its description
   bool                 PlaySoundByDescription(const string sound_description);

//--- Pass the pointers to all the necessary collections to the trading class
   void                 TradingOnInit(void)
                          {
                           this.m_trading.OnInit(this.GetAccountCurrent(),m_symbols.GetObject(),m_market.GetObject(),m_history.GetObject());
                          }

Os três métodos simplesmente chamam os métodos da classe de negociação com o mesmo nome, enquanto o método de reprodução sonora de acordo com sua descrição é considerado abaixo:

//+------------------------------------------------------------------+
//| Play a sound by its description                                  |
//+------------------------------------------------------------------+
bool CEngine::PlaySoundByDescription(const string sound_description)
  {
   string file_name=NULL;
   //--- Get the list of resources
   CArrayObj* list=this.GetListResource();
   if(list==NULL)
      return false;
   //--- Get an index of a resource object by its description
   int index=this.m_resource.GetIndexResObjByDescription(sound_description);
   //--- If a resource object with a specified description is found in the list
   if(index>WRONG_VALUE)
     {
      //--- Get a resource object by its index in the list
      CResObj *res_obj=list.At(index);
      if(res_obj==NULL)
         return false;
      //--- Get a resource object file name
      file_name=res_obj.FileName();
     }
   //--- If there is no resource object with a specified description in the list, attempt to play the file by the name written in its description
   //--- To do this, make sure that either a standard audio file (macro substitution of its name),
   //--- or a name of a new *.wav audio file is passed as a description
   else if(::StringFind(sound_description,"SND_")==0 || StringSubstr(sound_description,StringLen(sound_description)-4)==".wav")
      file_name=sound_description;
   //--- Return the file playing result
   return(file_name!=NULL ? CMessage::PlaySound(file_name) : false);
  }
//+------------------------------------------------------------------+

Anteriormente criamos objetos-recursos em que podíamos armazenar arquivos de som e arquivos de imagem. Para cada recurso, tornamos possível adicionar uma descrição, facilitando indicar qual arquivo de som precisamos reproduzir. Por exemplo, é muito mais fácil lembrar a descrição do arquivo do que o nome. Se o nome do arquivo for "informe", como sound_01.wav, podemos especificar qualquer descrição para ele, por exemplo, "o som de abrir a posição de compra no EURUSD".
Este método apenas permite especificar nos seus parâmetros a descrição de arquivo necessária. O método encontra o objeto-recurso com tal descrição e reproduz um som. Opcionalmente, o método tem a capacidade de reproduzir sons padrão a partir da substituição macro dos seus nomes (os que criamos em Defines.mqh), bem como de qualquer arquivo de som desconhecido, basta transferir seu nome como descrição. O principal é que esse arquivo está na área restrita do terminal, possui a extensão wav e o nome possui o caminho correto para ele.

Os métodos de negociação que colocamos temporariamente na classe CEngine no último artigo, bem como os métodos que definem os parâmetros do objeto de negociação e também temporariamente colocados no CEngine, passaram por alterações, todos esses métodos, sua implementação, foram transferidos para a classe de negociação,
enquanto a partir dos métodos da classe CEngine, são simplesmente chamados os métodos correspondentes da classe de negociação:

//+------------------------------------------------------------------+
//| Open Buy position                                                |
//+------------------------------------------------------------------+
bool CEngine::OpenBuy(const double volume,const string symbol,const ulong magic=ULONG_MAX,double sl=0,double tp=0,const string comment=NULL)
  {
   return this.m_trading.OpenBuy(volume,symbol,magic,sl,tp,comment);
  }
//+------------------------------------------------------------------+
//| Open a Sell position                                             |
//+------------------------------------------------------------------+
bool CEngine::OpenSell(const double volume,const string symbol,const ulong magic=ULONG_MAX,double sl=0,double tp=0,const string comment=NULL)
  {
   return this.m_trading.OpenSell(volume,symbol,magic,sl,tp,comment);
  }
//+------------------------------------------------------------------+
//| Modify a position                                                |
//+------------------------------------------------------------------+
bool CEngine::ModifyPosition(const ulong ticket,const double sl=WRONG_VALUE,const double tp=WRONG_VALUE)
  {
   return this.m_trading.ModifyPosition(ticket,sl,tp);
  }
//+------------------------------------------------------------------+
//| Close a position in full                                         |
//+------------------------------------------------------------------+
bool CEngine::ClosePosition(const ulong ticket)
  {
   return this.m_trading.ClosePosition(ticket);
  }
//+------------------------------------------------------------------+
//| Close a position partially                                       |
//+------------------------------------------------------------------+
bool CEngine::ClosePositionPartially(const ulong ticket,const double volume)
  {
   return this.m_trading.ClosePositionPartially(ticket,volume);
  }

//+------------------------------------------------------------------+
//| Close a position by an opposite one                              |
//+------------------------------------------------------------------+
bool CEngine::ClosePositionBy(const ulong ticket,const ulong ticket_by)
  {
   return this.m_trading.ClosePositionBy(ticket,ticket_by);
  }
//+------------------------------------------------------------------+
//| Place BuyStop pending order                                      |
//+------------------------------------------------------------------+
bool CEngine::PlaceBuyStop(const double volume,
                           const string symbol,
                           const double price,
                           const double sl=0,
                           const double tp=0,
                           const ulong magic=WRONG_VALUE,
                           const string comment=NULL,
                           const datetime expiration=0,
                           const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC)
  {
   return this.m_trading.PlaceBuyStop(volume,symbol,price,sl,tp,magic,comment,expiration,type_time);
  }
//+------------------------------------------------------------------+
//| Place BuyLimit pending order                                     |
//+------------------------------------------------------------------+
bool CEngine::PlaceBuyLimit(const double volume,
                            const string symbol,
                            const double price,
                            const double sl=0,
                            const double tp=0,
                            const ulong magic=WRONG_VALUE,
                            const string comment=NULL,
                            const datetime expiration=0,
                            const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC)
  {
   return this.m_trading.PlaceBuyLimit(volume,symbol,price,sl,tp,magic,comment,expiration,type_time);
  }
//+------------------------------------------------------------------+
//| Place BuyStopLimit pending order                                 |
//+------------------------------------------------------------------+
bool CEngine::PlaceBuyStopLimit(const double volume,
                                const string symbol,
                                const double price_stop,
                                const double price_limit,
                                const double sl=0,
                                const double tp=0,
                                const ulong magic=WRONG_VALUE,
                                const string comment=NULL,
                                const datetime expiration=0,
                                const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC)
  {
   return this.m_trading.PlaceBuyStopLimit(volume,symbol,price_stop,price_limit,sl,tp,magic,comment,expiration,type_time);
  }
//+------------------------------------------------------------------+
//| Place SellStop pending order                                     |
//+------------------------------------------------------------------+
bool CEngine::PlaceSellStop(const double volume,
                            const string symbol,
                            const double price,
                            const double sl=0,
                            const double tp=0,
                            const ulong magic=WRONG_VALUE,
                            const string comment=NULL,
                            const datetime expiration=0,
                            const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC)
  {
   return this.m_trading.PlaceSellStop(volume,symbol,price,sl,tp,magic,comment,expiration,type_time);
  }
//+------------------------------------------------------------------+
//| Place SellLimit pending order                                    |
//+------------------------------------------------------------------+
bool CEngine::PlaceSellLimit(const double volume,
                             const string symbol,
                             const double price,
                             const double sl=0,
                             const double tp=0,
                             const ulong magic=WRONG_VALUE,
                             const string comment=NULL,
                             const datetime expiration=0,
                             const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC)
  {
   return this.m_trading.PlaceSellLimit(volume,symbol,price,sl,tp,magic,comment,expiration,type_time);
  }
//+------------------------------------------------------------------+
//| Place SellStopLimit pending order                                |
//+------------------------------------------------------------------+
bool CEngine::PlaceSellStopLimit(const double volume,
                                 const string symbol,
                                 const double price_stop,
                                 const double price_limit,
                                 const double sl=0,
                                 const double tp=0,
                                 const ulong magic=WRONG_VALUE,
                                 const string comment=NULL,
                                 const datetime expiration=0,
                                 const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC)
  {
   return this.m_trading.PlaceSellStopLimit(volume,symbol,price_stop,price_limit,sl,tp,magic,comment,expiration,type_time);
  }
//+------------------------------------------------------------------+
//| Modify a pending order                                           |
//+------------------------------------------------------------------+
bool CEngine::ModifyOrder(const ulong ticket,
                          const double price=WRONG_VALUE,
                          const double sl=WRONG_VALUE,
                          const double tp=WRONG_VALUE,
                          const double stoplimit=WRONG_VALUE,
                          datetime expiration=WRONG_VALUE,
                          ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE)
  {
   return this.m_trading.ModifyOrder(ticket,price,sl,tp,stoplimit,expiration,type_time);
  }
//+------------------------------------------------------------------+
//| Remove a pending order                                           |
//+------------------------------------------------------------------+
bool CEngine::DeleteOrder(const ulong ticket)
  {
   return this.m_trading.DeleteOrder(ticket);
  }
//+------------------------------------------------------------------+
//| Set the valid filling policy                                     |
//| for trading objects of all symbols                               |
//+------------------------------------------------------------------+
void CEngine::TradingSetCorrectTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL)
  {
   this.m_trading.SetCorrectTypeFilling(type,symbol_name);
  }
//+------------------------------------------------------------------+
//| Set the filling policy                                           |
//| for trading objects of all symbols                               |
//+------------------------------------------------------------------+
void CEngine::TradingSetTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL)
  {
   this.m_trading.SetTypeFilling(type,symbol_name);
  }
//+------------------------------------------------------------------+
//| Set a correct order expiration type                              |
//| for trading objects of all symbols                               |
//+------------------------------------------------------------------+
void CEngine::TradingSetCorrectTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL)
  {
   this.m_trading.SetCorrectTypeExpiration(type,symbol_name);
  }
//+------------------------------------------------------------------+
//| Set an order expiration type                                     |
//| for trading objects of all symbols                               |
//+------------------------------------------------------------------+
void CEngine::TradingSetTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL)
  {
   this.m_trading.SetTypeExpiration(type,symbol_name);
  }
//+------------------------------------------------------------------+
//| Set a magic number for trading objects of all symbols            |
//+------------------------------------------------------------------+
void CEngine::TradingSetMagic(const ulong magic,const string symbol_name=NULL)
  {
   this.m_trading.SetMagic(magic,symbol_name);
  }
//+------------------------------------------------------------------+
//| Set a comment for trading objects of all symbols                 |
//+------------------------------------------------------------------+
void CEngine::TradingSetComment(const string comment,const string symbol_name=NULL)
  {
   this.m_trading.SetComment(comment,symbol_name);
  }

//+------------------------------------------------------------------+
//| Set a slippage                                                   |
//| for trading objects of all symbols                               |
//+------------------------------------------------------------------+
void CEngine::TradingSetDeviation(const ulong deviation,const string symbol_name=NULL)
  {
   this.m_trading.SetDeviation(deviation,symbol_name);
  }
//+------------------------------------------------------------------+
//| Set a volume for trading objects of all symbols                  |
//+------------------------------------------------------------------+
void CEngine::TradingSetVolume(const double volume=0,const string symbol_name=NULL)
  {
   this.m_trading.SetVolume(volume,symbol_name);
  }
//+------------------------------------------------------------------+
//| Set an order expiration date                                     |
//| for trading objects of all symbols                               |
//+------------------------------------------------------------------+
void CEngine::TradingSetExpiration(const datetime expiration=0,const string symbol_name=NULL)
  {
   this.m_trading.SetExpiration(expiration,symbol_name);
  }
//+------------------------------------------------------------------+
//| Set the flag of asynchronous sending of trading requests         |
//| for trading objects of all symbols                               |
//+------------------------------------------------------------------+
void CEngine::TradingSetAsyncMode(const bool mode=false,const string symbol_name=NULL)
  {
   this.m_trading.SetAsyncMode(mode,symbol_name);
  }
//+------------------------------------------------------------------+
//| Set a logging level of trading requests                          |
//| for trading objects of all symbols                               |
//+------------------------------------------------------------------+
void CEngine::TradingSetLogLevel(const ENUM_LOG_LEVEL log_level=LOG_LEVEL_ERROR_MSG,const string symbol_name=NULL)
  {
   this.m_trading.SetLogLevel(log_level,symbol_name);
  }
//+------------------------------------------------------------------+

Assim fica concluído o aprimoramento da classe CEngine e temos que verificar como funciona agora tudo isso.

Teste

Para testar, pegamos o EA do artigo anterior e o salvamos numa nova pasta \MQL5\Experts\TestDoEasy\Part22\ usando o novo nome TestDoEasyPart22.mq5.

No nosso último EA, no manipulador OnInit(), no log eram exibidas muitas informações de verificação de texto. Agora, como não precisamos delas, removemos todas as Print() desnecessárias e adicionamos a inicialização da classe de negociação e a verificação de reprodução de som padrão pela substituição de macros e a de som personalizado pela sua descrição:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Calling the function displays the list of enumeration constants in the journal 
//--- (the list is set in the strings 22 and 25 of the DELib.mqh file) for checking the constants validity
   //EnumNumbersTest();
   
//--- Set EA global variables
   prefix=MQLInfoString(MQL_PROGRAM_NAME)+"_";
   for(int i=0;i<TOTAL_BUTT;i++)
     {
      butt_data[i].name=prefix+EnumToString((ENUM_BUTTONS)i);
      butt_data[i].text=EnumToButtText((ENUM_BUTTONS)i);
     }
   lot=NormalizeLot(Symbol(),fmax(InpLots,MinimumLots(Symbol())*2.0));
   magic_number=InpMagic;
   stoploss=InpStopLoss;
   takeprofit=InpTakeProfit;
   distance_pending=InpDistance;
   distance_stoplimit=InpDistanceSL;
   slippage=InpSlippage;
   trailing_stop=InpTrailingStop*Point();
   trailing_step=InpTrailingStep*Point();
   trailing_start=InpTrailingStart;
   stoploss_to_modify=InpStopLossModify;
   takeprofit_to_modify=InpTakeProfitModify;

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

//--- Set the type of the used symbol list in the symbol collection
   engine.SetUsedSymbols(array_used_symbols);
//--- Displaying the selected mode of working with the symbol object collection
   Print(engine.ModeSymbolsListDescription(),TextByLanguage(". Number of used symbols: ",". Number of symbols used: "),engine.GetSymbolsCollectionTotal());
   
//--- Create resource text files
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_01",TextByLanguage("Звук упавшей монетки 1","Sound of falling coin 1"),sound_array_coin_01);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_02",TextByLanguage("Звук упавших монеток","Falling coins"),sound_array_coin_02);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_03",TextByLanguage("Звук монеток","Coins"),sound_array_coin_03);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_04",TextByLanguage("Звук упавшей монетки 2","Sound of falling coin 2"),sound_array_coin_04);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_click_01",TextByLanguage("Звук щелчка по кнопке 1","Click on button sound 1"),sound_array_click_01);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_click_02",TextByLanguage("Звук щелчка по кнопке 2","Click on button sound 1"),sound_array_click_02);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_click_03",TextByLanguage("Звук щелчка по кнопке 3","Click on button sound 1"),sound_array_click_03);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_cash_machine_01",TextByLanguage("Звук кассового аппарата","Sound of cash machine"),sound_array_cash_machine_01);
   engine.CreateFile(FILE_TYPE_BMP,"img_array_spot_green",TextByLanguage("Изображение \"Зелёный светодиод\"","Image \"Green Spot lamp\""),img_array_spot_green);
   engine.CreateFile(FILE_TYPE_BMP,"img_array_spot_red",TextByLanguage("Изображение \"Красный светодиод\"","Image \"Red Spot lamp\""),img_array_spot_red);

//--- Pass all existing collections to the trading class
   engine.TradingOnInit();
//--- Set synchronous passing of orders for all used symbols
   engine.TradingSetAsyncMode();
//--- Set standard sounds for trading objects of all used symbols
   engine.SetSoundsStandart();
//--- Check playing a standard sound by macro substitution and a custom sound by description
   engine.PlaySoundByDescription(SND_OK);
   Sleep(600);
   engine.PlaySoundByDescription(TextByLanguage("Звук упавшей монетки 2","Falling coin 2"));
      
//--- Set controlled values for symbols
   //--- Get the list of all collection symbols
   CArrayObj *list=engine.GetListAllUsedSymbols();
   if(list!=NULL && list.Total()!=0)
     {
      //--- In a loop by the list, set the necessary values for tracked symbol properties
      //--- By default, the LONG_MAX value is set to all properties, which means "Do not track this property" 
      //--- It can be enabled or disabled (by setting the value less than LONG_MAX or vice versa - set the LONG_MAX value) at any time and anywhere in the program
      for(int i=0;i<list.Total();i++)
        {
         CSymbol* symbol=list.At(i);
         if(symbol==NULL)
            continue;
         //--- Set control of the symbol price increase by 100 points
         symbol.SetControlBidInc(100*symbol.Point());
         //--- Set control of the symbol price decrease by 100 points
         symbol.SetControlBidDec(100*symbol.Point());
         //--- Set control of the symbol spread increase by 40 points
         symbol.SetControlSpreadInc(40);
         //--- Set control of the symbol spread decrease by 40 points
         symbol.SetControlSpreadDec(40);
         //--- Set control of the current spread by the value of 40 points
         symbol.SetControlSpreadLevel(40);
        }
     }
//--- Set controlled values for the current account
   CAccount* account=engine.GetAccountCurrent();
   if(account!=NULL)
     {
      //--- Set control of the profit increase to 10
      account.SetControlledValueINC(ACCOUNT_PROP_PROFIT,10.0);
      //--- Set control of the funds increase to 15
      account.SetControlledValueINC(ACCOUNT_PROP_EQUITY,15.0);
      //--- Set profit control level to 20
      account.SetControlledValueLEVEL(ACCOUNT_PROP_PROFIT,20.0);
     }

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

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

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

Após compilar e iniciar o Expert Advisor, primeiro será reproduzido o som padrão “ok.wav” e após 1/6 segundos o personalizado tocará com a descrição “Sound of the drop coin 2”.

Para testar o trabalho dos métodos de verificação de restrições de negociação, é preciso criá-las artificialmente.
Por exemplo:

  1. desativamos a Internet (imitar uma quebra na comunicação com o servidor de negociação),
  2. nas configurações do EA, o proibiremos de negociar (pressionamos F7 e, na janela de configurações do EA aberto na guia "Geral", desmarcamos a caixa "Permitir que o EA negocie"),
  3. desabilitamos no terminal a negociação automática (pressionamos o botão "Autotrading")

E tentamos clicar no botão para abrir uma posição no painel de negociação do EA. Como resultado, obtemos uma entrada no log:

2019.09.26 15:07:55.582 CTrading::OpenBuy: The request was rejected before being sent to the server due to:
2019.09.26 15:07:55.582 1. There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled)
2019.09.26 15:07:55.582 2. No connection to the trading server
2019.09.26 15:07:55.582 3. EA does not have permission to conduct trading operations (F7 --> Common --> "Allow Automatic Trading")

Removemos as restrições uma a uma.

Ativamos a Internet e ao tentar abrir uma posição, obtemos:

2019.09.26 15:10:36.766 CTrading::OpenBuy: The request was rejected before being sent to the server due to:
2019.09.26 15:10:36.766 1. There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled)
2019.09.26 15:10:36.766 2. EA does not have permission to conduct trading operations (F7 --> Common --> "Allow Automatic Trading")

Ativamos no terminal a negociação automática clicando no botão Autotrading e, ao tentar abrir uma posição, obtemos

2019.09.26 15:13:03.424 CTrading::OpenBuy: The request was rejected before being sent to the server due to:
2019.09.26 15:13:03.424 EA does not have permission to conduct trading operations (F7 --> Common --> "Allow Automatic Trading")

Pressionamos F7 e nas configurações do EA, permitiremos que ele negocie. Ao tentar abrir uma posição, obtemos uma posição aberta:

2019.09.26 15:14:32.619 - Position is open: 2019.09.26 11:14:32.711 -
2019.09.26 15:14:32.619 EURUSD Opened 0.10 Buy #455179802 [0.10 Market-order Buy #455179802] at price 1.09441, Magic number 123

As restantes restrições podem ser verificadas no testador ou numa conta demo, criando uma situação em que uma das restrições funciona, por exemplo, uma restrição no número máximo de ordens pendentes na conta.

O que vem agora?

No próximo artigo, controlaremos que os parâmetros das ordens de negociação sejam corretos.

Abaixo estão anexados todos os arquivos da versão atual da biblioteca e os arquivos do EA de teste. Você pode baixá-los e testar tudo sozinho.
Se você tiver perguntas, comentários e sugestões, poderá expressá-los nos comentários do artigo.

Complementos

Artigos desta série:

Parte 1. Conceito, gerenciamento de dados e primeiros resultados
Parte 2. Coleção do histórico de ordens e negócios
Parte 3. Coleção de ordens e posições de mercado, busca e ordenação
Parte 4. Eventos de Negociação. Conceito
Parte 5. Classes e coleções de eventos de negociação. Envio de eventos para o programa
Parte 6. Eventos da conta netting
Parte 7. Eventos de ativação da ordem stoplimit, preparação da funcionalidade para os eventos de modificação de ordens e posições
Parte 8. Eventos de modificação de ordens e posições
Parte 9. Compatibilidade com a MQL4 - preparação dos dados
Parte 10. Compatibilidade com a MQL4 - eventos de abertura de posição e ativação de ordens pendentes
Parte 11. Compatibilidade com a MQL4 - eventos de encerramento de posição
Parte 12. Implementação da classe de objeto "conta" e da coleção de objetos da conta
Parte 13. Eventos do objeto conta
Parte 14. O objeto símbolo
Parte 15. Coleção de objetos-símbolos
Parte 16. Eventos de coleção de símbolos
Parte 17. Interatividade de objetos de biblioteca
Parte 18. Interatividade do objeto-conta e quaisquer de outros objetos da biblioteca
Parte 19. Classe de mensagens de biblioteca
Parte 20. Criação e armazenamento de recursos de programas
Parte 21 Classes de negociação - objeto básico de negociação multiplataforma

Traduzido do russo pela MetaQuotes Software Corp.
Artigo original: https://www.mql5.com/ru/articles/7258

Arquivos anexados |
MQL5.zip (3585.29 KB)
MQL4.zip (3585.26 KB)
Ampliando as funcionalidades do Construtor de Estratégia Ampliando as funcionalidades do Construtor de Estratégia

Nos dois artigos anteriores, nós discutimos a aplicação dos padrões de Merrill a vários tipos de dados. Um aplicativo foi desenvolvido para testar as ideias apresentadas. Neste artigo, nós continuaremos trabalhando com o Construtor de Estratégia, para melhorar sua eficiência e implementar novos recursos e capacidades.

Otimização Walk Forward Contínua (Parte 1): Trabalhando com os Relatórios de Otimização Otimização Walk Forward Contínua (Parte 1): Trabalhando com os Relatórios de Otimização

O primeiro artigo é dedicado à criação de um kit de ferramentas para trabalhar com os relatórios de otimização, importá-los da plataforma e para filtrar e classificar os dados obtidos. A MetaTrader 5 permite baixar os resultados da otimização, no entanto, nosso objetivo é adicionar nossos próprios dados ao relatório de otimização.

Explorando os Padrões Sazonais de Séries Temporais Financeiras com o Boxplot Explorando os Padrões Sazonais de Séries Temporais Financeiras com o Boxplot

Neste artigo, nós visualizaremos características sazonais de séries temporais financeiras usando diagramas Boxplot. Cada boxplot separado (ou diagrama de caixa) fornece uma boa visualização de como os valores são distribuídos ao longo do conjunto de dados. Os boxplots não devem ser confundidos com os gráficos de velas, embora possam ser visualmente semelhantes.

Biblioteca para criação simples e rápida de programas para MetaTrader (Parte XXIII): classe básica de negociação, controle de parâmetros válidos Biblioteca para criação simples e rápida de programas para MetaTrader (Parte XXIII): classe básica de negociação, controle de parâmetros válidos

Neste artigo, continuaremos a acompanhar o desenvolvimento da classe de negociação, criaremos um controle que encontre valores incorretos nos parâmetros da ordem de negociação e sonorizaremos eventos de negociação.