Библиотека для простого и быстрого создания программ для MetaTrader (Часть XXII): Торговые классы - Основной торговый класс, контроль ограничений

Artyom Trishkin | 30 сентября, 2019

Содержание

В прошлой статье мы открыли обширный раздел библиотеки, посвящённый торговым функциям и создали базовый торговый объект символа. Этот торговый объект получает в своих параметрах все свойства отправляемого на сервер торгового запроса, заполняет структуру торгового запроса в соответствии с типом вызванного метода класса (открытие позиции/установка отложенного ордера/модификация/закрытие/удаление) и отправляет торговый приказ на сервер. И мы условились о понимании, что в базовый торговый объект для отсылки торгового приказа передаются корректные значения свойств торгового запроса. Но для полноценного использования торгового объекта нам необходимо сначала проверить существующие ограничения для проведения торговых операций в терминале, программе, на счёте и символе. И уже после прохождения этих первичных проверок мы можем проверять корректность свойств торгового запроса.

Сегодня начнём делать полноценный торговый класс, и первое что сделаем для реализации полноценной и комфортной работы с торговым функционалом библиотеки — проверку ограничений для проведения торговых операций.

Концепция

Мы уже имеем базовый торговый объект, который входит в состав объекта-символа. Выполняет он простую задачу — заполнить структуру торгового запроса в соответствии с параметрами, переданными в один из методов класса, и отправить торговый приказ на сервер. Сегодня мы, перед тем, как начать делать полноценный торговый класс, дополним немного функционал базового торгового объекта — добавим возможность озвучивания результатов отсылки торгового приказа. В итоге мы сможем задать любой звук для озвучивания торговых событий. Причём, для каждого символа мы сможем задать свои звуки для каждого из торговых событий. Но также, естественно, можем задать общий набор звуков для каждого из событий, одинаковые для всех символов. В общем, базовый торговый объект будет предоставлять широкие возможности задания звуков торговым событиям, как одинаковых сразу для всех символов и событий, так и индивидуальных для отдельно взятого символа и события.

Затем создадим торговый класс, из которого в дальнейшем будем проводить все торговые операции. Сегодня этот класс будет иметь минимальный функционал — проверку разрешения на проведение торговых операций и вызов необходимых методов базовых торговых объектов требуемых символов.

Расширение функционала базового торгового объекта

Итак. Для установки звуков торговым событиям нам потребуются макроподстановки и перечисления. Откроем файл Defines.mqh, и впишем в него макроподстановки, подменяющие названия стандартных звуковых файлов:

//+------------------------------------------------------------------+
//| Макроподстановки                                                 |
//+------------------------------------------------------------------+
//--- "Описание функции с номером строки ошибки"
#define DFUN_ERR_LINE                  (__FUNCTION__+(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian" ? ", Стр. " : ", Line ")+(string)__LINE__+": ")
#define DFUN                           (__FUNCTION__+": ")        // "Описание функции"
#define COUNTRY_LANG                   ("Russian")                // Язык страны
#define END_TIME                       (D'31.12.3000 23:59:59')   // Конечная дата для запросов данных истории счёта
#define TIMER_FREQUENCY                (16)                       // Минимальная частота таймера библиотеки в милисекундах
//--- Стандартные звуки
#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"
//--- Параметры таймера коллекции ордеров и сделок

Просто так удобнее будет задавать имена для установки стандартных звуковых файлов, если мы хотим использовать их в качестве файлов звуков для озвучки торговых событий.

В конец листинга в блок данных для работы с торговыми классами
впишем перечисление типов торговых операций и перечисление режимов установки звуков:

//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Данные для работы с торговыми классами                           |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|  Уровень логирования                                             |
//+------------------------------------------------------------------+
enum ENUM_LOG_LEVEL
  {
   LOG_LEVEL_NO_MSG,                                        // Логирование торговли отключено
   LOG_LEVEL_ERROR_MSG,                                     // Только торговые ошибки
   LOG_LEVEL_ALL_MSG                                        // Полное логирование
  };
//+------------------------------------------------------------------+
//| Типы проводимых операций                                         |
//+------------------------------------------------------------------+
enum ENUM_ACTION_TYPE
  {
   ACTION_TYPE_BUY               =  ORDER_TYPE_BUY,               // Открытие Buy
   ACTION_TYPE_SELL              =  ORDER_TYPE_SELL,              // Открытие Sell
   ACTION_TYPE_BUY_LIMIT         =  ORDER_TYPE_BUY_LIMIT,         // Установка BuyLimit
   ACTION_TYPE_SELL_LIMIT        =  ORDER_TYPE_SELL_LIMIT,        // Установка SellLimit
   ACTION_TYPE_BUY_STOP          =  ORDER_TYPE_BUY_STOP,          // Установка BuyStop
   ACTION_TYPE_SELL_STOP         =  ORDER_TYPE_SELL_STOP,         // Установка SellStop
   ACTION_TYPE_BUY_STOP_LIMIT    =  ORDER_TYPE_BUY_STOP_LIMIT,    // Установка BuyStopLimit
   ACTION_TYPE_SELL_STOP_LIMIT   =  ORDER_TYPE_SELL_STOP_LIMIT,   // Установка SellStopLimit
   ACTION_TYPE_CLOSE_BY          =  ORDER_TYPE_CLOSE_BY,          // Закрытие позиции встречной
   ACTION_TYPE_MODIFY            =  ACTION_TYPE_CLOSE_BY+1,       // Модификация
  };
//+------------------------------------------------------------------+
//| Режим установки звуков                                           |
//+------------------------------------------------------------------+
enum ENUM_MODE_SET_SOUND
  {
   MODE_SET_SOUND_OPEN,                                     // Режим установки звука открытия/установки
   MODE_SET_SOUND_CLOSE,                                    // Режим установки звука закрытия/удаления
   MODE_SET_SOUND_MODIFY_SL,                                // Режим установки звука модификации StopLoss
   MODE_SET_SOUND_MODIFY_TP,                                // Режим установки звука модификации TakeProfit
   MODE_SET_SOUND_MODIFY_PRICE,                             // Режим установки звука модификации цены установки
   MODE_SET_SOUND_ERROR_OPEN,                               // Режим установки звука ошибки открытия/установки
   MODE_SET_SOUND_ERROR_CLOSE,                              // Режим установки звука ошибки закрытия/удаления
   MODE_SET_SOUND_ERROR_MODIFY_SL,                          // Режим установки звука ошибки модификации StopLoss
   MODE_SET_SOUND_ERROR_MODIFY_TP,                          // Режим установки звука ошибки модификации TakeProfit
   MODE_SET_SOUND_ERROR_MODIFY_PRICE,                       // Режим установки звука ошибки модификации цены установки
  };
//+------------------------------------------------------------------+

Начиная с версии терминала 2155 в MQL5 появились новые свойства для символа и аккаунта:

  1. MQL5: В перечисление ENUM_SYMBOL_INFO_STRING добавлены следующие значения:

    • SYMBOL_CATEGORY — категория символа. Используется для дополнительной маркировки финансовых инструментов. Например, в нем могут быть указаны секторы рынка, к которым относится символ: Agriculture, Oil & Gas и т.д.
    • SYMBOL_EXCHANGE — название биржи или площадки, на которой торгуется символ.

  2. MQL5: Добавлена поддержка закрытия позиций по правилу FIFO.

    • В перечисление ENUM_ACCOUNT_INFO_INTEGER добавлено значение ACCOUNT_FIFO_CLOSE — признак того, что позиции можно закрывать только по правилу FIFO. Если значение свойства равно true, то позиции по каждому символу разрешается закрывать только в том порядке, в котором они были открыты — сначала самую старую, затем более новую и т.д. При попытке закрыть позиции в ином порядке будет получена ошибка. Для счетов без хеджингового учета позиций (ACCOUNT_MARGIN_MODE!=ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) свойство всегда равно false.
    • Добавлен новый код возврата сервера TRADE_RETCODE_FIFO_CLOSE — запрос отклонен, так как для торгового счета установлено правило "Разрешено закрывать существующие позиции только по правилу FIFO".

    Закрытие позиций может осуществляться тремя основными способами:

    • Закрытие через клиентский терминал — это закрытие позиций трейдером вручную, при помощи торгового робота, через сервис "Сигналы" и т.д. При попытке закрыть позиции не по правилу FIFO трейдер получит соответствующую ошибку.
    • Закрытие при срабатывании Стоп Лосса или Тейк Профита — эти ордера обрабатываются на стороне сервера, соответственно и закрытие позиций в таком случае инициируется не трейдером (терминалом), а самим сервером. Если для позиции сработал Стоп Лосс или Тейк профит, и эта позиция не соответствует правилу FIFO (по тому же инструменту есть более ранние позиции), то она не будет закрыта.
    • Закрытие при срабатывании Стоп аута — такие операции также обрабатываются на стороне сервера. В обычном режиме, когда закрытие по правилу FIFO отключено, при наступлении Стоп аута позиции закрываются, начиная с самой убыточной. При включении этой опции у закрываемых убыточных позиции будет дополнительно проверяться время их открытия. Сервер определяет убыточные позиции по каждому символу, находит для каждого символа наиболее старую позицию, а затем из найденных позиций закрывает ту, что дает наибольший убыток.

В связи с этим в объект-символ и в объект-аккаунт были добавлены новые свойства.

В блок целочисленных свойств аккаунта вписано новое свойство, и количество целочисленных свойств увеличено до 11:

//+------------------------------------------------------------------+
//| Целочисленные свойства аккаунта                                  |
//+------------------------------------------------------------------+
enum ENUM_ACCOUNT_PROP_INTEGER
  {
   ACCOUNT_PROP_LOGIN,                                      // Номер счёта
   ACCOUNT_PROP_TRADE_MODE,                                 // Тип торгового счета
   ACCOUNT_PROP_LEVERAGE,                                   // Размер предоставленного плеча
   ACCOUNT_PROP_LIMIT_ORDERS,                               // Максимально допустимое количество действующих отложенных ордеров
   ACCOUNT_PROP_MARGIN_SO_MODE,                             // Режим задания минимально допустимого уровня залоговых средств
   ACCOUNT_PROP_TRADE_ALLOWED,                              // Разрешенность торговли для текущего счета со стороны сервера
   ACCOUNT_PROP_TRADE_EXPERT,                               // Разрешенность торговли для эксперта со стороны сервера
   ACCOUNT_PROP_MARGIN_MODE,                                // Режим расчета маржи
   ACCOUNT_PROP_CURRENCY_DIGITS,                            // Количество знаков после запятой для валюты счета, необходимых для точного отображения торговых результатов
   ACCOUNT_PROP_SERVER_TYPE,                                // Тип торгового сервера (MetaTrader5, MetaTrader4)
   ACCOUNT_PROP_FIFO_CLOSE                                  // Признак закрытия позиций только по правилу FIFO
  };
#define ACCOUNT_PROP_INTEGER_TOTAL    (11)                  // Общее количество целочисленных свойств счетов
#define ACCOUNT_PROP_INTEGER_SKIP     (0)                   // Количество неиспользуемых в сортировке целочисленных свойств счетов
//+------------------------------------------------------------------+

В блок возможных критериев сортировки аккаунта добавили новый критерий сортировки по целочисленным свойствам:

//+------------------------------------------------------------------+
//| Возможные критерии сортировки аккаунтов                          |
//+------------------------------------------------------------------+
#define FIRST_ACC_DBL_PROP            (ACCOUNT_PROP_INTEGER_TOTAL-ACCOUNT_PROP_INTEGER_SKIP)
#define FIRST_ACC_STR_PROP            (ACCOUNT_PROP_INTEGER_TOTAL-ACCOUNT_PROP_INTEGER_SKIP+ACCOUNT_PROP_DOUBLE_TOTAL-ACCOUNT_PROP_DOUBLE_SKIP)
enum ENUM_SORT_ACCOUNT_MODE
  {
//--- Сортировка по целочисленным свойствам
   SORT_BY_ACCOUNT_LOGIN = 0,                               // Сортировать по номеру счёта
   SORT_BY_ACCOUNT_TRADE_MODE,                              // Сортировать по типу торгового счета
   SORT_BY_ACCOUNT_LEVERAGE,                                // Сортировать по размеру предоставленного плеча
   SORT_BY_ACCOUNT_LIMIT_ORDERS,                            // Сортировать по максимально допустимому количеству действующих отложенных ордеров
   SORT_BY_ACCOUNT_MARGIN_SO_MODE,                          // Сортировать по режиму задания минимально допустимого уровня залоговых средств
   SORT_BY_ACCOUNT_TRADE_ALLOWED,                           // Сортировать по разрешенности торговли для текущего счета
   SORT_BY_ACCOUNT_TRADE_EXPERT,                            // Сортировать по разрешенности торговли для эксперта
   SORT_BY_ACCOUNT_MARGIN_MODE,                             // Сортировать по режиму расчета маржи
   SORT_BY_ACCOUNT_CURRENCY_DIGITS,                         // Сортировать по количеству знаков после запятой для валюты счета
   SORT_BY_ACCOUNT_SERVER_TYPE,                             // Сортировать по типу торгового сервера (MetaTrader5, MetaTrader4)
   SORT_BY_ACCOUNT_FIFO_CLOSE,                              // Сортировать по признаку закрытия позиций только по правилу FIFO
//--- Сортировка по вещественным свойствам

Точно так же добавлены свойства объекта-символа.

В блок строковых свойств добавлены два новых свойства и количество строковых свойств увеличено до 13:

//+------------------------------------------------------------------+
//| Строковые свойства символа                                       |
//+------------------------------------------------------------------+
enum ENUM_SYMBOL_PROP_STRING
  {
   SYMBOL_PROP_NAME = (SYMBOL_PROP_INTEGER_TOTAL+SYMBOL_PROP_DOUBLE_TOTAL),   // Имя символа
   SYMBOL_PROP_BASIS,                                       // Имя базового актива для производного инструмента
   SYMBOL_PROP_CURRENCY_BASE,                               // Базовая валюта инструмента
   SYMBOL_PROP_CURRENCY_PROFIT,                             // Валюта прибыли
   SYMBOL_PROP_CURRENCY_MARGIN,                             // Валюта, в которой вычисляются залоговые средства
   SYMBOL_PROP_BANK,                                        // Источник текущей котировки
   SYMBOL_PROP_DESCRIPTION,                                 // Строковое описание символа
   SYMBOL_PROP_FORMULA,                                     // Формула для построения цены пользовательского символа
   SYMBOL_PROP_ISIN,                                        // Имя торгового символа в системе международных идентификационных кодов ценных бумаг — ISIN
   SYMBOL_PROP_PAGE,                                        // Адрес интернет страницы с информацией по символу
   SYMBOL_PROP_PATH,                                        // Путь в дереве символов
   SYMBOL_PROP_CATEGORY,                                    // Категория символа
   SYMBOL_PROP_EXCHANGE                                     // Название биржи или площадки, на которой торгуется символ
  };
#define SYMBOL_PROP_STRING_TOTAL     (13)                   // Общее количество строковых свойств
//+------------------------------------------------------------------+

В список возможных критериев сортировки символов добавлены два новых критерия сортировки по строковым свойствам символа:

//--- Сортировка по строковым свойствам
   SORT_BY_SYMBOL_NAME = FIRST_SYM_STR_PROP,                // Сортировать по имени символа
   SORT_BY_SYMBOL_BASIS,                                    // Сортировать по имени базового актива для производного инструмента
   SORT_BY_SYMBOL_CURRENCY_BASE,                            // Сортировать по базовой валюте инструмента
   SORT_BY_SYMBOL_CURRENCY_PROFIT,                          // Сортировать по валюте прибыли
   SORT_BY_SYMBOL_CURRENCY_MARGIN,                          // Сортировать по валюте, в которой вычисляются залоговые средства
   SORT_BY_SYMBOL_BANK,                                     // Сортировать по источнику текущей котировки
   SORT_BY_SYMBOL_DESCRIPTION,                              // Сортировать по строковому описанию символа
   SORT_BY_SYMBOL_FORMULA,                                  // Сортировать по формуле для построения цены пользовательского символа
   SORT_BY_SYMBOL_ISIN,                                     // Сортировать по имени торгового символа в системе международных идентификационных кодов ценных бумаг — ISIN
   SORT_BY_SYMBOL_PAGE,                                     // Сортировать по адресу интернет страницы с информацией по символу
   SORT_BY_SYMBOL_PATH,                                     // Сортировать по пути в дереве символов
   SORT_BY_SYMBOL_CATEGORY,                                 // Сортировать по категории символа
   SORT_BY_SYMBOL_EXCHANGE                                  // Сортировать по названию биржи или площадки, на которой торгуется символ
  };
//+------------------------------------------------------------------+

Также били добавлены некоторые новые константы индексов текстовых сообщений библиотеки для работы с новыми свойствами объектов, классами и методами.
Рассмотрим добавленные новые константы в файле Datas.mqh:

