
Библиотека для простого и быстрого создания программ для MetaTrader (Часть XXII): Торговые классы - Основной торговый класс, контроль ограничений
Содержание
В прошлой статье мы открыли обширный раздел библиотеки, посвящённый торговым функциям и создали базовый торговый объект символа. Этот торговый объект получает в своих параметрах все свойства отправляемого на сервер торгового запроса, заполняет структуру торгового запроса в соответствии с типом вызванного метода класса (открытие позиции/установка отложенного ордера/модификация/закрытие/удаление) и отправляет торговый приказ на сервер. И мы условились о понимании, что в базовый торговый объект для отсылки торгового приказа передаются корректные значения свойств торгового запроса. Но для полноценного использования торгового объекта нам необходимо сначала проверить существующие ограничения для проведения торговых операций в терминале, программе, на счёте и символе. И уже после прохождения этих первичных проверок мы можем проверять корректность свойств торгового запроса.
Сегодня начнём делать полноценный торговый класс, и первое что сделаем для реализации полноценной и комфортной работы с торговым функционалом
библиотеки — проверку ограничений для проведения торговых операций.
Концепция
Мы уже имеем базовый торговый объект, который входит в состав объекта-символа. Выполняет он простую задачу — заполнить структуру торгового запроса в соответствии с параметрами, переданными в один из методов класса, и отправить торговый приказ на сервер. Сегодня мы, перед тем, как начать делать полноценный торговый класс, дополним немного функционал базового торгового объекта — добавим возможность озвучивания результатов отсылки торгового приказа. В итоге мы сможем задать любой звук для озвучивания торговых событий. Причём, для каждого символа мы сможем задать свои звуки для каждого из торговых событий. Но также, естественно, можем задать общий набор звуков для каждого из событий, одинаковые для всех символов. В общем, базовый торговый объект будет предоставлять широкие возможности задания звуков торговым событиям, как одинаковых сразу для всех символов и событий, так и индивидуальных для отдельно взятого символа и события.
Затем создадим торговый класс, из которого в дальнейшем будем проводить все торговые операции. Сегодня этот класс будет иметь минимальный
функционал — проверку разрешения на проведение торговых операций и вызов необходимых методов базовых торговых объектов требуемых
символов.
Расширение функционала базового торгового объекта
Итак. Для установки звуков торговым событиям нам потребуются макроподстановки и перечисления. Откроем файл 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 появились новые свойства для символа и аккаунта:
- MQL5: В перечисление ENUM_SYMBOL_INFO_STRING
добавлены следующие значения:
- SYMBOL_CATEGORY — категория символа. Используется для дополнительной маркировки финансовых инструментов. Например, в нем могут быть указаны секторы рынка, к которым относится символ: Agriculture, Oil & Gas и т.д.
- SYMBOL_EXCHANGE — название биржи или площадки, на которой торгуется символ.
- 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".
Чтобы проверить работу методов проверки ограничений торговли, нужно их искуственно создать.
Для примера:
- отключим интернет (эмулируем разрыв связи с торговым сервером),
- в настройках советника запретим ему торговать (нажмём F7 и в открывшемся окне настроек советника во вкладке "Общие" снимем флажок
"Разрешить советнику торговать"),
- запретим в терминале автоторговлю (отожмём кнопку "Автоторговля")
И попробуем нажать на кнопку открытия позиции на торговой панели советника. В итоге получим запись в журнале:
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. Торговые классы - Базовый
кроссплатформенный торговый объект





- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Нужно весь код поглядеть. Кинь в личку, или сюда если не тайна за семью печатями.
Ну нет там ещё ничего
Ну нет там ещё ничего
Мне, чтобы что-либо тебе ответить, нужно запустить код твой. Буду на месте, отвечу.
Я помню что ты не дома и не тороплю.
Я помню что ты не дома и не тороплю.
Я помню что ты не дома и не тороплю.
Да, была недоработка в торговых событиях - не было флага, возвращающего факт произошедшего события.
Добавил. Обновление будет в следующей статье. Спасибо за сообщение.