//+------------------------------------------------------------------+
//| Список индексов текстовых сообщений библиотеки                   |
//+------------------------------------------------------------------+
enum ENUM_MESSAGES_LIB
  {
   MSG_LIB_PARAMS_LIST_BEG=ERR_USER_ERROR_FIRST,      // Начало списка параметров
   MSG_LIB_PARAMS_LIST_END,                           // Конец списка параметров
   MSG_LIB_PROP_NOT_SUPPORTED,                        // Свойство не поддерживается
   MSG_LIB_PROP_NOT_SUPPORTED_MQL4,                   // Свойство не поддерживается в MQL4
   MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_2155,          // Свойство не поддерживается в MetaTrader5 версии ниже 2155
   MSG_LIB_PROP_NOT_SUPPORTED_POSITION,               // Свойство не поддерживается у позиции
   MSG_LIB_PROP_NOT_SUPPORTED_PENDING,                // Свойство не поддерживается у отложенного ордера
   MSG_LIB_PROP_NOT_SUPPORTED_MARKET,                 // Свойство не поддерживается у маркет-ордера
   MSG_LIB_PROP_NOT_SUPPORTED_MARKET_HIST,            // Свойство не поддерживается у исторического маркет-ордера
   MSG_LIB_PROP_NOT_SET,                              // Значение не задано
   MSG_LIB_PROP_EMPTY,                                // Отсутствует
   
   MSG_LIB_SYS_ERROR,                                 // Ошибка
   MSG_LIB_SYS_NOT_SYMBOL_ON_SERVER,                  // Ошибка. Такого символа нет на сервере
   MSG_LIB_SYS_NOT_SYMBOL_ON_LIST,                    // Ошибка. Такого символа нет в списке используемых символов: 
   MSG_LIB_SYS_FAILED_PUT_SYMBOL,                     // Не удалось поместить в обзор рынка. Ошибка: 
   MSG_LIB_SYS_NOT_GET_PRICE,                         // Не удалось получить текущие цены. Ошибка: 
   MSG_LIB_SYS_NOT_GET_MARGIN_RATES,                  // Не удалось получить коэффициенты взимания маржи. Ошибка: 
   MSG_LIB_SYS_NOT_GET_DATAS,                         // Не удалось получить данные
   
   MSG_LIB_SYS_FAILED_CREATE_STORAGE_FOLDER,          // Не удалось создать папку хранения файлов. Ошибка: 
   MSG_LIB_SYS_FAILED_ADD_ACC_OBJ_TO_LIST,            // Ошибка. Не удалось добавить текущий объект-аккаунт в список-коллекцию
   MSG_LIB_SYS_FAILED_CREATE_CURR_ACC_OBJ,            // Ошибка. Не удалось создать объект-аккаунт с данными текущего счёта
   MSG_LIB_SYS_FAILED_OPEN_FILE_FOR_WRITE,            // Не удалось открыть для записи файл
   MSG_LIB_SYS_INPUT_ERROR_NO_SYMBOL,                 // Ошибка входных данных: нет символа
   MSG_LIB_SYS_FAILED_CREATE_SYM_OBJ,                 // Не удалось создать объект-символ
   MSG_LIB_SYS_FAILED_ADD_SYM_OBJ,                    // Не удалось добавить символ
   
   MSG_LIB_SYS_NOT_GET_CURR_PRICES,                   // Не удалось получить текущие цены по символу события
   MSG_LIB_SYS_EVENT_ALREADY_IN_LIST,                 // Такое событие уже есть в списке
   MSG_LIB_SYS_FILE_RES_ALREADY_IN_LIST,              // Такой файл уже создан и добавлен в список:
   MSG_LIB_SYS_FAILED_CREATE_RES_LINK,                // Ошибка. Не удалось создать объект-указатель на файл ресурса
   MSG_LIB_SYS_ERROR_ALREADY_CREATED_COUNTER,         // Ошибка. Уже создан счётчик с идентификатором
   MSG_LIB_SYS_FAILED_CREATE_COUNTER,                 // Не удалось создать счётчик таймера
   MSG_LIB_SYS_FAILED_CREATE_TEMP_LIST,               // Ошибка создания временного списка
   MSG_LIB_SYS_ERROR_NOT_MARKET_LIST,                 // Ошибка. Список не является списком рыночной коллекции
   MSG_LIB_SYS_ERROR_NOT_HISTORY_LIST,                // Ошибка. Список не является списком исторической коллекции
   MSG_LIB_SYS_FAILED_ADD_ORDER_TO_LIST,              // Не удалось добавить ордер в список
   MSG_LIB_SYS_FAILED_ADD_DEAL_TO_LIST,               // Не удалось добавить сделку в список
   MSG_LIB_SYS_FAILED_ADD_CTRL_ORDER_TO_LIST,         // Не удалось добавить контрольный ордер
   MSG_LIB_SYS_FAILED_ADD_CTRL_POSITION_TO_LIST,      // Не удалось добавить контрольую позицию
   MSG_LIB_SYS_FAILED_ADD_MODIFIED_ORD_TO_LIST,       // Не удалось добавить модифицированный ордер в список изменённых ордеров
   MSG_LIB_SYS_FAILED_CREATE_TIMER,                   // Не удалось создать таймер. Ошибка: 
    
   MSG_LIB_SYS_NO_TICKS_YET,                          // Ещё не было тиков
   MSG_LIB_SYS_FAILED_CREATE_OBJ_STRUCT,              // Не удалось создать структуру объекта
   MSG_LIB_SYS_FAILED_WRITE_UARRAY_TO_FILE,           // Не удалось записать uchar-массив в файл
   MSG_LIB_SYS_FAILED_LOAD_UARRAY_FROM_FILE,          // Не удалось загрузить uchar-массив из файла
   MSG_LIB_SYS_FAILED_CREATE_OBJ_STRUCT_FROM_UARRAY,  // Не удалось создать структуру объекта из uchar-массива
   MSG_LIB_SYS_FAILED_SAVE_OBJ_STRUCT_TO_UARRAY,      // Не удалось сохранить структуру объекта в uchar-массив, ошибка
   MSG_LIB_SYS_ERROR_INDEX,                           // Ошибка. Значение "index" должно быть в пределах 0 - 3
   MSG_LIB_SYS_ERROR_FAILED_CONV_TO_LOWERCASE,        // Не удалось преобразовать строку в нижний регистр, ошибка
//--- COrder
   MSG_ORD_BUY,                                       // Buy
   MSG_ORD_SELL,                                      // Sell
   MSG_ORD_TO_BUY,                                    // Ордер на покупку
   MSG_ORD_TO_SELL,                                   // Ордер на продажу
   MSG_DEAL_TO_BUY,                                   // Сделка на покупку
   MSG_DEAL_TO_SELL,                                  // Сделка на продажу
   MSG_ORD_MARKET,                                    // Маркет-ордер
   MSG_ORD_HISTORY,                                   // Исторический ордер
   MSG_ORD_DEAL,                                      // Сделка
   MSG_ORD_POSITION,                                  // Позиция
   MSG_ORD_PENDING_ACTIVE,                            // Установленный отложенный ордер
   MSG_ORD_PENDING,                                   // Отложенный ордер
   MSG_ORD_UNKNOWN_TYPE,                              // Неизвестный тип ордера
   MSG_POS_UNKNOWN_TYPE,                              // Неизвестный тип позиции
   MSG_POS_UNKNOWN_DEAL,                              // Неизвестный тип сделки
   //---
   //---
   MSG_SYM_PROP_NAME,                                 // Имя символа
   MSG_SYM_PROP_BASIS,                                // Имя базового актива для производного инструмента
   MSG_SYM_PROP_CURRENCY_BASE,                        // Базовая валюта инструмента
   MSG_SYM_PROP_CURRENCY_PROFIT,                      // Валюта прибыли
   MSG_SYM_PROP_CURRENCY_MARGIN,                      // Валюта залоговых средств
   MSG_SYM_PROP_BANK,                                 // Источник текущей котировки
   MSG_SYM_PROP_DESCRIPTION,                          // Описание символа
   MSG_SYM_PROP_FORMULA,                              // Формула для построения цены пользовательского символа
   MSG_SYM_PROP_ISIN,                                 // Имя торгового символа в системе международных идентификационных кодов
   MSG_SYM_PROP_PAGE,                                 // Адрес интернет страницы с информацией по символу
   MSG_SYM_PROP_PATH,                                 // Путь в дереве символов
   MSG_SYM_PROP_CAYEGORY,                             // Категория символа
   MSG_SYM_PROP_EXCHANGE,                             // Название биржи или площадки, на которой торгуется символ
   //---
   //---
   MSG_SYM_TRADE_MODE_DISABLED,                       // Торговля по символу запрещена
   MSG_SYM_TRADE_MODE_LONGONLY,                       // Разрешены только покупки
   MSG_SYM_TRADE_MODE_SHORTONLY,                      // Разрешены только продажи
   MSG_SYM_TRADE_MODE_CLOSEONLY,                      // Разрешены только операции закрытия позиций
   MSG_SYM_TRADE_MODE_FULL,                           // Нет ограничений на торговые операции
   
   MSG_SYM_MARKET_ORDER_DISABLED,                     // Торговля рыночными ордерами запрещена
   MSG_SYM_LIMIT_ORDER_DISABLED,                      // Установка Limit-ордеров запрещена
   MSG_SYM_STOP_ORDER_DISABLED,                       // Установка Stop-ордеров запрещена
   MSG_SYM_STOP_LIMIT_ORDER_DISABLED,                 // Установка StopLimit-ордеров запрещена
   MSG_SYM_SL_ORDER_DISABLED,                         // Установка StopLoss-ордеров запрещена
   MSG_SYM_TP_ORDER_DISABLED,                         // Установка TakeProfit-ордеров запрещена
   MSG_SYM_CLOSE_BY_ORDER_DISABLED,                   // Установка CloseBy-ордеров запрещена
   //---
//--- CAccount
   MSG_ACC_PROP_LOGIN,                                // Номер счёта
   MSG_ACC_PROP_TRADE_MODE,                           // Тип торгового счета
   MSG_ACC_PROP_LEVERAGE,                             // Размер предоставленного плеча
   MSG_ACC_PROP_LIMIT_ORDERS,                         // Максимально допустимое количество действующих отложенных ордеров
   MSG_ACC_PROP_MARGIN_SO_MODE,                       // Режим задания минимально допустимого уровня залоговых средств
   MSG_ACC_PROP_TRADE_ALLOWED,                        // Разрешенность торговли для текущего счета
   MSG_ACC_PROP_TRADE_EXPERT,                         // Разрешенность торговли для эксперта
   MSG_ACC_PROP_MARGIN_MODE,                          // Режим расчета маржи
   MSG_ACC_PROP_CURRENCY_DIGITS,                      // Количество знаков после запятой для валюты счета
   MSG_ACC_PROP_SERVER_TYPE,                          // Тип торгового сервера
   MSG_ACC_PROP_FIFO_CLOSE,                           // Признак закрытия позиций только по правилу FIFO
   //---
//--- CTrading
   MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED,           // В терминале нет разрешения на проведение торговых операций (отключена кнопка "Авто-торговля")
   MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED,                 // Для советника нет разрешения на проведение торговых операций (F7 --> Общие --> "Разрешить автоматическую торговлю")
   MSG_LIB_TEXT_ACCOUNT_NOT_TRADE_ENABLED,            // Для текущего счёта запрещена торговля
   MSG_LIB_TEXT_ACCOUNT_EA_NOT_TRADE_ENABLED,         // Для советников на текущем счёте запрещена торговля на стороне торгового сервера
   MSG_LIB_TEXT_TERMINAL_NOT_CONNECTED,               // Нет связи с торговым сервером
   MSG_LIB_TEXT_REQUEST_REJECTED_DUE,                 // Запрос отклонён до отправки на сервер по причине:
   MSG_LIB_TEXT_NOT_ENOUTH_MONEY_FOR,                 // Не хватает средств на открытие позиции:
   MSG_LIB_TEXT_MAX_VOLUME_LIMIT_EXCEEDED,            // Превышен максимальный совокупный объём ордеров и позиций в одном направлении
   MSG_LIB_TEXT_REQ_VOL_LESS_MIN_VOLUME,              // Объём в запросе меньше минимально-допустимого
   MSG_LIB_TEXT_REQ_VOL_MORE_MAX_VOLUME,              // Объём в запросе больше максимально-допустимого
   MSG_LIB_TEXT_CLOSE_BY_ORDERS_DISABLED,             // Закрытие встречным запрещено
   MSG_LIB_TEXT_INVALID_VOLUME_STEP,                  // Объём в запросе не кратен минимальной градации шага изменения лота
   MSG_LIB_TEXT_CLOSE_BY_SYMBOLS_UNEQUAL,             // Символы встречных позиций не равны
   
  };

И добавим в массивы текстовых сообщений тексты, соответствующие объявленным константам:

//+------------------------------------------------------------------+
//| Массив предопределённых сообщений библиотеки                     |
//| (1) на языке страны пользователя                                 |
//| (2) на международном - английском языке                          |
//| (3) любой требуемый добавочный язык сообщения.                   |
//|  По умолчанию используются два языка - русский и английский.     |
//|  Для добавления нужного количества иных языков достаточно        |
//|  указать общее количество используемых языков в TOTAL_LANG       |
//|  и дописать требуемый перевод после текста на английском языке   |
//+------------------------------------------------------------------+
string messages_library[][TOTAL_LANG]=
  {
   {"Начало списка параметров","The beginning of the event parameter list"},
   {"Конец списка параметров","End of the parameter list"},
   {"Свойство не поддерживается","Property is not support"},
   {"Свойство не поддерживается в MQL4","Property is not supported in MQL4"},
   {"Свойство не поддерживается в MetaTrader5 версии ниже 2155","The property is not supported in MetaTrader5, build lower than 2155"},
   {"Свойство не поддерживается у позиции","Property not supported for position"},
   {"Свойство не поддерживается у отложенного ордера","The property is not supported for a pending order"},
   {"Свойство не поддерживается у маркет-ордера","The property is not supported for a market-order"},
   {"Свойство не поддерживается у исторического маркет-ордера","The property is not supported for a history market-order"},
   {"Значение не задано","Value not set"},
   {"Отсутствует","Not set"},
   
   {"Ошибка ","Error "},
   {"Ошибка. Такого символа нет на сервере","Error. There is no such symbol on the server"},
   {"Ошибка. Такого символа нет в списке используемых символов: ","Error. This symbol is not in the list of the symbols used: "},
   {"Не удалось поместить в обзор рынка. Ошибка: ","Failed to put in the 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 an 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 is already in the list"},
   {"Такой файл уже создан и добавлен в список: ","This file has already been created and added to the list: "},
   {"Ошибка. Не удалось создать объект-указатель на файл ресурса","Error. Failed to create resource file link object"},
   
   {"Ошибка. Уже создан счётчик с идентификатором ","Error. Already created a counter with id "},
   {"Не удалось создать счётчик таймера ","Failed to create timer counter "},
   
   {"Ошибка создания временного списка","Error creating temporary list"},
   {"Ошибка. Список не является списком рыночной коллекции","Error. The list is not a list of the market collection"},
   {"Ошибка. Список не является списком исторической коллекции","Error. The list is not a list of the history collection"},
   {"Не удалось добавить ордер в список","Could not add order to the list"},
   {"Не удалось добавить сделку в список","Could not add deal to the list"},
   {"Не удалось добавить контрольный ордер ","Failed to add a control order "},
   {"Не удалось добавить контрольую позицию ","Failed to add a control position "},
   {"Не удалось добавить модифицированный ордер в список изменённых ордеров","Could not add modified order to the list of modified orders"},
   {"Не удалось создать таймер. Ошибка: ","Could not create timer. Error: "},
   
//--- COrder
   {"Buy","Buy"},
   {"Sell","Sell"},
   {"Ордер на покупку","The order to Buy"},
   {"Ордер на продажу","The order to Sell"},
   
   {"Сделка на покупку","The deal to Buy"},
   {"Сделка на продажу","The deal to Sell"},
   
   {"Маркет-ордер","Market-order"},
   {"Исторический ордер","History order"},
   {"Сделка","Deal"},
   {"Позиция","Active position"},
   {"Установленный отложенный ордер","Active pending order"},
   {"Отложенный ордер","Pending order"},
   {"Неизвестный тип ордера","Unknown order type"},
   {"Неизвестный тип позиции","Unknown position type"},
   {"Неизвестный тип сделки","Unknown deal type"},
   //---
   {"Путь в дереве символов","Path in the symbol tree"},
   {"Название категории или сектора, к которой принадлежит торговый символ","The name of the sector or category to which the trading symbol belongs"},
   {"Название биржи или площадки, на которой торгуется символ","The name of the exchange in which the financial symbol is traded"},
   //---
   {"Форекс символ","Forex symbol"},
   {"Разрешены только операции закрытия позиций","Allowed only position close operations"},
   {"Нет ограничений на торговые операции","No trade restrictions"},
   {"Торговля рыночными ордерами запрещена","Trading through market orders is prohibited"},
   {"Установка Limit-ордеров запрещена","Limit orders are prohibited"},
   {"Установка Stop-ордеров запрещена","Stop orders are prohibited"},
   {"Установка StopLimit-ордеров запрещена","StopLimit orders are prohibited"},
   {"Установка StopLoss-ордеров запрещена","StopLoss orders are prohibited"},
   {"Установка TakeProfit-ордеров запрещена","TakeProfit orders are prohibited"},
   {"Установка CloseBy-ордеров запрещена","CloseBy orders are 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 the minimal allowed margin"},
   {"Разрешенность торговли для текущего счета","Allowed trade for the current account"},
   {"Разрешенность торговли для эксперта","Allowed trade for an Expert Advisor"},
   {"Режим расчета маржи","Margin calculation mode"},
   {"Количество знаков после запятой для валюты счета","The number of decimal places in the account currency"},
   {"Тип торгового сервера","Type of trading server"},
   {"Признак закрытия позиций только по правилу FIFO","Sign of closing positions only according to the FIFO rule"},
   //---
   {"Баланс счета","Account balance"},
//--- CEngine
   {"С момента последнего запуска ЕА торговых событий не было","There have been no trade events since the last launch of EA"},
   {"Не удалось получить описание последнего торгового события","Failed to get the description of the last trading event"},
   {"Не удалось получить список открытых позиций","Failed to get open positions list"},
   {"Не удалось получить список установленных ордеров","Failed to get pending orders list"},
   {"Нет открытых позиций","No open positions"},
   {"Нет установленных ордеров","No placed orders"},
   {"В терминале нет разрешения на проведение торговых операций (отключена кнопка \"Авто-торговля\")","There is no permission to conduct trading operations in the terminal (the \"AutoTrading\" button is disabled)"},
   {"Для советника нет разрешения на проведение торговых операций (F7 --> Общие --> \"Разрешить автоматическую торговлю\")","EA does not have permission to conduct trading operations (F7 --> Common --> \"Allow Automatic Trading\")"},
   {"Для текущего счёта запрещена торговля","Trading is prohibited for the current account"},
   {"Для советников на текущем счёте запрещена торговля на стороне торгового сервера","From the side of the trading server, trading for EA on the current account is prohibited"},
   {"Нет связи с торговым сервером","No connection to the trading server"},
   {"Запрос отклонён до отправки на сервер по причине:","The request was rejected before being sent to the server due to:"},
   {"Не хватает средств на открытие позиции: ","Not enough money to open position: "},
   {"Превышен максимальный совокупный объём ордеров и позиций в одном направлении","Exceeded the maximum total volume of orders and positions in one direction"},
   {"Объём в запросе меньше минимально-допустимого","The volume in the request is less than the minimum allowable"},
   {"Объём в запросе больше максимально-допустимого","The volume in the request is greater than the maximum allowable"},
   {"Закрытие встречным запрещено","CloseBy orders is prohibited"},
   {"Объём в запросе не кратен минимальной градации шага изменения лота","The volume in the request is not a multiple of the minimum gradation of the step for changing the lot"},
   {"Символы встречных позиций не равны","Symbols of the two opposite positions are not equal"},
   
  };
//+---------------------------------------------------------------------+
//| Массив сообщений кодов возвратов торгового сервера (10004 - 10045)  |
//| (1) на языке страны пользователя                                    |
//| (2) на международном языке                                          |
//+---------------------------------------------------------------------+
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 the request was completed"},                                                                         // 10010
   {"Ошибка обработки запроса","Request processing error"},                                                                                        // 10011
   {"Запрос отменен по истечению времени","Request canceled by timeout"},                                                                          // 10012
   {"Неправильный запрос","Invalid request"},                                                                                                      // 10013
   {"Неправильный объем в запросе","Invalid volume in the request"},                                                                               // 10014
   {"Неправильная цена в запросе","Invalid price in the request"},                                                                                 // 10015
   {"Неправильные стопы в запросе","Invalid stops in the request"},                                                                                // 10016
   {"Торговля запрещена","Trade is disabled"},                                                                                                     // 10017
   {"Рынок закрыт","Market is closed"},                                                                                                            // 10018
   {"Нет достаточных денежных средств для выполнения запроса","There is not enough money to complete the request"},                                // 10019
   {"Цены изменились","Prices changed"},                                                                                                           // 10020
   {"Отсутствуют котировки для обработки запроса","There are no quotes to process the request"},                                                   // 10021
   {"Неверная дата истечения ордера в запросе","Invalid order expiration date in the 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 the trade server"},                                                                   // 10031
   {"Операция разрешена только для реальных счетов","Operation is allowed only for live accounts"},                                                // 10032
   {"Достигнут лимит на количество отложенных ордеров","The number of pending orders has reached the limit"},                                      // 10033
   {"Достигнут лимит на объем ордеров и позиций для данного символа","The volume of orders and positions for the symbol has reached the limit"},   // 10034
   {"Неверный или запрещённый тип ордера","Incorrect or prohibited order type"},                                                                   // 10035
   {"Позиция с указанным идентификатором уже закрыта","Position with the specified identifier has already been closed"},                           // 10036
   {"Неизвестный код возврата торгового сервера","Unknown trading server return code"},                                                   // 10037
   {"Закрываемый объем превышает текущий объем позиции","A close volume exceeds the current position volume"},                                     // 10038
   {"Для указанной позиции уже есть ордер на закрытие","A close order already exists for a specified position"},                                   // 10039
   {"Достигнут лимит на количество открытых позиций","The number of positions has reached the limit"},                                             // 10040
   {
    "Запрос на активацию отложенного ордера отклонен, а сам ордер отменен",                                                                        // 10041
    "The pending order activation request is rejected, the order is canceled"
   },
   {
    "Запрос отклонен, так как на символе установлено правило \"Разрешены только длинные позиции\"",                                                // 10042
    "The request is rejected, because the \"Only long positions are allowed\" rule is set for the symbol"
   },
   {
    "Запрос отклонен, так как на символе установлено правило \"Разрешены только короткие позиции\"",                                               // 10043
    "The request is rejected, because the \"Only short positions are allowed\" rule is set for the symbol"
   },
   {
    "Запрос отклонен, так как на символе установлено правило \"Разрешено только закрывать существующие позиции\"",                                 // 10044
    "The request is rejected, because the \"Only position closing is allowed\" rule is set for the symbol"
   },
   {
    "Запрос отклонен, так как для торгового счета установлено правило \"Разрешено закрывать существующие позиции только по правилу FIFO\"",        // 10045
    "The request is rejected, because \"Position closing is allowed only by FIFO rule\" flag is set for the trading account"
   },
  };
//+------------------------------------------------------------------+

Как мы уже знаем, все проделанные манипуляции служат для добавления в библиотеку новых её сообщений, и для быстрого доступа к сообщению по его индексу, прописанному в константе сообщения.

Теперь доработаем класс сообщений, расположенный в файле \MQL5\Include\DoEasy\Services\Message.mqh.

В публичной секции класса объявим метод для остановки воспроизведения любого звукового файла:

public:
//--- (1) Выводит текстовое сообщение в журнал, отправляет Push и e-mail,
//--- (2) Выводит сообщение в журнал по идентификатору, отправляет Push и e-mail,
//--- (3) воспроизводит звуковой файл
//--- (4) Останавливает воспроизведение любого звука
   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);
   //--- Возвращает (1) сообщение, (2) код в формате "(код)"

И за пределами тела класса напишем его реализацию:

//+------------------------------------------------------------------+
//| Останавливает воспроизведение любого звука                       |
//+------------------------------------------------------------------+
bool CMessage::StopPlaySound(void)
  {
   bool res=::PlaySound(NULL);
   CMessage::m_global_error=(res ? ERR_SUCCESS : ::GetLastError());
   return res;
  }
//+------------------------------------------------------------------+

Тут всё просто: при передаче в качестве имени файла константы NULL, штатная функция PlaySound() останавливает воспроизведение проигрываемого в данный момент звукового файла.

Для того чтобы у нас была возможность проигрывать стандартные файлы звуков, прилагаемые к поставке терминала, нам нужно указать в имени файла либо только имя файла (для воспроизведения звуков из стандартного расположения файлов: папка_расположения_терминала\Sounds), либо имя файла с префиксом, где указан двойной слеш и подпапка, в которой находятся нестандартные звуковые файлы.
Поэтому мы доработаем метод PlaySound():

//+------------------------------------------------------------------+
//| Воспроизводит звуковой файл                                      |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+

Что у нас тут:

Если в качестве имени файла передано имя стандартного звукового файла, то в префикс имени файла записываем пустую строку.
Иначе
— в префикс записываем двойной слеш и имя подпапки расположения звуков библиотеки.
Затем имя файла составляется из префикса и переданного в метод имени.
Теперь при передаче имени в функцию PlaySound() у нас автоматически будет выбрано место расположения звукового файла — либо стандартный каталог звуков, либо папка расположения звуковых файлов библиотеки и проигран соответствующий файл.

Так как у нас теперь добавился новый код возврата торгового сервера, то в методе получения сообщения из массива текстов по идентификатору
void CMessage::GetTextByID() изменим пределы кодов возврата торгового сервера на 1 больше (было 10044, стало 10045):

      //--- Ошибки времени выполнения (Экономический календарь 5400 - 5402)
      msg_id>5399 && msg_id<5403    ?  messages_runtime_calendar[msg_id-5400][m_lang_num]         :
      //--- Коды возврата торгового сервера (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 (4000 - 4030)
      msg_id<4031                   ?  messages_runtime_4000_4030[msg_id-4000][m_lang_num]        :
      //--- Ошибки времени выполнения MQL4 (4050 - 4075)
      msg_id>4049 && msg_id<4076    ?  messages_runtime_4050_4075[msg_id-4050][m_lang_num]        :
      //--- Ошибки времени выполнения MQL4 (4099 - 4112)
      msg_id>4098 && msg_id<4113    ?  messages_runtime_4099_4112[msg_id-4099][m_lang_num]        :
      //--- Ошибки времени выполнения MQL4 (4200 - 4220)
      msg_id>4199 && msg_id<4221    ?  messages_runtime_4200_4220[msg_id-4200][m_lang_num]        :
      //--- Ошибки времени выполнения MQL4 (4250 - 4266)
      msg_id>4249 && msg_id<4267    ?  messages_runtime_4250_4266[msg_id-4250][m_lang_num]        :
      //--- Ошибки времени выполнения MQL4 (5001 - 5029)
      msg_id>5000 && msg_id<5030    ?  messages_runtime_5001_5029[msg_id-5001][m_lang_num]        :
      //--- Ошибки времени выполнения MQL4 (5200 - 5203)
      msg_id>5199 && msg_id<5204    ?  messages_runtime_5200_5203[msg_id-5200][m_lang_num]        :
     #endif 
      //--- Сообщения библиотеки (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]
     );

Это все изменения в классе сообщений библиотеки.

Иногда нам требуется узнать по типу ордера в каком направлении откроется позиция при срабатывании этого ордера. Например, мы выставили отложенный ордер с типом ORDER_TYPE_BUY_LIMIT. При его срабатывании будет выставлен маркет-ордер ORDER_TYPE_BUY, который породит сделку DEAL_ENTRY_IN с типом DEAL_TYPE_BUY, и она в свою очредь — позицию с типом POSITION_TYPE_BUY.

Так вот, чтобы узнать по типу отложенного ордера в каком же направлении будет открыта позиция, нам нужно получить тип маркет-ордера (для данного примера) ORDER_TYPE_BUY.
Ранее мы его определяли при помощи тернарного оператора, сравнивая с типом отложенного ордера. Но можно делать проще: можно просто брать остаток от деления типа проверяемого ордера на 2. Для чётных ордеров всегда будет возвращаться тип 0 (ORDER_TYPE_BUY), а для нечётных — тип 1 (ORDER_TYPE_SELL). Что мы и сделали в некоторых функциях и методах.
В классе абстрактного ордера (\MQL5\Include\DoEasy\Objects\Orders\Order.mqh):

//+------------------------------------------------------------------+
//| Возвращает тип по направлению                                    |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+

и в библиотеке сервисных функций (\MQL5\Include\DoEasy\Services\DELib.mqh):

//+------------------------------------------------------------------+
//| Возвращает тип позиции по типу ордера                            |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+

В этом же файле сервисных функций претерпела некоторые изменения функция, возвращающая наименование ордера.
Был добавлен флаг, указывающий необходимость вывода описания ордера и к возвращаемому типу маркет-ордера в зависимости от этого флага либо добавляется описание что это маркет-ордер, либо нет. И к возвращаемым типам отложенных ордеров были добавлены описания типа ордера:

//+------------------------------------------------------------------+
//| Возвращает наименование ордера                                   |
//+------------------------------------------------------------------+
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)
     );
  }
//+------------------------------------------------------------------+

В связи с появлением новых свойств у объектов символа и аккаунта нам нужно добавить эти свойства объектам.

Откроем файл \MQL5\Include\DoEasy\Objects\Symbols\Symbol.mqh и впишем в него необходимые изменения.
В защищённой секции класса впишем определение методов для получения двух новых свойств:

protected:
//--- Защищённый параметрический конструктор
                     CSymbol(ENUM_SYMBOL_STATUS symbol_status,const string name,const int index);

//--- Получает и возвращает целочисленные свойства выбранного символа из его параметров
   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);
//--- Получает и возвращает вещественные свойства выбранного символа из его параметров
   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);
//--- Получает и возвращает строковые свойства выбранного символа из его параметров
   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;
//--- Ищет символ и возвращает флаг его наличия на сервере
   bool              Exist(void)                         const;

public:

В публичной секции класса, в блоке упрощённого получения свойств объекта впишем определение двух новых методов:

public:
//+------------------------------------------------------------------+
//| Методы упрощённого доступа к свойствам объекта-символа           |
//+------------------------------------------------------------------+
//--- Целочисленные свойства
   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);      }
//--- Вещественные свойства
   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            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);                                    }
   
//+------------------------------------------------------------------+

В закрытом параметрическом конструкторе класса впишем получение этих новых свойств:

//--- Сохранение строковых свойств
   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();
//--- Сохранение дополнительных целочисленных свойств

За пределами тела класса напишем реализацию методов получения двух новых свойств:

//+------------------------------------------------------------------+
//| Возвращает категорию символа                                     |
//+------------------------------------------------------------------+
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
     );
  }
//+------------------------------------------------------------------+
//| Возвращает название биржи или площадки,                          |
//| на которой торгуется символ                                      |
//+------------------------------------------------------------------+
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
     );
  }
//+------------------------------------------------------------------+

Здесь: для MQL5 проверяем номер сборки терминала, и если он меньше 2155, то возвращаем сообщение о том, что данное свойство не поддерживается в версии, ниже чем 2155, иначе — возвращаем новое свойство SYMBOL_EXCHANGE.
Для MQL4 сразу возвращаем сообщение, что свойство не поддерживается в MQL4.

В реализацию метода, возвращающего описание строкового свойства символа добавим возврат описаний двух новых свойств:

//+------------------------------------------------------------------+
//| Возвращает описание строкового свойства символа                  |
//+------------------------------------------------------------------+
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)+"\"")
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+

Теперь допишем новое свойство к объекту-аккаунту в файле \MQL5\Include\DoEasy\Objects\Accounts\Account.mqh.

В структуру свойств аккаунта допишем новое поле:

//+------------------------------------------------------------------+
//| Класс аккаунта                                                   |
//+------------------------------------------------------------------+
class CAccount : public CBaseObj
  {
private:
   struct SData
     {
      //--- Целочисленные свойства счёта
      long           login;                        // ACCOUNT_LOGIN (Номер счёта)
      int            trade_mode;                   // ACCOUNT_TRADE_MODE (Тип торгового счета)
      long           leverage;                     // ACCOUNT_LEVERAGE (Размер предоставленного плеча)
      int            limit_orders;                 // ACCOUNT_LIMIT_ORDERS (Максимально допустимое количество действующих отложенных ордеров)
      int            margin_so_mode;               // ACCOUNT_MARGIN_SO_MODE (Режим задания минимально допустимого уровня залоговых средств)
      bool           trade_allowed;                // ACCOUNT_TRADE_ALLOWED (Разрешенность торговли для текущего счета со стороны сервера)
      bool           trade_expert;                 // ACCOUNT_TRADE_EXPERT (Разрешенность торговли для эксперта со стороны сервера)
      int            margin_mode;                  // ACCOUNT_MARGIN_MODE (Режим расчета маржи)
      int            currency_digits;              // ACCOUNT_CURRENCY_DIGITS (Количество знаков после запятой для валюты счета)
      int            server_type;                  // Тип торгового сервера (MetaTrader5, MetaTrader4)
      bool           fifo_close;                   // Признак того, что позиции можно закрывать только по правилу FIFO
      //--- Вещественные свойства счёта
      double         balance;                      // ACCOUNT_BALANCE (Баланс счета в валюте депозита)
      double         credit;                       // ACCOUNT_CREDIT (Размер предоставленного кредита в валюте депозита)
      double         profit;                       // ACCOUNT_PROFIT (Размер текущей прибыли на счете в валюте депозита)
      double         equity;                       // ACCOUNT_EQUITY (Значение собственных средств на счете в валюте депозита)
      double         margin;                       // ACCOUNT_MARGIN (Размер зарезервированных залоговых средств на счете  в валюте депозита)
      double         margin_free;                  // ACCOUNT_MARGIN_FREE (Размер свободных средств на счете  в валюте депозита, доступных для открытия позиции)
      double         margin_level;                 // ACCOUNT_MARGIN_LEVEL (Уровень залоговых средств на счете в процентах)
      double         margin_so_call;               // ACCOUNT_MARGIN_SO_CALL (Уровень залоговых средств, при котором происходит MarginCall)
      double         margin_so_so;                 // ACCOUNT_MARGIN_SO_SO (Уровень залоговых средств, при достижении которого происходит StopOut)
      double         margin_initial;               // ACCOUNT_MARGIN_INITIAL (Размер средств, зарезервированных на счёте, для обеспечения гарантийной суммы по всем отложенным ордерам)
      double         margin_maintenance;           // ACCOUNT_MARGIN_MAINTENANCE (Размер средств, зарезервированных на счёте, для обеспечения минимальной суммы по всем открытым позициям)
      double         assets;                       // ACCOUNT_ASSETS (Текущий размер активов на счёте)
      double         liabilities;                  // ACCOUNT_LIABILITIES (Текущий размер обязательств на счёте)
      double         comission_blocked;            // ACCOUNT_COMMISSION_BLOCKED (Текущая сумма заблокированных комиссий по счёту)
      //--- Строковые свойства счёта
      uchar          name[128];                    // ACCOUNT_NAME (Имя клиента)
      uchar          server[64];                   // ACCOUNT_SERVER (Имя торгового сервера)
      uchar          currency[32];                 // ACCOUNT_CURRENCY (Валюта депозита)
      uchar          company[128];                 // ACCOUNT_COMPANY (Имя компании, обслуживающей счет)
     };
   SData             m_struct_obj;                                      // Структура объекта-аккаунта

В публичной секции класса, в блоке методов упрощённого доступа к свойствам объекта впишем метод, возвращающий новое свойство:

//+------------------------------------------------------------------+
//| Методы упрощённого доступа к свойствам объекта-аккаунта          |
//+------------------------------------------------------------------+
//--- Возвращает целочисленные свойства аккаунта
   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);                                    }
//--- Возвращает вещественные свойства аккаунта

В конструкторе класса впишем сохранение нового свойства объекта-аккаунта:

//+------------------------------------------------------------------+
//| Конструктор                                                      |
//+------------------------------------------------------------------+
CAccount::CAccount(void)
  {
//--- Инициализация контролируемых данных
   this.SetControlDataArraySizeLong(ACCOUNT_PROP_INTEGER_TOTAL);
   this.SetControlDataArraySizeDouble(ACCOUNT_PROP_DOUBLE_TOTAL);
   this.ResetChangesParams();
   this.ResetControlsParams();
  
//--- Сохранение целочисленных свойств
   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 );
   
//--- Сохранение вещественных свойств

Если билд иерминала ниже 2155, то вписываем false, иначе — значение свойства аккаунта ACCOUNT_FIFO_CLOSE.

В методе обновления свойств аккаунта Refresh() так же впишем сохранение данного свойства:

//+------------------------------------------------------------------+
//| Обновляет все данные аккаунта                                    |
//+------------------------------------------------------------------+
void CAccount::Refresh(void)
  {
//--- Инициализация событийных данных
   this.m_is_event=false;
   this.m_hash_sum=0;
//--- Обновление целочисленных свойств
   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 );
   
//--- Обновление вещественных свойств

В методе создания объекта-аккаунта из структуры пропишем заполнение нового свойства:

//+------------------------------------------------------------------+
//| Создаёт объект-аккаунт из структуры                              |
//+------------------------------------------------------------------+
void CAccount::StructToObject(void)
  {
//--- Сохранение целочисленных свойств
   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;
//--- Сохранение вещественных свойств

В методе, возвращающем описание целочисленных свойств объекта-аккаунта впишем вывод описания нового свойства:

//+------------------------------------------------------------------+
//| Возвращает описание целочисленного свойства аккаунта             |
//+------------------------------------------------------------------+
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)                       :
      ""
     );
  }
//+------------------------------------------------------------------+

Следует учитывать, что внесение нового свойсва в объект-аккаунт сделало невалидным ранее сохранённые объекты-аккаунты в общей папке всех терминалов, и чтобы не было ошибок их считывания, нужно самостоятельно удалить все ранее созданные файлы аккаунтов в общей папке всех терминалов в подпапке \DoEasy\Accounts\. В последующем, при смене счёта на новый, библиотека сама сохранит объекты-аккаунты в новом формате.
Чтобы открыть общую папку всех терминалов, нужно воспользоваться командой редактора "Файл --> Открыть общую папку данных". В открывшемся окне проводника войти в папку Files, а в ней в подпапку библиотеки \DoEasy\Accounts\

Для работы с создаваемым сегодня торговым классом нам потребуется получать размер маржи, необходимый для открытия позиции или установки ордера.

В публичной секции класса впишем определение метода, возвращающего размер маржи, требуемого для открытия указанной позиции или установки отложенного ордера:

public:
//--- Конструктор
                     CAccount(void);
//--- Устанавливает (1) целочисленное, (2) вещественное и (3) строковое свойство аккаунта
   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;                }
//--- Возвращает из массива свойств (1) целочисленное, (2) вещественное и (3) строковое свойство аккаунта
   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)];               }
//--- Возвращает флаг расчёта уровне MarginCall и StopOut в процентах
   bool              IsPercentsForSOLevels(void)                                 const { return this.MarginSOMode()==ACCOUNT_STOPOUT_MODE_PERCENT;          }
//--- Возвращает флаг поддержания объектом-аккаунтом данного свойства
   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; }

//--- Сравнивает объекты CAccount между собой по всем возможным свойствам (для сортировки списков по указанному свойству объекта-аккаунта)
   virtual int       Compare(const CObject *node,const int mode=0) const;
//--- Сравнивает объекты CAccount между собой по свойствам счёта (для поиска равных объектов-аккаунтов)
   bool              IsEqual(CAccount* compared_account) const;
//--- Обновляет все данные аккаунта
   virtual void      Refresh(void);
//--- (1) Сохраняет объект-аккаунт в файл, (2), загружает объект-аккаунт из файла
   virtual bool      Save(const int file_handle);
   virtual bool      Load(const int file_handle);
 
//--- Возвращает размер маржи, требуемый для открытия позиции или установки отложенного ордера
   double            MarginForAction(const ENUM_ORDER_TYPE action,const string symbol,const double volume,const double price) const;

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

И за пределами тела класса напишем его реализацию:

//+------------------------------------------------------------------+
//| Возвращает размер маржи, требуемый для открытия позиции          |
//| или установки отложенного ордера                                 |
//+------------------------------------------------------------------+
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
  }
//+------------------------------------------------------------------+

Здесь: для MQL5 получаем при помощи функции OrderCalcMargin() размер маржи, требуемый для открытия новой позиции или установки отложенного ордера. При этом, если по какой-то причине функция вернула ошибку, то возвращаем максимальное значение DBL_MAX (это значение имеет константа EMPTY_VALUE), иначе — рассчитанный размер требуемой маржи.
Для MQL4 возвращаем размер имеющейся свободной маржи за вычетом средств, которые останутся после открытия указанной позиции или установки ордера, рассчитанные при помощи функции AccountFreeMarginCheck().

Доработка класса объекта-аккаунта завершена.

Теперь доработаем класс базового торгового объекта. Нам необходимо добавить в него возможность установки любых звуков для озвучивания любых торговых событий.
Для хранения данных, в приватной секции класса создадим структуру, хранящую флаги использования звуков и имена звуковых файлов для разных событий:

//+------------------------------------------------------------------+
//| Класс торгового объекта                                          |
//+------------------------------------------------------------------+
class CTradeObj
  {
private:
   struct SActionsFlags
     {
   private:
      bool                    m_use_sound_open;          // Флаг использования звука открытия позиции/установки ордера
      bool                    m_use_sound_close;         // Флаг использования звука закрытия позиции/удаления ордера
      bool                    m_use_sound_modify_sl;     // Флаг использования звука модификации StopLoss позиции/ордера
      bool                    m_use_sound_modify_tp;     // Флаг использования звука модификации TakeProfit позиции/ордера
      bool                    m_use_sound_modify_price;  // Флаг использования звука модификации цены установки ордера
      //---
      string                  m_sound_open;              // Звук открытия позиции/установки ордера
      string                  m_sound_close;             // Звук закрытия позиции/удаления ордера
      string                  m_sound_modify_sl;         // Звук модификации StopLoss позиции/ордера
      string                  m_sound_modify_tp;         // Звук модификации TakeProfit позиции/ордера
      string                  m_sound_modify_price;      // Звук модификации цены установки ордера
      //---
      string                  m_sound_open_err;          // Звук ошибки при открытии позиции/установки ордера
      string                  m_sound_close_err;         // Звук ошибки при закрытии позиции/удаления ордера
      string                  m_sound_modify_sl_err;     // Звук ошибки при модификации StopLoss позиции/ордера
      string                  m_sound_modify_tp_err;     // Звук ошибки при модификации TakeProfit позиции/ордера
      string                  m_sound_modify_price_err;  // Звук ошибки при модификации цены установки ордера
   public:
      //--- Методы установки/доступа к флагам и именам файлов
      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;

Структура состоит из двух вложенных структур: структура с данными о флагах и именах файлов SActionsFlags, и структура SActions m_data, имеющая в своём составе данные с типом структуры SActionsFlags для каждого из типов позиций и ордеров. Таким образом мы всегда сможем для любого ордера или позиции обратиться к полю его структуры с флагами и именами файлов, что даёт нам большую гибкость установки и использования звуков для любых событий.

Там же,
в приватной секции класса объявим переменную-член класса, хранящую флаг использования торговым объектом звуков для торговых событий:

   bool                       m_use_sound;                   // Флаг использования звуков торговых событий объекта

Этот флаг будет общим включателем/выключателем использования звуков для всех торговых событий торгового объекта символа. При помощи данного флага можно будет одновременно включать/выключать использование звуков для торговых событий каждого символа одним разом.

В публичной секции класса объявим все необходимые методы для установки и получения флагов использования звуков и имён звуковых файлов для всех торговых событий базового торгового объекта символа:

public:
//--- Конструктор
                              CTradeObj();

//--- Устанавливает значения по умолчанию
   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);
                                   
//--- Устанавливает звуки и флаги использования звуков по умолчанию,
   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);
//--- Разрешает работу со звуками и устанавливает стандартные звуки
   void                       SetSoundsStandart(void);
//--- Устанавливает флаг использования звука (1) открытия/установки для заданного типа позиции/ордера,
//--- (2) закрытия/удаления для заданного типа позиции/ордера (3) модификации StopLoss для заданного типа позиции/ордера,
//--- (4) модификации TakeProfit для заданного типа позиции/ордера (5) модификации цены установки для заданного типа ордера
   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);
//--- Возвращает флаг использования звука (1) открытия/установки для заданного типа позиции/ордера,
//--- (2) закрытия/удаления для заданного типа позиции/ордера (3) модификации StopLoss для заданного типа позиции/ордера,
//--- (4) модификации TakeProfit для заданного типа позиции/ордера (5) модификации цены установки для заданного типа ордера
   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;

//--- Устанавливает звук (1) открытия/установки для заданного типа позиции/ордера,
//--- (2) закрытия/удаления для заданного типа позиции/ордера (3) модификации StopLoss для заданного типа позиции/ордера,
//--- (4) модификации TakeProfit для заданного типа позиции/ордера (5) модификации цены установки для заданного типа ордера
   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);
//--- Устанавливает звук ошибки (1) открытия/установки для заданного типа позиции/ордера,
//--- (2) закрытия/удаления для заданного типа позиции/ордера (3) модификации StopLoss для заданного типа позиции/ордера,
//--- (4) модификации TakeProfit для заданного типа позиции/ордера (5) модификации цены установки для заданного типа ордера
   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);

//--- Возвращает звук (1) открытия/установки для заданного типа позиции/ордера,
//--- (2) закрытия/удаления для заданного типа позиции/ордера (3) модификации StopLoss для заданного типа позиции/ордера,
//--- (4) модификации TakeProfit для заданного типа позиции/ордера (5) модификации цены установки для заданного типа ордера
   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;
//--- Возвращает звук ошибки (1) открытия/установки для заданного типа позиции/ордера,
//--- (2) закрытия/удаления для заданного типа позиции/ордера (3) модификации StopLoss для заданного типа позиции/ордера,
//--- (4) модификации TakeProfit для заданного типа позиции/ордера (5) модификации цены установки для заданного типа ордера
   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;
   
//--- Воспроизводит звук (1) открытия/установки для заданного типа позиции/ордера,
//--- (2) закрытия/удаления для заданного типа позиции/ордера (3) модификации StopLoss для заданного типа позиции/ордера,
//--- (4) модификации TakeProfit для заданного типа позиции/ордера (5) модификации цены установки для заданного типа ордера
   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);
//--- Воспроизводит звук ошибки (1) открытия/установки для заданного типа позиции/ордера,
//--- (2) закрытия/удаления для заданного типа позиции/ордера (3) модификации StopLoss для заданного типа позиции/ордера,
//--- (4) модификации TakeProfit для заданного типа позиции/ордера (5) модификации цены установки для заданного типа ордера
   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);

//--- Устанавливает/возвращает флаг использования звуков
   void                       SetUseSound(const bool flag)                             { this.m_use_sound=flag;               }
   bool                       IsUseSound(void)                                   const { return this.m_use_sound;             }

//--- (1) Возвращает режим расчёта маржи (2) флаг счёта хедж

В конструкторе класса сбросим общий флаг использования звуков и инициализируем флаги использования звуков и звуковые файлы в значения по умолчанию как запрет использования звуков и пустые имена файлов:

//+------------------------------------------------------------------+
//| Конструктор                                                      |
//+------------------------------------------------------------------+
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)
  {
   //--- Режим расчёта маржи
   this.m_margin_mode=
     (
      #ifdef __MQL5__ (ENUM_ACCOUNT_MARGIN_MODE)::AccountInfoInteger(ACCOUNT_MARGIN_MODE)
      #else /* MQL4 */ ACCOUNT_MARGIN_MODE_RETAIL_HEDGING #endif 
     );
   //--- Установка звуков и флагов использования звуков по умолчанию
   this.m_use_sound=false;
   this.InitSounds();
  }
//+------------------------------------------------------------------+

За пределами тела класса напишем реализацию метода инициализации флагов использования звуков и задания имён звуковых файлов:

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

//| Устанавливает звуки и флаги использования звуков по умолчанию    |
//+------------------------------------------------------------------+
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);
  }  
//+------------------------------------------------------------------+

В метод передаются флаг использования звуков событий торгового объекта, имена файлов звука открытия, закрытия, модификации StopLoss и TakeProfit, цены установки ордера и звук ошибки. Далее заполняются поля структур для каждого торгового события для каждого типа ордера, отправляемого на сервер переданными значениями.

Флаг использования звуков и имя файла звука ошибки здесь устанавливаются один на все перечисленные торговые события, а вот для торговых событий для каждого звук задаётся индивидуально. Впрочем, при желании, можно и для звуков ошибки конкретных событий установить собственный звук при помощи объявленных выше методов, равно как и задать флаг использования звука для каждого торгового события объекта индивидуально. По умолчанию устанавливается запрет использования звуков и пустые имена файлов.

Также в классе предусмотрен метод, позволяющий задать одновременно для всех торговых событий объекта стандартные звуки и разрешить их использование для каждого торгового события:

//+------------------------------------------------------------------+
//| Разрешает работу со звуками и устанавливает стандартные звуки    |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+

За пределами тела класса напишем методы воспроизведения звуков и установки флагов и звуков для конкретного типа торгового события:

//+------------------------------------------------------------------+
//| Устанавливает флаг использования звуков                          |
//| открытия/установки для заданного типа позиции/ордера             |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования звука                           |
//| закрытия/удаления для заданного типа позиции/ордера              |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования звука                           |
//| модификации StopLoss для заданного типа позиции/ордера           |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования звука                           |
//| модификации TakeProfit для заданного типа позиции/ордера         |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования звука модификации               |
//| цены установки для заданного типа ордера                         |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования звука открытия/установки           |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования звука закрытия/удаления            |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования звука                              |
//| модификации StopLoss для заданного типа позиции/ордера           |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования звука                              |
//| модификации TakeProfit для заданного типа позиции/ордера         |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования звука модификации                  |
//| цены установки для заданного типа ордера                         |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Устанавливает звук открытия/установки                            |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Устанавливает звук закрытия/удаления                             |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Устанавливает звук модификации StopLoss                          |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Устанавливает звук модификации TakeProfit                        |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Устанавливает звук модификации цены установки                    |
//| для заданного типа ордера                                        |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Устанавливает звук ошибки открытия/установки                     |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Устанавливает звук ошибки закрытия/удаления                      |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Устанавливает звук ошибки модификации StopLoss                   |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Устанавливает звук ошибки модификации TakeProfit                 |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Устанавливает звук ошибки модификации цены установки             |
//| для заданного типа ордера                                        |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Возвращает звук открытия/установки                               |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Возвращает звук закрытия/удаления                                |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Возвращает звук модификации StopLoss                             |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Возвращает звук модификации TakeProfit                           |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Возвращает звук модификации цены установки                       |
//| для заданного типа ордера                                        |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Возвращает звук ошибки открытия/установки                        |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Возвращает звук ошибки закрытия/удаления                         |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Возвращает звук ошибки модификации StopLoss                      |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Возвращает звук ошибки модификации TakeProfit                    |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Возвращает звук ошибки модификации цены установки                |
//| для заданного типа ордера                                        |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Воспроизводит звук открытия/установки                            |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Воспроизводит звук закрытия/удаления                             |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Воспроизводит звук модификации StopLoss                          |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Воспроизводит звук модификации TakeProfit                        |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Воспроизводит звук модификации цены установки                    |
//| для заданного типа ордера                                        |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Воспроизводит звук ошибки открытия/установки                     |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Воспроизводит звук ошибки закрытия/удаления                      |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Воспроизводит звук ошибки модификации StopLoss                   |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Воспроизводит звук ошибки модификации TakeProfit                 |
//| для заданного типа позиции/ордера                                |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+
//| Воспроизводит звук ошибки модификации цены установки             |
//| для заданного типа ордера                                        |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+

Ну здесь всё одинаково для всех методов, и всё понятно с первого взгляда: в метод, в имени которого присутствует тип торгового события, передаётся тип ордера (для позиции — тип маркет-ордера), событие которого необходимо установить, вернуть или воспроизвести. И далее, исходя из типа позиции/ордера устанавливается/возвращается/воспроизводится звук заданного торгового события.

На этом доработка базового торгового объекта символа завершена и мы приступаем к созданию основного торгового класса.

Хочу отметить, что в торговый класс для его правильной работы мы будем передавать указатели на ранее созданные нами коллекции. Для этого мы в каждом классе коллекции допишем метод, возвращающий указатель на объект-коллекцию:

Для объекта исторической коллекции:

public:
//--- Возвращает себя
   CHistoryCollection *GetObject(void)                                                                   { return &this;   }

Для объекта рыночной коллекции:

public:
//--- Возвращает себя
   CMarketCollection *GetObject(void)                                                                    { return &this;   }

Для коллекции символов:

public:
//--- Возвращает себя
   CSymbolsCollection *GetObject(void)                                                                   { return &this;   }

Создаваемый нами торговый класс будет предоставлять централизованный доступ к торговым операциям. В нём будут аккумулированы все проверки перед отсылкой торгового приказа, обработка ответов торгового сервера и принятие решений о дальнейших действиях в зависимости от ответа торгового сервера и настроек поведения торговых методов класса.

Сегодня создадим основу класса, которую далее будем развивать. А пока займёмся проверкой ограничений для торговли со стороны программы, терминала, аккаунта и символа.

Торговый класс

В главной папке библиотеки \MQL5\Include\DoEasy\ создадим новый класс CTrading в файле Trading.mqh.
Так как для работы класса потребуются списки некоторых, предварительно созданных нами коллекций, и для хранения ошибок при проверке разрешений — объект динамического массива переменных типа int или uint стандартной библиотеки,
то сразу же подключим их к файлу класса:

//+------------------------------------------------------------------+
//|                                                      Trading.mqh |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#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.mqh |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#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"
//+------------------------------------------------------------------+
//| Торговый класс                                                   |
//+------------------------------------------------------------------+
class CTrading
  {
private:
   CAccount            *m_account;           // Указатель на объект-текущий аккаунт
   CSymbolsCollection  *m_symbols;           // Указатель на список коллекции символов
   CMarketCollection   *m_market;            // Указатель на список коллекции рыночных ордеров и позиций
   CHistoryCollection  *m_history;           // Указатель на список коллекции исторических ордеров и сделок
   CArrayInt            m_list_errors;       // Список ошибок
   bool                 m_is_trade_enable;   // Флаг разрешения торговли
   ENUM_LOG_LEVEL       m_log_level;         // Уровень логирования

//--- Добавляет код ошибки в список
   bool                 AddErrorCodeToList(const int error_code);
//--- Возвращает объект-символ по тикету (1) позиции, (2) ордера
   CSymbol             *GetSymbolObjByPosition(const ulong ticket,const string source_method);
   CSymbol             *GetSymbolObjByOrder(const ulong ticket,const string source_method);
//--- Возвращает торговый объект символа по тикету (1) позиции, (2) ордера, (3) по имени символа
   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);
//--- Возвращает количество позиций (1) всех, (2) на покупку, (3) на продажу
   int                  PositionsTotalAll(void)          const;
   int                  PositionsTotalLong(void)         const;
   int                  PositionsTotalShort(void)        const;
//--- Возвращает количество отложенных ордеров (1) всех, (2) на покупку, (3) на продажу
   int                  OrdersTotalAll(void)             const;
   int                  OrdersTotalLong(void)            const;
   int                  OrdersTotalShort(void)           const;
//--- Возвращает совокупный объём позиций (1) на покупку, (2) на продажу
   double               PositionsTotalVolumeLong(void)   const;
   double               PositionsTotalVolumeShort(void)  const;
//--- Возвращает совокупный объём ордеров (1) на покупку, (2) на продажу
   double               OrdersTotalVolumeLong(void)      const;
   double               OrdersTotalVolumeShort(void)     const;
//--- Возвращает направление ордера по типу операции
   ENUM_ORDER_TYPE      DirectionByActionType(ENUM_ACTION_TYPE action) const;
//--- Проверяет наличие (1) позиции, (2) ордера по тикету
   bool                 CheckPositionAvailablity(const ulong ticket,const string source_method);
   bool                 CheckOrderAvailablity(const ulong ticket,const string source_method);
//--- Устанавливает торговому объекту нужный звук
   void                 SetSoundByMode(const ENUM_MODE_SET_SOUND mode,const ENUM_ORDER_TYPE action,const string sound,CTradeObj *trade_obj);
public:
//--- Конструктор
                        CTrading();
//--- Получение указателей на списки (вызывать метод обязательно в OnInit() программы, так как список коллекции символов создаётся там)
   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;
                          }
//--- Возвращает список ошибок
   CArrayInt           *GetListErrors(void)                                { return &this.m_list_errors; }
//--- Проверка ограничений для торговли
   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);
//--- Проверка достаточности средств
   bool                 CheckMoneyFree(const ENUM_ORDER_TYPE order_type,const double volume,const double price,const CSymbol *symbol_obj,const string source_method) const;

//--- Устанавливает для торговых объектов символов:
//--- (1) корректное значение политики исполнения, (2) значение политики исполнения,
//--- (3) корректный тип истечения ордера, (4) тип истечения ордера,
//--- (5) магик, (6) Комментарий, (7) размер проскальзывания, (8) объём, (9) срок истечения ордера,
//--- (10) флаг асинхронной отправки торгового запроса, (11) уровень логирования
   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);

//--- Устанавливает стандартные звуки (1 symbol=NULL) торговым объектам всех символов, (2 symbol!=NULL) торговому объекту символа
   void                 SetSoundsStandart(const string symbol=NULL);
//--- Устанавливает звук для указанного типа ордера/позиции и символа
//--- Режим mode указывает для какого именно события устанавливается звук
//--- (symbol=NULL) торговым объектам всех символов,
//--- (symbol!=NULL) торговому объекту указанного символа
   void                 SetSound(const ENUM_MODE_SET_SOUND mode,const ENUM_ORDER_TYPE action,const string sound,const string symbol=NULL);

//--- Открывает позицию (1) Buy, (2) Sell
   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);
//--- Модифицирует позицию
   bool                 ModifyPosition(const ulong ticket,const double sl=WRONG_VALUE,const double tp=WRONG_VALUE);
//--- Закрывает позицию (1) полностью, (2) частично, (3) встречной
   bool                 ClosePosition(const ulong ticket);
   bool                 ClosePositionPartially(const ulong ticket,const double volume);
   bool                 ClosePositionBy(const ulong ticket,const ulong ticket_by);
//--- Устанавливает отложенный ордер (1) BuyStop, (2) BuyLimit, (3) BuyStopLimit
   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);
//--- Устанавливает отложенный ордер (1) SellStop, (2) SellLimit, (3) SellStopLimit
   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);
//--- Модифицирует отложенный ордер
   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);
//--- Удаляет отложенный ордер
   bool                 DeleteOrder(const ulong ticket);
  };
//+------------------------------------------------------------------+

К каждому из методов класса есть пояснительный комментарий, и надеюсь в дополнительных пояснениях состав методов класса не нуждается.

Торговые методы класса имеют практически ту же сигнатуру, что и методы базового торгового объекта символа. Разницей является лишь наличие наименования символа, на котором необходимо провести торговую операцию, в методах открытия позиции и установки отложенного ордера.

Рассмотирм реализацию методов класса.

Так как ограничений при проверке может оказаться несколько сразу, то чтобы отобразить их все, необходимо код каждой ошибки поместить в список, а затем — после окончания проверки всех необходимых условий, вывести список обнаруженных ограничений. Чтобы дважды не помещать в список одно и то же значение ограничения, обнаруженное в разных местах проверочного кода, то необходимо проверить наличие такого ограничения в списке, и добавлять его только при отсутствии. В этом случае каждый тип ограничений будет находиться в списке единожды.
Для проверки наличия типа ограничения в списке, и его добавления в список, создан метод:

//+------------------------------------------------------------------+
//| Добавляет код ошибки в список                                    |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+

В метод передаётся код ошибки, являющейся причиной ограничения торговли. Списку устанавливается флаг сортированного списка, проверяется отсутствие такого кода в списке, и при успешности проверки возвращается результат добавления кода в список методом Add().
Если код уже есть в списке — возвращаем false.

Так как торговые объекты принадлежат символу — каждый символ имеет свой торговый объект, а многие торговые методы работают с тикетом ордера или позиции, то нам необходимо по тикету определить символ, на котором существует такая позиция или ордер.
Для этого существует методы, возвращающие объект-символ по тикету позиции:

//+------------------------------------------------------------------+
//| Возвращает объект-символ по тикету позиции                       |
//+------------------------------------------------------------------+
CSymbol *CTrading::GetSymbolObjByPosition(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);
   //--- Если не удалось получить список открытых позиций - выводим сообщение и возвращаем 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;
     }
   //--- Если список пустой (Нет открытых позиций) - выводим сообщение и возвращаем 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;
     }
   //--- Фильтруем список по тикету 
   list=CSelect::ByOrderProperty(list,ORDER_PROP_TICKET,ticket,EQUAL);
   //--- Если не удалось получить список открытых позиций - выводим сообщение и возвращаем 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;
     }
   //--- Если список пустой (нет искомого тикета) - выводим сообщение и возвращаем NULL
   if(list.Total()==0)
     {
      //--- Ошибка. Нет открытой позиции с тикетом #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;
     }
   //--- Получаем позицию с тикетом #ticket из полученного списка
   COrder *pos=list.At(0);
   //--- Если не удалось получить объект-позицию - выводим сообщение и возвращаем 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;
     }
   //--- Получаем объект-символ по имени
   CSymbol * symbol_obj=this.m_symbols.GetSymbolObjByName(pos.Symbol());
   //--- Если не удалось получить объект-символ - выводим сообщение и возвращаем 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 symbol_obj;
  }
//+------------------------------------------------------------------+

и по тикету ордера:

//+------------------------------------------------------------------+
//| Возвращает объект-символ по тикету ордера                        |
//+------------------------------------------------------------------+
CSymbol *CTrading::GetSymbolObjByOrder(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);
   //--- Если не удалось получить список установленных ордеров - выводим сообщение и возвращаем 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;
     }
   //--- Если список пустой (Нет установленных ордеров) - выводим сообщение и возвращаем 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;
     }
   //--- Фильтруем список по тикету 
   list=CSelect::ByOrderProperty(list,ORDER_PROP_TICKET,ticket,EQUAL);
   //--- Если не удалось получить список установленных ордеров - выводим сообщение и возвращаем 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;
     }
   //--- Если список пустой (нет искомого тикета) - выводим сообщение и возвращаем NULL
   if(list.Total()==0)
     {
      //--- Ошибка. Нет установленного ордера с тикетом #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;
     }
   //--- Получаем ордер с тикетом #ticket из полученного списка
   COrder *ord=list.At(0);
   //--- Если не удалось получить объект-ордер - выводим сообщение и возвращаем 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;
     }
   //--- Получаем объект-символ по имени
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(ord.Symbol());
   //--- Если не удалось получить объект-символ - выводим сообщение и возвращаем 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 symbol_obj;
  }
//+------------------------------------------------------------------+

Эти два метода практически идентичны. Только в первом мы ищем позицию по тикету, а во втором — ордер. В метод передаётся тикет искомой позиции или ордера и наименование метода, из которого был вызван данный метод — чтобы при каких-либо ошибках мы могли в журнал распечатать название метода, из которого вызван этот метод — ведь если распечатать название этого вспомогательного метода, то это не даст нам никакой информации для определения места, в котором произошёл сбой (нам необходимо указать из какого метода был вызван поиск объекта-символа).

Для работы методов класса нам бывает необходимо получить торговый объект символа по тикету позиции, по тикету ордера или по имени символа:

//+------------------------------------------------------------------+
//| Возвращает торговый объект символа по тикету позиции             |
//+------------------------------------------------------------------+
CTradeObj *CTrading::GetTradeObjByPosition(const ulong ticket,const string source_method)
  {
   //--- Получаем объект-символ по тикету позиции
   CSymbol * symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN);
   //--- Если не удалось получить объект-символ - выводим сообщение и возвращаем 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;
     }
   //--- Получаем и возвращаем торговый объект из объекта-символа
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   return trade_obj;
  }
//+------------------------------------------------------------------+
//| Возвращает торговый объект символа по тикету ордера              |
//+------------------------------------------------------------------+
CTradeObj *CTrading::GetTradeObjByOrder(const ulong ticket,const string source_method)
  {
   //--- Получаем объект-символ по тикету ордера
   CSymbol * symbol_obj=this.GetSymbolObjByOrder(ticket,source_method);
   //--- Если не удалось получить объект-символ - выводим сообщение и возвращаем 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;
     }
   //--- Получаем и возвращаем торговый объект из объекта-символа
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   return trade_obj;
  }
//+------------------------------------------------------------------+
//| Возвращает торговый объект символа по имени символа              |
//+------------------------------------------------------------------+
CTradeObj *CTrading::GetTradeObjBySymbol(const string symbol,const string source_method)
  {
   //--- Получаем объект-символ по его имени
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
   //--- Если не удалось получить объект-символ - выводим сообщение и возвращаем 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;
     }
   //--- Получаем и возвращаем торговый объект из объекта-символа
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   return trade_obj;
  }
//+------------------------------------------------------------------+

Все три вспомогательных метода возвращают торговый объект для дальнейшей работы с ним. В листингах методов все действия прокомментированы.

Для проверки некоторых ограничений, а так же для принятия торговых решений, нам будет требоваться знание количества открытых позиций, выставленных ордеров как всех, так и в одном направлении.
Метод, возвращающий количество открытых позиций на счёте:

//+------------------------------------------------------------------+
//| Возвращает количество позиций                                    |
//+------------------------------------------------------------------+
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());
  }
//+------------------------------------------------------------------+

Здесь: получаем список всех открытых позиций и установленных ордеров,
фильтруем список по статусу ордера "рыночная позиция"
.
Возвращаем количество объектов в полученном списке
. Если список получить не удалось, то возвращаем ноль.

Метод, возвращающий количество открытых позиций на покупку на счёте:

//+------------------------------------------------------------------+
//| Возвращает количество позиций на покупку                         |
//+------------------------------------------------------------------+
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());
  }
//+------------------------------------------------------------------+

Здесь: получаем список всех открытых позиций и установленных ордеров,
фильтруем список по статусу ордера "рыночная позиция"
.
Полученный список фильтруем по типу позиции на покупку
.
Возвращаем количество объектов в полученном списке. Если список получить не удалось, то возвращаем ноль.

Метод, возвращающий количество открытых позиций на продажу на счёте:

//+------------------------------------------------------------------+
//| Возвращает количество позиций на продажу                         |
//+------------------------------------------------------------------+
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());
  }
//+------------------------------------------------------------------+

Здесь: получаем список всех открытых позиций и установленных ордеров,
фильтруем список по статусу ордера "рыночная позиция"
.
Полученный список фильтруем по типу позиции на продажу
.
Возвращаем количество объектов в полученном списке. Если список получить не удалось, то возвращаем ноль.

Методы получения количества всех отложенных ордеров на счёте, ордеров на покупку и ордеров на продажу:

//+------------------------------------------------------------------+
//| Возвращает количество отложенных ордеров                         |
//+------------------------------------------------------------------+
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());
  }
//+------------------------------------------------------------------+
//| Возвращает количество отложенных ордеров  на покупку             |
//+------------------------------------------------------------------+
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());
  }
//+------------------------------------------------------------------+
//| Возвращает количество отложенных ордеров  на продажу             |
//+------------------------------------------------------------------+
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());
  }
//+------------------------------------------------------------------+

Эти три вспомогательных метода идентичны трём методам, рассмотренным выше. Только здесь мы фильтруем список по статусу "действующий отложенный ордер" и по направлению типа ордера на покупку или продажу.

Также, для определения некоторых ограничений, нам необходимо знать совокупный объём открытых позиций и выставленных отложенных ордеров.

Метод, возвращающий совокупный объём позиций на покупку:

//+------------------------------------------------------------------+
//| Возвращает совокупный объём позиций на покупку                   |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+

Здесь: получаем список всех открытых позиций и установленных ордеров,
фильтруем список по статусу ордера "рыночная позиция"
.
Полученный список фильтруем по типу позиции на покупку.
Если список пустой — возвращаем ноль.
В цикле по полученному списку получаем очередной объект-ордер и его объём добавляем к значению переменной vol.
По окончании цикла, возвращаем полученное значение в переменной vol.

Метод, возвращающий совокупный объём позиций на продажу:

//+------------------------------------------------------------------+
//| Возвращает совокупный объём позиций на продажу                   |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+

Метод идентичен предыдущему, за исключением фильтрации по типу позиций на продажу.

Методы, возвращающие совокупный объём установленных отложенных ордеров на покупку и на продажу:

//+------------------------------------------------------------------+
//| Возвращает совокупный объём ордеров на покупку                   |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+
//| Возвращает совокупный объём ордеров на продажу                   |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+

Методы идентичны рассмотренным методам совокупного объёма позиций. Но списки фильтруем по типу "рыночный отложенный ордер" и по направлению ордера либо на покупку, либо на продажу.

Метод, возвращающий направление ордера по типу торговой операции:

//+------------------------------------------------------------------+
//| Возвращает направление ордера по типу операции                   |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+

Если в метод передан тип торговой операции "закрытие встречным" или "модификация", то возвращаем -1, иначе — остаток от деления значения типа торговой операции на 2, что в итоге даст нам направление — либо 0 (ORDER_TYPE_BUY), либо 1 (ORDER_TYPE_SELL).

Метод проверки существования позиции по тикету:

//+------------------------------------------------------------------+
//| Проверяет наличие позиции по тикету                              |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+

Здесь: В метод передаётся тикет проверяемой позиции и наименование источника.
Получаем список всех открытых позиций и установленных ордеров,
фильтруем список по статусу ордера "рыночная позиция"
.
Устанавливаем списку флаг сортировки по тикету.
Полученный список фильтруем по тикету, переданному входным параметром.
Если в списке содержится один объект (позиция с искомым тикетом) — возвращаем true.
Иначе — сообщаем об отсутствии позиции и возвращаем false.

Метод проверки существования отложенного ордера по тикету:

//+------------------------------------------------------------------+
//| Проверяет наличие ордера по тикету                               |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+

Метод идентичен вышерассмотренному за исключением того, что список фильтруем по статусу "рыночный отложенный ордер".

Метод, устанавливающий торговому объекту заданный звук:

//+------------------------------------------------------------------+
//| Устанавливает торговому объекту нужный звук                      |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+

В метод передаётся режим установки звука (какому торговому событию будет принадлежать звук), тип ордера торгового события, для которого устанавливается звук, наименование звукового файла (звук, который будет присвоен торговому событию ордера или позиции) и указатель на торговый объект, в котором необходимо установить звук (для какого символа устанавливаются свои звуки торговых событий).
В зависимости от режима, переданного в метод, вызываются соответствующие методы установки звука торгового объекта.

Методы установки параметров торговых объектов символов, рассмотренные нами в прошлой статье, и временно реализованные в классе базового объекта библиотеки 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);

теперь перенесены в торговый класс и переделаны в классе CEngine (просто вызывают эти методы, расположенные здесь). Эти методы мы уже рассматривали ранее, и возвращаться к ним не будем — посмотреть их реализацию можно в прилагаемых в конце статьи файлах.

Метод, устанавливающий стандартные звуки торговому объекту:

//+------------------------------------------------------------------+
//| Устанавливает торговому объекту символа стандартные звуки        |
//+------------------------------------------------------------------+
void CTrading::SetSoundsStandart(const string symbol=NULL)
  {
   //--- Объявляем пустой объект-символ
   CSymbol *symbol_obj=NULL;
   //--- Если в качестве имени символа передан NULL - устанавливаем звуки для торговых объектов всех символов
   if(symbol==NULL)
     {
      //--- Получаем список символов
      CArrayObj *list=this.m_symbols.GetList();
      if(list==NULL || list.Total()==0)
         return;
      //--- В цикле по списку символов
      int total=list.Total();
      for(int i=0;i<total;i++)
        {
         //--- получаем очередной объект-символ
         symbol_obj=list.At(i);
         if(symbol_obj==NULL)
            continue;
         //--- получаем торговый объект символа
         CTradeObj *trade_obj=symbol_obj.GetTradeObj();
         if(trade_obj==NULL)
            continue;
         //--- устанавливаем торговому объекту стандартные звуки
         trade_obj.SetSoundsStandart();
        }
     }
   //--- Если передано имя символа
   else
     {
      //--- получаем торговый объект символа
      CTradeObj *trade_obj=this.GetTradeObjBySymbol(symbol,DFUN);
      if(trade_obj==NULL)
         return;
      //--- устанавливаем торговому объекту стандартные звуки
      trade_obj.SetSoundsStandart();
     }
  }
//+------------------------------------------------------------------+

Метод, устанавливающий торговому объекту звук заданного торгового события для заданного ордера:

//+------------------------------------------------------------------+
//| Устанавливает звук для указанного типа ордера/позиции и символа  |
//| Режим mode указывает для какого события устанавливается звук     |
//| (symbol=NULL) торговым объектам всех символов,                   |
//| (symbol!=NULL) торговому объекту указанного символа              |
//+------------------------------------------------------------------+
void CTrading::SetSound(const ENUM_MODE_SET_SOUND mode,const ENUM_ORDER_TYPE action,const string sound,const string symbol=NULL)
  {
   //--- Объявляем пустой объект-символ
   CSymbol *symbol_obj=NULL;
   //--- Если в качестве имени символа передан NULL - устанавливаем звук для торговых объектов всех символов
   if(symbol==NULL)
     {
      //--- Получаем список символов
      CArrayObj *list=this.m_symbols.GetList();
      if(list==NULL || list.Total()==0)
         return;
      //--- В цикле по списку символов
      int total=list.Total();
      for(int i=0;i<total;i++)
        {
         //--- получаем очередной объект-символ
         symbol_obj=list.At(i);
         if(symbol_obj==NULL)
            continue;
         //--- получаем торговый объект символа
         CTradeObj *trade_obj=symbol_obj.GetTradeObj();
         if(trade_obj==NULL)
            continue;
         //--- устанавливаем торговому объекту звук нужного события
         this.SetSoundByMode(mode,action,sound,trade_obj);
        }
     }
   //--- Если передано имя символа
   else
     {
      //--- получаем торговый объект символа
      CTradeObj *trade_obj=this.GetTradeObjBySymbol(symbol,DFUN);
      if(trade_obj==NULL)
         return;
      //--- устанавливаем торговому объекту звук нужного события
      this.SetSoundByMode(mode,action,sound,trade_obj);
     }
  }
//+------------------------------------------------------------------+

В обоих методах все действия расписаны в комментариях к коду.

Сегодня мы создаём для торговых операций методы первичной проверки ограничений для торговли. Что мы отнесём к этой категории? Это проверка достаточности средств для проведения торговой операции — ведь если средств недостаточно, то и смысла в попытке послать запрос нет никакого. Данный тип ограничения требует времени на его устранение — необходимо либо дождаться увеличения свободных средств естественным путём — запланированное закрытие позиции по ТС и получением прибыли (убытка) с высвобождением залоговых средств, требующихся на поддержание открытой позиции, либо принудительно закрыть убыточную позицию для возврата только залоговых средств, либо пополнить счёт. Здесь пока проще всего вернуть флаг невозможности выполнения торгового запроса.
И есть ещё ограничения для торговли — запрет на автоторговлю в терминале, запрет автоторговли для советника в его настройках, запрет автоторговли со стороны сервера или для конкретного символа, и ещё некоторые дополнительные факторы.
Вот это всё мы сегодня и сделаем для торгового класса.

Метод проверки достаточности средств, необходимых для проведения торговой операции:

//+------------------------------------------------------------------+
//| Проверка достаточности средств                                   |
//+------------------------------------------------------------------+
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();
   //--- Получаем тип маркет-ордера по типу торговой операции
   ENUM_ORDER_TYPE action=this.DirectionByActionType((ENUM_ACTION_TYPE)order_type);
   //--- Получаем размер свободных средств, которые останутся после выполнения торговой операции
   double money_free=
     (
      //--- Для MQL5 рассчитываем разницу между свободными средствами и средствами, требующимися на проведение торговой операции
      #ifdef __MQL5__  this.m_account.MarginFree()-this.m_account.MarginForAction(action,symbol_obj.Name(),volume,price)
      //--- Для MQL4 используем результат работы стандартной функции, возвращающей количество средств, которые останутся
      #else/*__MQL4__*/::AccountFreeMarginCheck(symbol_obj.Name(),order_type,volume) #endif 
     );
   //--- Если свободных средств не останется - сообщаем и возвращаем false
   if(money_free<=0 #ifdef __MQL4__ || ::GetLastError()==134 #endif )
     {
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
        {
         //--- создаём текст сообщения
         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())+")"
           );
         //--- выводим сообщение в журнал
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(source_method,CMessage::Text(MSG_LIB_TEXT_NOT_ENOUTH_MONEY_FOR),message);
        }
      return false;
     }
   //--- Проверка пройдена успешно
   return true;
  }
//+------------------------------------------------------------------+

Метод проверки ограничений для проведения торговых операций:

//+------------------------------------------------------------------+
//| Проверка ограничений для торговли                                |
//+------------------------------------------------------------------+
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)
  {
//--- результат проведения всех проверок
   bool res=true;
//--- Очищаем список ошибок (кодов найденных ограничений)
   this.m_list_errors.Clear();
   this.m_list_errors.Sort();

//--- Проверяем связь с торговым сервером (не в режиме тестирования)
   if(!::TerminalInfoInteger(TERMINAL_CONNECTED))
     {
      if(!::MQLInfoInteger(MQL_TESTER))
        {
         //--- добавляем код ошибки в список и записываем в результат false
         this.AddErrorCodeToList(MSG_LIB_TEXT_TERMINAL_NOT_CONNECTED);
         res &=false;
        }
     }
//--- Проверяем разрешение торговли для данного счета (при наличии связи с торговым сервером)
   else if(!this.m_account.TradeAllowed())
     {
      //--- добавляем код ошибки в список и записываем в результат false
      this.AddErrorCodeToList(MSG_LIB_TEXT_ACCOUNT_NOT_TRADE_ENABLED);
      res &=false;
     }
//--- Проверяем разрешение на торговлю любым экспертам/скриптам для данного счета
   if(!this.m_account.TradeExpert())
     {
      //--- добавляем код ошибки в список и записываем в результат false
      this.AddErrorCodeToList(MSG_LIB_TEXT_ACCOUNT_EA_NOT_TRADE_ENABLED);
      res &=false;
     }
//--- Проверяем разрешение автоторговли в терминале.
//--- Кнопка "Авто-торговля" (Настройки --> Советники --> Флажок "Разрешить автоматическую торговлю")
   if(!::TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
     {
      //--- добавляем код ошибки в список и записываем в результат false
      this.AddErrorCodeToList(MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED);
      res &=false;
     }
//--- Проверяем разрешение автоторговли для текущего эксперта.
//--- (F7 --> Общие --> Флажок "Разрешить автоматическую торговлю")
   if(!::MQLInfoInteger(MQL_TRADE_ALLOWED))
     {
      //--- добавляем код ошибки в список и записываем в результат false
      this.AddErrorCodeToList(MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED);
      res &=false;
     }
//--- Проверяем разрешение торговли на символе.
//--- Если торговля запрещена - добавляем код ошибки в список и записываем в результат false
   if(symbol_obj.TradeMode()==SYMBOL_TRADE_MODE_DISABLED)
     {
      this.AddErrorCodeToList(MSG_SYM_TRADE_MODE_DISABLED);
      res &=false;
     }

//--- Если не закрытие/удаление/модификация
   if(action_type>WRONG_VALUE && action_type<ACTION_TYPE_CLOSE_BY)
     {
      //--- Если разрешены только операции закрытия позиций - добавляем код ошибки в список и записываем в результат false
      if(symbol_obj.TradeMode()==SYMBOL_TRADE_MODE_CLOSEONLY)
        {
         this.AddErrorCodeToList(MSG_SYM_TRADE_MODE_CLOSEONLY);
         res &=false;
        }
      //--- Проверка минимального объёма
      if(volume<symbol_obj.LotsMin())
        {
         //--- Объём в запросе меньше минимально-допустимого
         //--- добавляем код ошибки в список и записываем в результат false
         this.AddErrorCodeToList(MSG_LIB_TEXT_REQ_VOL_LESS_MIN_VOLUME);
         res &=false;
        }
      //--- Проверка максимального объёма
      else if(volume>symbol_obj.LotsMax())
        {
         //--- Объём в запросе больше максимально-допустимого
         //--- добавляем код ошибки в список и записываем в результат false
         this.AddErrorCodeToList(MSG_LIB_TEXT_REQ_VOL_MORE_MAX_VOLUME);
         res &=false;
        }
      //--- Проверка минимальной градации объема
      double step=symbol_obj.LotsStep();
      if(fabs((int)round(volume/step)*step-volume)>0.0000001)
        {
         //--- Объём в запросе не кратен минимальной градации шага изменения лота
         //--- добавляем код ошибки в список и записываем в результат false
         this.AddErrorCodeToList(MSG_LIB_TEXT_INVALID_VOLUME_STEP);
         res &=false;
        }
     }

//--- Если открытие позиции
   if(action_type>WRONG_VALUE && action_type<ACTION_TYPE_BUY_LIMIT)
     {
      //--- Проверяем разрешение отправки маркет-ордеров на символе.
      //--- Если торговля маркет-ордерами запрещена - добавляем код ошибки в список и записываем в результат false
      if(!symbol_obj.IsMarketOrdersAllowed())
        {
         this.AddErrorCodeToList(MSG_SYM_MARKET_ORDER_DISABLED);
         res &=false;
        }
     }
//--- Если установка отложенного ордера
   else if(action_type>ACTION_TYPE_SELL && action_type<ACTION_TYPE_CLOSE_BY)
     {
      //--- Если есть ограничение на количество отложенных ордеров на счёте,
      //--- и выставление нового ордера превысит допустимое количество
      if(this.m_account.LimitOrders()>0 && this.OrdersTotalAll()+1 > this.m_account.LimitOrders())
        {
         //--- Достигнут лимит на количество отложенных ордеров
         //--- добавляем код ошибки в список и записываем в результат false
         this.AddErrorCodeToList(10033);
         res &=false;
        }  
      //--- Проверяем разрешение установки лимит-ордеров на символе.
      if(action_type==ACTION_TYPE_BUY_LIMIT || action_type==ACTION_TYPE_SELL_LIMIT)
        {
         //--- Если установка лимит-ордеров запрещена - добавляем код ошибки в список и записываем в результат false
         if(!symbol_obj.IsLimitOrdersAllowed())
           {
            this.AddErrorCodeToList(MSG_SYM_LIMIT_ORDER_DISABLED);
            res &=false;
           }
        }
      //--- Проверяем разрешение установки стоп-ордеров на символе.
      else if(action_type==ACTION_TYPE_BUY_STOP || action_type==ACTION_TYPE_SELL_STOP)
        {
         //--- Если установка стоп-ордеров запрещена - добавляем код ошибки в список и записываем в результат false
         if(!symbol_obj.IsStopOrdersAllowed())
           {
            this.AddErrorCodeToList(MSG_SYM_STOP_ORDER_DISABLED);
            res &=false;
           }
        }
      //--- Для MQL5 Проверяем разрешение установки стоп-лимит-ордеров на символе.
      #ifdef __MQL5__
      else if(action_type==ACTION_TYPE_BUY_STOP_LIMIT || action_type==ACTION_TYPE_SELL_STOP_LIMIT)
        {
         //--- Если установка стоп-лимит-ордеров запрещена - добавляем код ошибки в список и записываем в результат false
         if(!symbol_obj.IsStopLimitOrdersAllowed())
           {
            this.AddErrorCodeToList(MSG_SYM_STOP_LIMIT_ORDER_DISABLED);
            res &=false;
           }
        }
      #endif 
     }

//--- Если открытие/установка/модификация
   if(action_type>WRONG_VALUE && action_type!=ACTION_TYPE_CLOSE_BY)
     {
      //--- Если не модификация
      if(action_type!=ACTION_TYPE_MODIFY)
        {
         //--- Если покупка: проверяем разрешение торговли в long на символе
         if(this.DirectionByActionType(action_type)==ORDER_TYPE_BUY)
           {
            //--- Если разрешены только продажи - добавляем код ошибки в список и записываем в результат false
            if(symbol_obj.TradeMode()==SYMBOL_TRADE_MODE_SHORTONLY)
              {
               this.AddErrorCodeToList(MSG_SYM_TRADE_MODE_SHORTONLY);
               res &=false;
              }
            //--- Если для символа есть ограничение на совокупный объем открытой позиции и отложенных ордеров в одном направлении   
            if(symbol_obj.VolumeLimit()>0)
              {
               //--- (Если совокупный объём установленных long-ордеров и открытых long-позиций)+открываемый объём превышают максимальный
               if(this.OrdersTotalVolumeLong()+this.PositionsTotalVolumeLong()+volume > symbol_obj.VolumeLimit())
                 {
                  //--- Превышен максимальный совокупный объём ордеров и позиций в одном направлении
                  //--- добавляем код ошибки в список и записываем в результат false
                  this.AddErrorCodeToList(MSG_LIB_TEXT_MAX_VOLUME_LIMIT_EXCEEDED);
                  res &=false;
                 }
              }
           }
         //--- Если продажа: проверяем разрешение торговли в short на символе
         else if(this.DirectionByActionType(action_type)==ORDER_TYPE_SELL)
           {
            //--- Если разрешены только покупки - добавляем код ошибки в список и записываем в результат false
            if(symbol_obj.TradeMode()==SYMBOL_TRADE_MODE_LONGONLY)
              {
               this.AddErrorCodeToList(MSG_SYM_TRADE_MODE_LONGONLY);
               res &=false;
              }
            //--- Если для символа есть ограничение на совокупный объем открытой позиции и отложенных ордеров в одном направлении   
            if(symbol_obj.VolumeLimit()>0)
              {
               //--- (Если совокупный объём установленных short-ордеров и открытых short-позиций)+открываемый объём превышают максимальный
               if(this.OrdersTotalVolumeShort()+this.PositionsTotalVolumeShort()+volume > symbol_obj.VolumeLimit())
                 {
                  //--- Превышен максимальный совокупный объём ордеров и позиций в одном направлении
                  //--- добавляем код ошибки в список и записываем в результат false
                  this.AddErrorCodeToList(MSG_LIB_TEXT_MAX_VOLUME_LIMIT_EXCEEDED);
                  res &=false;
                 }
              }
           }
        }
      //--- Если в запросе есть StopLoss и не разрешена его установка
      if(sl>0 && !symbol_obj.IsStopLossOrdersAllowed())
        {
         //--- добавляем код ошибки в список и записываем в результат false
         this.AddErrorCodeToList(MSG_SYM_SL_ORDER_DISABLED);
         res &=false;
        }
      //--- Если в запросе есть TakeProfit и не разрешена его установка
      if(tp>0 && !symbol_obj.IsTakeProfitOrdersAllowed())
        {
         //--- добавляем код ошибки в список и записываем в результат false
         this.AddErrorCodeToList(MSG_SYM_TP_ORDER_DISABLED);
         res &=false;
        }
     }

//--- Если закрытие встречным
   else if(action_type==ACTION_TYPE_CLOSE_BY)
     {
      //--- Если закрытие встречным не разрешено
      if(!symbol_obj.IsCloseByOrdersAllowed())
        {
         //--- добавляем код ошибки в список и записываем в результат false
         this.AddErrorCodeToList(MSG_LIB_TEXT_CLOSE_BY_ORDERS_DISABLED);
         res &=false;
        }
     }

//--- Если есть ограничения, выводим заголовок и список ошибок
   if(!res)
     {
      //--- Запрос отклонён до отправки на сервер по причине:
      int total=this.m_list_errors.Total();
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
        {
         //--- Для MQL5 сначала выводится заголовок списка, затем список ошибок
         #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)));
         //--- Для MQL4, так как в журнал выводится всё в обратном порядке, сначала выводится список ошибок, а затем заголовок списка
         #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;
  }
//+------------------------------------------------------------------+

Метод достаточно ёмкий, но всё тут однообразно — проверяем свойства программы, терминала, аккаунта или символа, по которым возможны ограничения, и если ограничение существует, то добавляем код найденного ограничения в список, и к флагу результата добавляем false. По окончании всех проверок, и если в переменной, хранящей результат, содержится false, то выводим заголовок списка найденных ограничений, и в цикле по списку кодов ограничений выводим под заголовком все найденные ограничения для торговли, иначе — если в переменной, хранящей результат проверок содержится true, которым эта переменная изначально была инициализирована — значит все проверки пройдены — возвращаем true.

В данной версии торгового класса мы этим ограничимся. Далее, при создании методов обработки ошибок, все действия по реакции на ограничения и ошибки будут нами обрабатываться в этом классе.

Торговые методы класса:

//+------------------------------------------------------------------+
//| Открывает позицию Buy                                            |
//+------------------------------------------------------------------+
bool CTrading::OpenBuy(const double volume,const string symbol,const ulong magic=ULONG_MAX,double sl=0,double tp=0,const string comment=NULL)
  {
//--- Получаем объект-символ по имени символа
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
   //--- Если не удалось получить объект-символ - выводим сообщение и возвращаем 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;
     }
//--- Обновляем котировки по символу
   symbol_obj.RefreshRates();
//--- Если есть ограничения по разрешённости торговли - сообщаем и уходим
   if(!this.CheckTradeConstraints(volume,ACTION_TYPE_BUY,symbol_obj,DFUN,sl,tp))
     {
      return false;
     }
//--- Если не хватает средств - сообщаем и уходим
   if(!this.CheckMoneyFree(ORDER_TYPE_BUY,volume,symbol_obj.Ask(),symbol_obj,DFUN))
     {
      return false;
     }

//--- получаем торговый объект из объекта-символа
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Ошибка. Не удалось получить торговый объект
      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 trade_obj.OpenPosition(POSITION_TYPE_BUY,volume,sl,tp,magic,trade_obj.GetDeviation(),comment);
  }
//+------------------------------------------------------------------+
//| Открывает позицию Sell                                           |
//+------------------------------------------------------------------+
bool CTrading::OpenSell(const double volume,const string symbol,const ulong magic=ULONG_MAX,double sl=0,double tp=0,const string comment=NULL)
  {
//--- Получаем объект-символ по имени символа
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
   //--- Если не удалось получить объект-символ - выводим сообщение и возвращаем 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;
     }
//--- Обновляем котировки по символу
   symbol_obj.RefreshRates();
//--- Если есть ограничения по разрешённости торговли - сообщаем и уходим
   if(!this.CheckTradeConstraints(volume,ACTION_TYPE_SELL,symbol_obj,DFUN,sl,tp))
     {
      return false;
     }
   //--- Если не хватает средств - сообщаем и уходим
   if(!this.CheckMoneyFree(ORDER_TYPE_SELL,volume,symbol_obj.Bid(),symbol_obj,DFUN))
     {
      return false;
     }
//--- получаем торговый объект из объекта-символа
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Ошибка. Не удалось получить торговый объект
      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 trade_obj.OpenPosition(POSITION_TYPE_SELL,volume,sl,tp,magic,trade_obj.GetDeviation(),comment);
  }
//+------------------------------------------------------------------+
//| Модифицирует позицию                                             |
//+------------------------------------------------------------------+
bool CTrading::ModifyPosition(const ulong ticket,const double sl=WRONG_VALUE,const double tp=WRONG_VALUE)
  {
//--- Получаем объект-символ по тикету позиции
   CSymbol *symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN);
   //--- Если не удалось получить объект-символ - выводим сообщение и возвращаем 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;
     }
//--- Обновляем котировки по символу
   symbol_obj.RefreshRates();
//--- Если есть ограничения по разрешённости торговли - сообщаем и уходим
   if(!this.CheckTradeConstraints(0,ACTION_TYPE_MODIFY,symbol_obj,DFUN,sl,tp))
     {
      return false;
     }
//--- получаем торговый объект из объекта-символа
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Ошибка. Не удалось получить торговый объект
      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 trade_obj.ModifyPosition(ticket,sl,tp);
  }
//+------------------------------------------------------------------+
//| Закрывает позицию полностью                                      |
//+------------------------------------------------------------------+
bool CTrading::ClosePosition(const ulong ticket)
  {
//--- Получаем объект-символ по тикету позиции
   CSymbol *symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN);
   //--- Если не удалось получить объект-символ - выводим сообщение и возвращаем 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;
     }
//--- Обновляем котировки по символу
   symbol_obj.RefreshRates();
//--- Если есть ограничения по разрешённости торговли - сообщаем и уходим
   if(!this.CheckTradeConstraints(0,WRONG_VALUE,symbol_obj,DFUN))
     {
      return false;
     }
//--- получаем торговый объект из объекта-символа
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Ошибка. Не удалось получить торговый объект
      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 trade_obj.ClosePosition(ticket);
  }
//+------------------------------------------------------------------+
//| Закрывает позицию частично                                       |
//+------------------------------------------------------------------+
bool CTrading::ClosePositionPartially(const ulong ticket,const double volume)
  {
//--- Получаем объект-символ по тикету позиции
   CSymbol *symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN);
   //--- Если не удалось получить объект-символ - выводим сообщение и возвращаем 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;
     }
//--- Обновляем котировки по символу
   symbol_obj.RefreshRates();
//--- Если есть ограничения по разрешённости торговли - сообщаем и уходим
   if(!this.CheckTradeConstraints(0,WRONG_VALUE,symbol_obj,DFUN))
     {
      return false;
     }
//--- получаем торговый объект из объекта-символа
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Ошибка. Не удалось получить торговый объект
      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 trade_obj.ClosePositionPartially(ticket,symbol_obj.NormalizedLot(volume));
  }
//+------------------------------------------------------------------+
//| Закрывает позицию встречной                                      |
//+------------------------------------------------------------------+
bool CTrading::ClosePositionBy(const ulong ticket,const ulong ticket_by)
  {
//--- Получаем объект-символ по тикету позиции
   CSymbol *symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN);
   //--- Если не удалось получить объект-символ - выводим сообщение и возвращаем 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;
     }
//--- Обновляем котировки по символу
   symbol_obj.RefreshRates();
//--- Если есть ограничения по разрешённости торговли - сообщаем и уходим
   if(!this.CheckTradeConstraints(0,ACTION_TYPE_CLOSE_BY,symbol_obj,DFUN))
     {
      return false;
     }
   //--- торговый объект закрываемой позиции
   CTradeObj *trade_obj_pos=this.GetTradeObjByPosition(ticket,DFUN);
   if(trade_obj_pos==NULL)
     {
      //--- Ошибка. Не удалось получить торговый объект
      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(!this.CheckPositionAvailablity(ticket_by,DFUN))
      return false;
   //--- торговый объект встречной позиции
   CTradeObj *trade_obj_pos_by=this.GetTradeObjByPosition(ticket_by,DFUN);
   if(trade_obj_pos_by==NULL)
     {
      //--- Ошибка. Не удалось получить торговый объект
      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(symbol_obj.Name()!=trade_obj_pos_by.GetSymbol())
     {
      //--- Символы встречных позиций не равны
      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 trade_obj_pos.ClosePositionBy(ticket,ticket_by);
  }
//+------------------------------------------------------------------+
//| Устанавливает отложенный ордер BuyStop                           |
//+------------------------------------------------------------------+
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)
  {
//--- Получаем объект-символ по имени символа
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
   //--- Если не удалось получить объект-символ - выводим сообщение и возвращаем 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;
     }
//--- Обновляем котировки по символу
   symbol_obj.RefreshRates();
//--- Если есть ограничения по разрешённости торговли - сообщаем и уходим
   if(!this.CheckTradeConstraints(volume,ACTION_TYPE_BUY_STOP,symbol_obj,DFUN,sl,tp))
     {
      return false;
     }
   //--- получаем торговый объект из объекта-символа
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Ошибка. Не удалось получить торговый объект
      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 trade_obj.SetOrder(ORDER_TYPE_BUY_STOP,volume,price,sl,tp,0,magic,expiration,type_time,comment);
  }
//+------------------------------------------------------------------+
//| Устанавливает отложенный ордер BuyLimit                          |
//+------------------------------------------------------------------+
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)
  {
//--- Получаем объект-символ по имени символа
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
   //--- Если не удалось получить объект-символ - выводим сообщение и возвращаем 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;
     }
//--- Обновляем котировки по символу
   symbol_obj.RefreshRates();
//--- Если есть ограничения по разрешённости торговли - сообщаем и уходим
   if(!this.CheckTradeConstraints(volume,ACTION_TYPE_BUY_LIMIT,symbol_obj,DFUN,sl,tp))
     {
      return false;
     }
   //--- получаем торговый объект из объекта-символа
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Ошибка. Не удалось получить торговый объект
      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 trade_obj.SetOrder(ORDER_TYPE_BUY_LIMIT,volume,price,sl,tp,0,magic,expiration,type_time,comment);
  }
//+------------------------------------------------------------------+
//| Устанавливает отложенный ордер BuyStopLimit                      |
//+------------------------------------------------------------------+
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)
  {
//--- Получаем объект-символ по имени символа
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
   //--- Если не удалось получить объект-символ - выводим сообщение и возвращаем 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;
     }
//--- Обновляем котировки по символу
   symbol_obj.RefreshRates();
//--- Если есть ограничения по разрешённости торговли - сообщаем и уходим
   if(!this.CheckTradeConstraints(volume,ACTION_TYPE_BUY_STOP_LIMIT,symbol_obj,DFUN,sl,tp))
     {
      return false;
     }
   #ifdef __MQL5__
      //--- получаем торговый объект из объекта-символа
      CTradeObj *trade_obj=symbol_obj.GetTradeObj();
      if(trade_obj==NULL)
        {
         //--- Ошибка. Не удалось получить торговый объект
         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 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 
  }
//+------------------------------------------------------------------+
//| Устанавливает отложенный ордер SellStop                          |
//+------------------------------------------------------------------+
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)
  {
//--- Получаем объект-символ по имени символа
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
   //--- Если не удалось получить объект-символ - выводим сообщение и возвращаем 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;
     }
//--- Обновляем котировки по символу
   symbol_obj.RefreshRates();
//--- Если есть ограничения по разрешённости торговли - сообщаем и уходим
   if(!this.CheckTradeConstraints(volume,ACTION_TYPE_SELL_STOP,symbol_obj,DFUN,sl,tp))
     {
      return false;
     }
   //--- получаем торговый объект из объекта-символа
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Ошибка. Не удалось получить торговый объект
      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 trade_obj.SetOrder(ORDER_TYPE_SELL_STOP,volume,price,sl,tp,0,magic,expiration,type_time,comment);
  }
//+------------------------------------------------------------------+
//| Устанавливает отложенный ордер SellLimit                         |
//+------------------------------------------------------------------+
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)
  {
//--- Получаем объект-символ по имени символа
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
   //--- Если не удалось получить объект-символ - выводим сообщение и возвращаем 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;
     }
//--- Обновляем котировки по символу
   symbol_obj.RefreshRates();
//--- Если есть ограничения по разрешённости торговли - сообщаем и уходим
   if(!this.CheckTradeConstraints(volume,ACTION_TYPE_SELL_LIMIT,symbol_obj,DFUN,sl,tp))
     {
      return false;
     }
   //--- получаем торговый объект из объекта-символа
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Ошибка. Не удалось получить торговый объект
      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 trade_obj.SetOrder(ORDER_TYPE_SELL_LIMIT,volume,price,sl,tp,0,magic,expiration,type_time,comment);
  }
//+------------------------------------------------------------------+
//| Устанавливает отложенный ордер SellStopLimit                     |
//+------------------------------------------------------------------+
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)
  {
//--- Получаем объект-символ по имени символа
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
   //--- Если не удалось получить объект-символ - выводим сообщение и возвращаем 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;
     }
//--- Обновляем котировки по символу
   symbol_obj.RefreshRates();
//--- Если есть ограничения по разрешённости торговли - сообщаем и уходим
   if(!this.CheckTradeConstraints(volume,ACTION_TYPE_SELL_STOP_LIMIT,symbol_obj,DFUN,sl,tp))
     {
      return false;
     }
   #ifdef __MQL5__
      //--- получаем торговый объект из объекта-символа
      CTradeObj *trade_obj=symbol_obj.GetTradeObj();
      if(trade_obj==NULL)
        {
         //--- Ошибка. Не удалось получить торговый объект
         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 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 
  }
//+------------------------------------------------------------------+
//| Модифицирует отложенный ордер                                    |
//+------------------------------------------------------------------+
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)
  {
//--- Получаем объект-символ по тикету ордера
   CSymbol *symbol_obj=this.GetSymbolObjByOrder(ticket,DFUN);
   //--- Если не удалось получить объект-символ - выводим сообщение и возвращаем 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;
     }
//--- Обновляем котировки по символу
   symbol_obj.RefreshRates();
//--- Если есть ограничения по разрешённости торговли - сообщаем и уходим
   if(!this.CheckTradeConstraints(0,ACTION_TYPE_MODIFY,symbol_obj,DFUN,sl,tp))
     {
      return false;
     }
   //--- получаем торговый объект из объекта-символа
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Ошибка. Не удалось получить торговый объект
      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 trade_obj.ModifyOrder(ticket,price,sl,tp,stoplimit,expiration,type_time);
  }
//+------------------------------------------------------------------+
//| Удаляет отложенный ордер                                         |
//+------------------------------------------------------------------+
bool CTrading::DeleteOrder(const ulong ticket)
  {
//--- Получаем объект-символ по тикету ордера
   CSymbol *symbol_obj=this.GetSymbolObjByOrder(ticket,DFUN);
   //--- Если не удалось получить объект-символ - выводим сообщение и возвращаем 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;
     }
//--- Обновляем котировки по символу
   symbol_obj.RefreshRates();
//--- Если есть ограничения по разрешённости торговли - сообщаем и уходим
   if(!this.CheckTradeConstraints(0,WRONG_VALUE,symbol_obj,DFUN))
     {
      return false;
     }
   //--- получаем торговый объект из объекта-символа
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      //--- Ошибка. Не удалось получить торговый объект
      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 trade_obj.DeleteOrder(ticket);
  }
//+------------------------------------------------------------------+

Непосредственно торговые методы — отправку торговых запросов на сервер — мы рассматривали в прошлой статье при создании базового торгового объекта. Здесь же в методы, имеющие сходную сигнатуру, передаются необходимые параметры торгового запроса, проверяются ограничения для торговли, рассмотренные нами выше, и вызывается соответствующий метод базового торгового объекта символа. Результат работы вызванного метода возвращается в программу.

Пока — на данном этапе, это все проверки, которые проводятся перед отправкой торгового запроса. Далее мы будем их, естественно, расширять. Ведь нам необходимо проверять и обрабатывать корректность параметров торгового запроса. Сейчас же подразумевается, что все параметры уже корректны.

Торговый класс в текущей его реализации с запланированным функционалом готов.
Теперь нам необходимо получить к нему доступ их базового объекта библиотеки CEngine, и через него уже работать с торговыми методами класса.

Откроем файл \MQL5\Include\DoEasy\Engine.mqh и внесём в него все необходимые доработки.

В первую очередь подключим к нему файл торгового класса:

//+------------------------------------------------------------------+
//|                                                       Engine.mqh |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#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"
//+------------------------------------------------------------------+

И в приватной секции класса объявим объект торгового класса:

//+------------------------------------------------------------------+
//| Класс-основа библиотеки                                          |
//+------------------------------------------------------------------+
class CEngine
  {
private:
   CHistoryCollection   m_history;                       // Коллекция исторических ордеров и сделок
   CMarketCollection    m_market;                        // Коллекция рыночных ордеров и сделок
   CEventsCollection    m_events;                        // Коллекция событий
   CAccountsCollection  m_accounts;                      // Коллекция аккаунтов
   CSymbolsCollection   m_symbols;                       // Коллекция символов
   CResourceCollection  m_resource;                      // Список ресурсов
   CTrading             m_trading;                       // Объект торгового класса
   CArrayObj            m_list_counters;                 // Список счётчиков таймера
   int                  m_global_error;                  // Код глобальной ошибки
   bool                 m_first_start;                   // Флаг первого запуска
   bool                 m_is_hedge;                      // Флаг хедж-счёта
   bool                 m_is_tester;                     // Флаг работы в тестере
   bool                 m_is_market_trade_event;         // Флаг торгового события на счёте
   bool                 m_is_history_trade_event;        // Флаг торгового события в истории счёта
   bool                 m_is_account_event;              // Флаг события изменения аккаунта
   bool                 m_is_symbol_event;               // Флаг события изменения свойств символа
   ENUM_TRADE_EVENT     m_last_trade_event;              // Последнее торговое событие на счёте
   int                  m_last_account_event;            // Последнее событие в свойствах счёта
   int                  m_last_symbol_event;             // Последнее событие в свойствах символа
//--- Возвращает индекс счётчика по id

Методы

//--- Устанавливает для торговых классов:
//--- (1) корректное значение политики исполнения, (2) значение политики исполнения,
//--- (3) корректный тип истечения ордера, (4) тип истечения ордера,
//--- (5) магик, (6) Комментарий, (7) размер проскальзывания, (8) объём, (9) срок истечения ордера,
//--- (10) флаг асинхронной отправки торгового запроса, (11) уровень логирования
   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);

переименуем в

//--- Устанавливает для торговых классов:
//--- (1) корректное значение политики исполнения, (2) значение политики исполнения,
//--- (3) корректный тип истечения ордера, (4) тип истечения ордера,
//--- (5) магик, (6) Комментарий, (7) размер проскальзывания, (8) объём, (9) срок истечения ордера,
//--- (10) флаг асинхронной отправки торгового запроса, (11) уровень логирования
   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);

Ну просто чтобы их наименование указывало на принадлежность к торговому классу.

В публичную секцию класса добавим методы для установки стандартных звуков, звуков для указанного типа позиции/ордера и торгового события, и метод, отправляющий в торговый класс указатели на все необходимые для его работы списки коллекций, а также объявим метод для воспроизведения звука по его описанию:

//--- Устанавливает стандартные звуки (symbol==NULL) торговому объекту символа, (symbol!=NULL) торговым объектам всех символов
   void                 SetSoundsStandart(const string symbol=NULL)
                          {
                           this.m_trading.SetSoundsStandart(symbol);
                          }

//--- Устанавливает звук для указанного типа ордера/позиции и символа. Режим mode указывает для какого события устанавливается звук
//--- (symbol=NULL) торговым объектам всех символов, (symbol!=NULL) торговому объекту указанного символа
   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);
                          }
//--- Воспроизводит звук по его описанию
   bool                 PlaySoundByDescription(const string sound_description);

//--- Передаёт в торговый класс указатели на все необходимые коллекции
   void                 TradingOnInit(void)
                          {
                           this.m_trading.OnInit(this.GetAccountCurrent(),m_symbols.GetObject(),m_market.GetObject(),m_history.GetObject());
                          }

Три метода просто вызывают одноимённые методы торгового класса, а метод воспроизведения звука по его описанию рассмотрим ниже:

//+------------------------------------------------------------------+
//| Воспроизводит звук по его описанию                               |
//+------------------------------------------------------------------+
bool CEngine::PlaySoundByDescription(const string sound_description)
  {
   string file_name=NULL;
   //--- Получим список ресурсов
   CArrayObj* list=this.GetListResource();
   if(list==NULL)
      return false;
   //--- Получим индекс объекта-ресурса по его описанию
   int index=this.m_resource.GetIndexResObjByDescription(sound_description);
   //--- Если объект-ресурс с заданным описанием найден в списке
   if(index>WRONG_VALUE)
     {
      //--- Получим объект-ресурс по его индексу из списка
      CResObj *res_obj=list.At(index);
      if(res_obj==NULL)
         return false;
      //--- Получим имя файла объекта-ресурса
      file_name=res_obj.FileName();
     }
   //--- Если объекта-ресурса с заданным описанием нет в списке, то попробуем воспроизвести файл по имени, записанному в его описании
   //--- Для этого проверим что в качестве описания передан либо стандартный звуковой файл (макроподстановка его имени),
   //--- либо в качестве описания передано имя нового звукового файла c расширением *.wav
   else if(::StringFind(sound_description,"SND_")==0 || StringSubstr(sound_description,StringLen(sound_description)-4)==".wav")
      file_name=sound_description;
   //--- Возвращаем результат воспроизведения файла
   return(file_name!=NULL ? CMessage::PlaySound(file_name) : false);
  }
//+------------------------------------------------------------------+

Ранее мы создавали объекты-ресурсы, в которых могли хранить звуковые файлы и файлы изображений. К каждому такому ресурсу мы сделали возможность добавления описания. Таким образом нам становится просто указать какой звуковой файл нам нужно воспроизвести. Например, гораздо проще помнить своё описание файла, чем его имя. Если имя у файла "безликое", допустим sound_01.wav, то описание к нему мы можем задать любым, например "звук открытия позиции Buy на EURUSD".
Данный метод как раз позволяет нам указать в его параметрах нужное описание файла. Метод найдёт объект-ресурс с таким описанием и воспроизведёт звук. Опционально метод имеет возможность воспроизведения стандартных звуков по макроподстановкам их имён, созданных нами в Defines.mqh, а также любого неизвестного звукового файла — достаточно передать его имя в качестве его описания. Главное, чтобы такой файл находился в песочнице терминала, имел разширение wav, и в имени был правильный к нему путь.

Торговые методы, которые в прошлой статье мы временно размещали в классе CEngine, а также методы, устанавливающие параметры торгового объекта, и также временно размещённые в CEngine, теперь претерпели изменения — все эти методы, их реализация, перенесены в торговый класс,
а из методов класса CEngine просто вызываются соответствующие методы торгового класса:

//+------------------------------------------------------------------+
//| Открывает позицию Buy                                            |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Открывает позицию Sell                                           |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Модифицирует позицию                                             |
//+------------------------------------------------------------------+
bool CEngine::ModifyPosition(const ulong ticket,const double sl=WRONG_VALUE,const double tp=WRONG_VALUE)
  {
   return this.m_trading.ModifyPosition(ticket,sl,tp);
  }
//+------------------------------------------------------------------+
//| Закрывает позицию полностью                                      |
//+------------------------------------------------------------------+
bool CEngine::ClosePosition(const ulong ticket)
  {
   return this.m_trading.ClosePosition(ticket);
  }
//+------------------------------------------------------------------+
//| Закрывает позицию частично                                       |
//+------------------------------------------------------------------+
bool CEngine::ClosePositionPartially(const ulong ticket,const double volume)
  {
   return this.m_trading.ClosePositionPartially(ticket,volume);
  }

//+------------------------------------------------------------------+
//| Закрывает позицию встречной                                      |
//+------------------------------------------------------------------+
bool CEngine::ClosePositionBy(const ulong ticket,const ulong ticket_by)
  {
   return this.m_trading.ClosePositionBy(ticket,ticket_by);
  }
//+------------------------------------------------------------------+
//| Устанавливает отложенный ордер BuyStop                           |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Устанавливает отложенный ордер BuyLimit                          |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Устанавливает отложенный ордер BuyStopLimit                      |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Устанавливает отложенный ордер SellStop                          |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Устанавливает отложенный ордер SellLimit                         |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Устанавливает отложенный ордер SellStopLimit                     |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Модифицирует отложенный ордер                                    |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Удаляет отложенный ордер                                         |
//+------------------------------------------------------------------+
bool CEngine::DeleteOrder(const ulong ticket)
  {
   return this.m_trading.DeleteOrder(ticket);
  }
//+------------------------------------------------------------------+
//| Устанавливает корректную политику исполнения                     |
//| для торговых объектов всех символов                              |
//+------------------------------------------------------------------+
void CEngine::TradingSetCorrectTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL)
  {
   this.m_trading.SetCorrectTypeFilling(type,symbol_name);
  }
//+------------------------------------------------------------------+
//| Устанавливает политику исполнения                                |
//| для торговых объектов всех символов                              |
//+------------------------------------------------------------------+
void CEngine::TradingSetTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL)
  {
   this.m_trading.SetTypeFilling(type,symbol_name);
  }
//+------------------------------------------------------------------+
//| Устанавливает корректный тип истечения ордера                    |
//| для торговых объектов всех символов                              |
//+------------------------------------------------------------------+
void CEngine::TradingSetCorrectTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL)
  {
   this.m_trading.SetCorrectTypeExpiration(type,symbol_name);
  }
//+------------------------------------------------------------------+
//| Устанавливает тип истечения ордера                               |
//| для торговых объектов всех символов                              |
//+------------------------------------------------------------------+
void CEngine::TradingSetTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL)
  {
   this.m_trading.SetTypeExpiration(type,symbol_name);
  }
//+------------------------------------------------------------------+
//| Устанавливает магик для торговых объектов всех символов          |
//+------------------------------------------------------------------+
void CEngine::TradingSetMagic(const ulong magic,const string symbol_name=NULL)
  {
   this.m_trading.SetMagic(magic,symbol_name);
  }
//+------------------------------------------------------------------+
//| Устанавливает комментарий для торговых объектов всех символов    |
//+------------------------------------------------------------------+
void CEngine::TradingSetComment(const string comment,const string symbol_name=NULL)
  {
   this.m_trading.SetComment(comment,symbol_name);
  }

//+------------------------------------------------------------------+
//| Устанавливает размер проскальзывания                             |
//| для торговых объектов всех символов                              |
//+------------------------------------------------------------------+
void CEngine::TradingSetDeviation(const ulong deviation,const string symbol_name=NULL)
  {
   this.m_trading.SetDeviation(deviation,symbol_name);
  }
//+------------------------------------------------------------------+
//| Устанавливает объём для торговых объектов всех символов          |
//+------------------------------------------------------------------+
void CEngine::TradingSetVolume(const double volume=0,const string symbol_name=NULL)
  {
   this.m_trading.SetVolume(volume,symbol_name);
  }
//+------------------------------------------------------------------+
//| Устанавливает срок истечения ордера                              |
//| для торговых объектов всех символов                              |
//+------------------------------------------------------------------+
void CEngine::TradingSetExpiration(const datetime expiration=0,const string symbol_name=NULL)
  {
   this.m_trading.SetExpiration(expiration,symbol_name);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг асинхронной отправки торговых запросов        |
//| для торговых объектов всех символов                              |
//+------------------------------------------------------------------+
void CEngine::TradingSetAsyncMode(const bool mode=false,const string symbol_name=NULL)
  {
   this.m_trading.SetAsyncMode(mode,symbol_name);
  }
//+------------------------------------------------------------------+
//| Устанавливает уровень логирования торговых запросов              |
//| для торговых объектов всех символов                              |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+

На этом доработка класса CEngine завершена и нам остаётся проверить как всё это теперь работает.

Тестирование

Для тестирования возьмём советник из прошлой статьи и сохраним его в новую папку \MQL5\Experts\TestDoEasy\Part22\ под новым именем TestDoEasyPart22.mq5.

У нас в прошлом советнике в обработчике OnInit() в журнал выводилось много текстовой проверочной информации. Сейчас она нам не нужна, поэтому удалим все ненужные Print() и добавим инициализацию торгового класса и проверку проигрывания стандартного звука по макроподстановке и пользовательского звука по его описанию:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Вызов данной функции выводит в журнал список констант перечисления, 
//--- заданного в файле DELib.mqh в строках 22 и 25, для проверки корректности констант
   //EnumNumbersTest();
   
//--- Установка глобальных переменных советника
   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;

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

//--- Установка типа используемого списка символов в коллекции символов
   engine.SetUsedSymbols(array_used_symbols);
//--- Отображение выбранного режима работы с коллекцией объектов-символов
   Print(engine.ModeSymbolsListDescription(),TextByLanguage(". Количество используемых символов: ",". The number of symbols used: "),engine.GetSymbolsCollectionTotal());
   
//--- Создание тестовых файлов ресурсов
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_01",TextByLanguage("Звук упавшей монетки 1","The sound of a falling coin 1"),sound_array_coin_01);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_02",TextByLanguage("Звук упавших монеток","Sound fallen coins"),sound_array_coin_02);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_03",TextByLanguage("Звук монеток","Sound of coins"),sound_array_coin_03);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_04",TextByLanguage("Звук упавшей монетки 2","The sound of a falling coin 2"),sound_array_coin_04);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_click_01",TextByLanguage("Звук щелчка по кнопке 1","Click on the button sound 1"),sound_array_click_01);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_click_02",TextByLanguage("Звук щелчка по кнопке 2","Click on the button sound 1"),sound_array_click_02);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_click_03",TextByLanguage("Звук щелчка по кнопке 3","Click on the button sound 1"),sound_array_click_03);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_cash_machine_01",TextByLanguage("Звук кассового аппарата","The sound of the 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);

//--- Передача в торговый класс всех имеющихся коллекций
   engine.TradingOnInit();
//--- Установка синхронной передачи приказов для всех используемых символов
   engine.TradingSetAsyncMode();
//--- Установка стандартных звуков торговым объектам всех используемых символов
   engine.SetSoundsStandart();
//--- Проверка воспроизведения стандартного звука по макроподстановке и пользовательского звука по описанию
   engine.PlaySoundByDescription(SND_OK);
   Sleep(600);
   engine.PlaySoundByDescription(TextByLanguage("Звук упавшей монетки 2","The sound of a falling coin 2"));
      
//--- Установка контрольных значений для символов
   //--- Получаем список всех символов коллекции
   CArrayObj *list=engine.GetListAllUsedSymbols();
   if(list!=NULL && list.Total()!=0)
     {
      //--- В цикле по списку устанавливаем нужные значения для отслеживаемых свойств символов
      //--- По умолчанию всем свойствам установлены значения LONG_MAX, что означает "Не отслеживать данное свойство" 
      //--- Включить или выключить (задать величину меньше LONG_MAX или наоборот - установить значение LONG_MAX) можно в любое время в любом месте программы
      for(int i=0;i<list.Total();i++)
        {
         CSymbol* symbol=list.At(i);
         if(symbol==NULL)
            continue;
         //--- Установка контроля увеличения цены символа на 100 пунктов
         symbol.SetControlBidInc(100*symbol.Point());
         //--- Установка контроля уменьшения цены символа на 100 пунктов
         symbol.SetControlBidDec(100*symbol.Point());
         //--- Установка контроля увеличения спреда символа на 40 пунктов
         symbol.SetControlSpreadInc(40);
         //--- Установка контроля уменьшения спреда символа на 40 пунктов
         symbol.SetControlSpreadDec(40);
         //--- Установка контроля размера спреда по значению 40 пунктов
         symbol.SetControlSpreadLevel(40);
        }
     }
//--- Установка контрольных значений для текущего аккаунта
   CAccount* account=engine.GetAccountCurrent();
   if(account!=NULL)
     {
      //--- Установка контроля увеличения значения прибыли на 10
      account.SetControlledValueINC(ACCOUNT_PROP_PROFIT,10.0);
      //--- Установка контроля увеличения значения средств на 15
      account.SetControlledValueINC(ACCOUNT_PROP_EQUITY,15.0);
      //--- Установка контрольного уровня прибыли на 20
      account.SetControlledValueLEVEL(ACCOUNT_PROP_PROFIT,20.0);
     }

//--- Проверка и удаление неудалённых графических объектов советника
   if(IsPresentObects(prefix))
      ObjectsDeleteAll(0,prefix);

//--- Создание панели кнопок
   if(!CreateButtons(InpButtShiftX,InpButtShiftY))
      return INIT_FAILED;
//--- Установка состояния кнопки активизации трейлингов
   ButtonState(butt_data[TOTAL_BUTT-1].name,trailing_on);

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

После компиляции и запуска советника сначала будет воспроизведён стандартный звук "ok.wav" и спустя 1/6 секунды пользовательский звук с описанием "Звук упавшей монетки 2".

Чтобы проверить работу методов проверки ограничений торговли, нужно их искуственно создать.
Для примера:

  1. отключим интернет (эмулируем разрыв связи с торговым сервером),
  2. в настройках советника запретим ему торговать (нажмём F7 и в открывшемся окне настроек советника во вкладке "Общие" снимем флажок "Разрешить советнику торговать"),
  3. запретим в терминале автоторговлю (отожмём кнопку "Автоторговля")

И попробуем нажать на кнопку открытия позиции на торговой панели советника. В итоге получим запись в журнале:

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")

Поочерёдно устраним ограничения.

Включим интернет и при попытке открыть позицию получим:

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")

Разрешим в терминале автоторговлю нажав кнопку Авто-торговля, и при попытке открыть позицию получим:

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")

Нажмём F7 и в настройках советника разрешим ему торговать. При попытке открытия позиции получим открытую позицию:

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

Остальные ограничения возможно проверить в тестере или на демо-счёте, создав ситуацию, при которой сработает одно из ограничений, например — ограничение по максимальному количеству отложенных ордеров на счёте.

Что дальше

В следующей статье сделаем контроль корректности параметров торговых приказов.

Ниже прикреплены все файлы текущей версии библиотеки и файлы тестового советника. Их можно скачать и протестировать всё самостоятельно.
При возникновении вопросов, замечаний и пожеланий, вы можете озвучить их в комментариях к статье.

К содержанию

Статьи этой серии:

Часть 1. Концепция, организация данных
Часть 2. Коллекция исторических ордеров и сделок
Часть 3. Коллекция рыночных ордеров и позиций, организация поиска
Часть 4. Торговые события. Концепция
Часть 5. Классы и коллекция торговых событий. Отправка событий в программу
Часть 6. События на счёте с типом неттинг
Часть 7. События срабатывания StopLimit-ордеров, подготовка функционала для регистрации событий модификации ордеров и позиций
Часть 8. События модификации ордеров и позиций
Часть 9. Совместимость с MQL4 - Подготовка данных
Часть 10. Совместимость с MQL4 - События открытия позиций и активации отложенных ордеров
Часть 11. Совместимость с MQL4 - События закрытия позиций
Часть 12. Класс объекта "аккаунт", коллекция объектов-аккаунтов
Часть 13. События объекта "аккаунт"
Часть 14. Объект "Символ"
Часть 15. Коллекция объектов-символов
Часть 16. События коллекции символов
Часть 17. Интерактивность объектов библиотеки
Часть 18. Интерактивность объекта-аккаунт и любых других объектов библиотеки
Часть 19. Класс сообщений библиотеки
Часть 20. Создание и хранение ресурсов программы
Часть 21. Торговые классы - Базовый кроссплатформенный торговый объект