Библиотека для простого и быстрого создания программ для MetaTrader (Часть XXIX): Отложенные торговые запросы - классы объектов-запросов
Содержание
- Концепция
- Базовый объект абстрактного отложенного торгового запроса
- Объекты-наследники базового объекта-отложенного запроса
- Тестирование
- Что дальше
Концепция
В трёх предыдущих статьях мы проверили концепцию управления торговыми методами торгового класса при помощи отложенных запросов.
Отложенный
запрос — это по сути обычный торговый приказ, но исполняемый по некоему условию. Мы проверяли условие задержки отсылки торгового
приказа в торговых методах при получении ошибки от сервера, обработка которой требует некоторого ожидания перед повторной отсылкой
запроса на сервер. Естественно, это не все условия, по которым можно использовать отложенные запросы. Условиями могут быть и ценовые
уровни, при достижении которых будет отослан торговый приказ. А может быть и совокупность каких-либо условий, например — некоторых
пороговых величин свойств символа, при достижении равенства которым также будет послан торговый приказ на сервер (стоп-лимитный ордер —
наглядный пример отложенного торгового запроса на выставление лимитного ордера при достижении ценой уровня стоп-ордера).
Но чтобы всё это вместить в код объекта-отложенного запроса, нам необходимо привести его к виду общей
концепции объектов библиотеки — тогда такие объекты станут легко расширяемыми для внедрения в них новых свойств. Сейчас же на данном
этапе работы с отложенными торговыми запросами мы для проверки концепции написали код работы с ними прямо в листинге торгового
класса, что концептуально не верно для дальнейшего их использования (впрочем, так и планировалось — сначала быстро всё проверить, а
затем уже облачить в нужную форму).
Сегодня мы создадим базовый класс абстрактного объекта-отложенного торгового запроса и классы
объектов-наследников базового объекта-запроса. В базовом объекте будут содержаться общие для всех объектов-запросов свойства, а в
объектах-наследниках — индивидуальные свойства, присущие статусам каждого дочернего объекта — так мы делаем для всех объектов
библиотеки, и здесь — не исключение.
Но для начала, как уже стало обычным, создадим нужные для работы с объектами сообщения библиотеки.
В файл Datas.mqh впишем индексы новых сообщений библиотеки:
...
MSG_LIB_TEXT_AND_PAUSE, // и паузой MSG_LIB_TEXT_ALREADY_EXISTS, // уже существует MSG_LIB_TEXT_CREATED, // Создан MSG_LIB_TEXT_ATTEMPTS, // Попыток MSG_LIB_TEXT_WAIT, // Ожидание MSG_LIB_TEXT_END, // Окончание
...
MSG_LIB_TEXT_REQUEST, // Отложенный запрос # MSG_LIB_TEXT_REQUEST_DATAS, // Параметры торгового запроса MSG_LIB_TEXT_PEND_REQUEST_DATAS, // Параметры отложенного торгового запроса
...
MSG_LIB_TEXT_PEND_REQUEST_BY_ERROR, // Отложенный запрос, созданный по коду возврата сервера MSG_LIB_TEXT_PEND_REQUEST_BY_REQUEST, // Отложенный запрос, созданный по запросу MSG_LIB_TEXT_PEND_REQUEST_WAITING_ONSET, // Ожидание наступления времени первой торговой попытки MSG_LIB_TEXT_PEND_REQUEST_STATUS, // Статус отложенного запроса MSG_LIB_TEXT_PEND_REQUEST_STATUS_OPEN, // Отложенный запрос на открытие позиции MSG_LIB_TEXT_PEND_REQUEST_STATUS_CLOSE, // Отложенный запрос на закрытие позиции MSG_LIB_TEXT_PEND_REQUEST_STATUS_SLTP, // Отложенный запрос на модификацию стоп-приказов позиции MSG_LIB_TEXT_PEND_REQUEST_STATUS_PLACE, // Отложенный запрос на установку отложенного ордера MSG_LIB_TEXT_PEND_REQUEST_STATUS_REMOVE, // Отложенный запрос на удаление отложенного ордера MSG_LIB_TEXT_PEND_REQUEST_STATUS_MODIFY, // Отложенный запрос на модификацию параметров отложенного ордера };
и соответствующие новым индексам тексты сообщений:
{" и паузой "," and pause "}, {" уже существует"," already exists"}, {"Создан","Created"}, {"Попыток","Attempts"}, {"Ожидание","Wait"}, {"Окончание","End"},
...
{"Отложенный запрос #","Pending request #"}, {"Параметры торгового запроса","Trade request parameters"}, {"Параметры отложенного торгового запроса","Pending trade request parameters"},
...
{"Отложенный запрос, созданный по коду возврата сервера","Pending request that was created as a result of the server code"}, {"Отложенный запрос, созданный по запросу","Pending request created by request"}, {"Ожидание наступления времени первой торговой попытки","Waiting for the onset time of the first trading attempt"}, {"Статус отложенного запроса","Pending request status"}, {"Отложенный запрос на открытие позиции","Pending request to open a position"}, {"Отложенный запрос на закрытие позиции","Pending request to close a position"}, {"Отложенный запрос на модификацию стоп-приказов позиции","Pending request to modify position stop orders"}, {"Отложенный запрос на установку отложенного ордера","Pending request to place a pending order"}, {"Отложенный запрос на удаление отложенного ордера","Pending request to remove a pending order"}, {"Отложенный запрос на модификацию параметров отложенного ордера","Pending request to modify pending order parameters"}, };
Как уже был сказано выше, базовый объект отложенного торгового запроса — это некий общий, абстрактный запрос, который содержит в себе
свойства, присущие всем торговым запросам, а уточнение свойств возлагается на объекты-наследники базового объекта.
Таким
образом, мы будем иметь один базовый объект-запрос и шесть объектов-наследников, уточняющих свойства отложенного запроса по типу
проводимой торговой операции:
- открытие позиции (новой на хедж-счёте, добавление объёма и переворот — на неттинг-счёте);
- модификация стоп-приказов открытой позиции;
- закрытие позиции — полное и частичное закрытие, и закрытие встречным ордером (на хедж-счёте);
- установка отложенного ордера;
- модификация свойств отложенного ордера — цены стоп-приказов ордера, цена установки ордера, цена StopLimit-ордера, срок жизни ордера, тип
заливки и тип экспирации;
- удаление ранее выставленного отложенного ордера.
Базовый объект абстрактного отложенного торгового запроса
Как и для всех предыдущих объектов библиотеки, создадим перечисления свойств объекта отложенного торгового запроса.
В файле Defines.mqh впишем перечисления статусов, а также целочисленных, вещественных и строковых свойств объекта:
//+------------------------------------------------------------------+ //| Данные для работы с отложенными торговыми запросами | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Статус отложенного запроса | //+------------------------------------------------------------------+ enum ENUM_PEND_REQ_STATUS { PEND_REQ_STATUS_OPEN, // Отложенный запрос на открытие рыночной позиции PEND_REQ_STATUS_CLOSE, // Отложенный запрос на закрытие позиции PEND_REQ_STATUS_SLTP, // Отложенный запрос на модификацию стоп-приказов открытой позиции PEND_REQ_STATUS_PLACE, // Отложенный запрос на установку отложенного ордера PEND_REQ_STATUS_REMOVE, // Отложенный запрос на удаление отложенного ордера PEND_REQ_STATUS_MODIFY // Отложенный запрос на модификацию установленного отложенного ордера }; //+------------------------------------------------------------------+ //| Тип отложенного запроса | //+------------------------------------------------------------------+ enum ENUM_PEND_REQ_TYPE { PEND_REQ_TYPE_ERROR=PENDING_REQUEST_ID_TYPE_ERR, // Отложенный запрос, созданный по коду возврата или ошибке PEND_REQ_TYPE_REQUEST=PENDING_REQUEST_ID_TYPE_REQ, // Отложенный запрос, созданный по запросу }; //+------------------------------------------------------------------+ //| Целочисленные свойства отложенного торгового запроса | //+------------------------------------------------------------------+ enum ENUM_PEND_REQ_PROP_INTEGER { PEND_REQ_PROP_STATUS = 0, // Статус торгового запроса (из перечисления ENUM_PEND_REQ_STATUS) PEND_REQ_PROP_TYPE, // Тип торгового запроса (из перечисления ENUM_PEND_REQ_TYPE) PEND_REQ_PROP_ID, // Идентификатор торгового запроса PEND_REQ_PROP_RETCODE, // Результат, на основании которого создан запрос PEND_REQ_PROP_TIME_CREATE, // Время создания запроса PEND_REQ_PROP_TIME_ACTIVATE, // Время активации очередной попытки PEND_REQ_PROP_WAITING, // Продолжительность ожидания между запросами PEND_REQ_PROP_CURENT, // Номер текущей попытки PEND_REQ_PROP_TOTAL, // Количество попыток //--- MqlTradeRequest PEND_REQ_PROP_MQL_REQ_ACTION, // Тип выполняемого действия в структуре запроса PEND_REQ_PROP_MQL_REQ_TYPE, // Тип ордера в структуре запроса PEND_REQ_PROP_MQL_REQ_MAGIC, // Штамп эксперта (идентификатор magic number) в структуре запроса PEND_REQ_PROP_MQL_REQ_ORDER, // Тикет ордера в структуре запроса PEND_REQ_PROP_MQL_REQ_POSITION, // Тикет позиции в структуре запроса PEND_REQ_PROP_MQL_REQ_POSITION_BY, // Тикет встречной позиции в структуре запроса PEND_REQ_PROP_MQL_REQ_DEVIATION, // Максимально приемлемое отклонение от запрашиваемой цены в структуре запроса PEND_REQ_PROP_MQL_REQ_EXPIRATION, // Срок истечения ордера (для ордеров типа ORDER_TIME_SPECIFIED) в структуре запроса PEND_REQ_PROP_MQL_REQ_TYPE_FILLING, // Тип ордера по исполнению в структуре запроса PEND_REQ_PROP_MQL_REQ_TYPE_TIME, // Тип ордера по времени действия в структуре запроса }; #define PEND_REQ_PROP_INTEGER_TOTAL (19) // Общее количество целочисленных свойств события #define PEND_REQ_PROP_INTEGER_SKIP (0) // Количество неиспользуемых в сортировке свойств запроса //+------------------------------------------------------------------+ //| Вещественные свойства отложенного торгового запроса | //+------------------------------------------------------------------+ enum ENUM_PEND_REQ_PROP_DOUBLE { PEND_REQ_PROP_PRICE_CREATE = PEND_REQ_PROP_INTEGER_TOTAL,// Цена при создании запроса //--- MqlTradeRequest PEND_REQ_PROP_MQL_REQ_VOLUME, // Запрашиваемый объем сделки в лотах в структуре запроса PEND_REQ_PROP_MQL_REQ_PRICE, // Цена в структуре запроса PEND_REQ_PROP_MQL_REQ_STOPLIMIT, // Уровень StopLimit ордера в структуре запроса PEND_REQ_PROP_MQL_REQ_SL, // Уровень Stop Loss ордера в структуре запроса PEND_REQ_PROP_MQL_REQ_TP, // Уровень Take Profit ордера в структуре запроса }; #define PEND_REQ_PROP_DOUBLE_TOTAL (6) // Общее количество вещественных свойств события #define PEND_REQ_PROP_DOUBLE_SKIP (0) // Количество неиспользуемых в сортировке свойств события //+------------------------------------------------------------------+ //| Строковые свойства отложенного торгового запроса | //+------------------------------------------------------------------+ enum ENUM_PEND_REQ_PROP_STRING { //--- MqlTradeRequest PEND_REQ_PROP_MQL_REQ_SYMBOL = (PEND_REQ_PROP_INTEGER_TOTAL+PEND_REQ_PROP_DOUBLE_TOTAL), // Имя торгового инструмента в структуре запроса PEND_REQ_PROP_MQL_REQ_COMMENT // Комментарий к ордеру в структуре запроса }; #define PEND_REQ_PROP_STRING_TOTAL (2) // Общее количество строковых свойств события //+------------------------------------------------------------------+
Для расчёта индексации свойств в массивах свойств объекта используются макроподстановки,
указывающие на количество каждого из типов свойств.
Это мы рассматривали в
первой статье описания создания библиотеки, и здесь к описанию возвращаться не будем.
Как видно из листинга, свойствами объекта являются как свойства, принадлежащие к параметрам создания отложенного запроса, так и свойства,
указанные в структуре торгового запроса MqlTradeRequest,
в которой прописываются все параметры отправляемого на сервер запроса.
Так как мы хотим сортировать и искать объекты в списке по
любому из их параметров (как и все предыдущие объекты библиотеки), то всё содержимое структуры торгового запроса мы копируем в
соответствующие свойства объекта, повторяющие назначение полей структуры — в таком случае мы сможем искать и сортировать отложенные
запросы в списке по любому свойству.
Для поиска и сортировки объектов-отложенных запросов перечислим все возможные критерии сортировки этих объектов:
//+------------------------------------------------------------------+ //| Возможные критерии сортировки отложенных запросов | //+------------------------------------------------------------------+ #define FIRST_PREQ_DBL_PROP (PEND_REQ_PROP_INTEGER_TOTAL-PEND_REQ_PROP_INTEGER_SKIP) #define FIRST_PREQ_STR_PROP (PEND_REQ_PROP_INTEGER_TOTAL-PEND_REQ_PROP_INTEGER_SKIP+PEND_REQ_PROP_DOUBLE_TOTAL-PEND_REQ_PROP_DOUBLE_SKIP) enum ENUM_SORT_PEND_REQ_MODE { //--- Сортировка по целочисленным свойствам SORT_BY_PEND_REQ_STATUS = 0, // Сортировать по статусу торгового запроса (из перечисления ENUM_PEND_REQ_STATUS) SORT_BY_PEND_REQ_TYPE, // Сортировать по типу торгового запроса (из перечисления ENUM_PEND_REQ_TYPE) SORT_BY_PEND_REQ_ID, // Сортировать по идентификатору торгового запроса SORT_BY_PEND_REQ_RETCODE, // Сортировать по результату, на основании которого создан запрос SORT_BY_PEND_REQ_TIME_CREATE, // Сортировать по времени создания запроса SORT_BY_PEND_REQ_TIME_ACTIVATE, // Сортировать по времени активации очередной попытки SORT_BY_PEND_REQ_WAITING, // Сортировать по продолжительности ожидания между запросами SORT_BY_PEND_REQ_CURENT, // Сортировать по номеру текущей попытки SORT_BY_PEND_REQ_TOTAL, // Сортировать по количеству попыток //--- MqlTradeRequest SORT_BY_PEND_REQ_MQL_REQ_ACTION, // Сортировать по типу выполняемого действия в структуре запроса SORT_BY_PEND_REQ_MQL_REQ_TYPE, // Сортировать по типу ордера в структуре запроса SORT_BY_PEND_REQ_MQL_REQ_MAGIC, // Сортировать по штампу эксперта (идентификатору magic number) в структуре запроса SORT_BY_PEND_REQ_MQL_REQ_ORDER, // Сортировать по тикету ордера в структуре запроса SORT_BY_PEND_REQ_MQL_REQ_POSITION, // Сортировать по тикету позиции в структуре запроса SORT_BY_PEND_REQ_MQL_REQ_POSITION_BY, // Сортировать по тикету встречной позиции в структуре запроса SORT_BY_PEND_REQ_MQL_REQ_DEVIATION, // Сортировать по максимально приемлемому отклонению от запрашиваемой цены в структуре запроса SORT_BY_PEND_REQ_MQL_REQ_EXPIRATION, // Сортировать по сроку истечения ордера (для ордеров типа ORDER_TIME_SPECIFIED) в структуре запроса SORT_BY_PEND_REQ_MQL_REQ_TYPE_FILLING, // Сортировать по типу ордера по исполнению в структуре запроса SORT_BY_PEND_REQ_MQL_REQ_TYPE_TIME, // Сортировать по типу ордера по времени действия в структуре запроса //--- Сортировка по вещественным свойствам SORT_BY_PEND_REQ_PRICE_CREATE = FIRST_PREQ_DBL_PROP, // Сортировать по цене при создании запроса //--- MqlTradeRequest SORT_BY_PEND_REQ_MQL_REQ_VOLUME, // Сортировать по запрашиваемому объему сделки в лотах в структуре запроса SORT_BY_PEND_REQ_MQL_REQ_PRICE, // Сортировать по цене в структуре запроса SORT_BY_PEND_REQ_MQL_REQ_STOPLIMIT, // Сортировать по уровню StopLimit ордера в структуре запроса SORT_BY_PEND_REQ_MQL_REQ_SL, // Сортировать по уровню StopLoss ордера в структуре запроса SORT_BY_PEND_REQ_MQL_REQ_TP, // Сортировать по уровню TakeProfit ордера в структуре запроса //--- Сортировка по строковым свойствам //--- MqlTradeRequest SORT_BY_PEND_REQ_MQL_SYMBOL = FIRST_PREQ_STR_PROP, // Сортировать по имени торгового инструмента в структуре запроса SORT_BY_PEND_REQ_MQL_COMMENT // Сортировать по комментарию к ордеру в структуре запроса }; //+------------------------------------------------------------------+
Теперь в отдельном файле создадим новый класс базового объекта абстрактного отложенного запроса.
В каталоге библиотеки \MQL5\Include\DoEasy\Objects\ создадим новую подпапку PendRequest\ — в ней будем хранить файлы классов отложенных торговых запросов.
Создадим в папке PendRequest новый класс базового объекта абстрактного отложенного запроса в файле PendRequest.mqh:
//+------------------------------------------------------------------+ //| PendRequest.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" #property strict // Нужно для mql4 //+------------------------------------------------------------------+ //| Включаемые файлы | //+------------------------------------------------------------------+ #include <Object.mqh> #include "..\..\Services\DELib.mqh" //+------------------------------------------------------------------+ //| Класс абстрактного отложенного торгового запроса | //+------------------------------------------------------------------+ class CPendRequest : public CObject { private: MqlTradeRequest m_request; // Структура торгового запроса //--- Копирует данные торгового запроса void CopyRequest(const MqlTradeRequest &request); //--- Возвращает индекс массива, по которому фактически расположено (1) double-свойство и (2) string-свойство запроса int IndexProp(ENUM_PEND_REQ_PROP_DOUBLE property)const { return(int)property-PEND_REQ_PROP_INTEGER_TOTAL; } int IndexProp(ENUM_PEND_REQ_PROP_STRING property)const { return(int)property-PEND_REQ_PROP_INTEGER_TOTAL-PEND_REQ_PROP_DOUBLE_TOTAL; } protected: int m_digits; // Количество знаков после запятой в котировке символа int m_digits_lot; // Количество знаков после запятой в значении лота символа bool m_is_hedge; // Флаг счёта с типом "хедж" long m_long_prop[PEND_REQ_PROP_INTEGER_TOTAL]; // Целочисленные свойства запроса double m_double_prop[PEND_REQ_PROP_DOUBLE_TOTAL]; // Вещественные свойства запроса string m_string_prop[PEND_REQ_PROP_STRING_TOTAL]; // Строковые свойства запроса //--- Защищённый параметрический конструктор CPendRequest(const ENUM_PEND_REQ_STATUS status, const uchar id, const double price, const ulong time, const MqlTradeRequest &request, const int retcode); //--- Возвращает (1) заданный в настройках магический номер, (2) флаг счёта с типом "хедж" ushort GetMagicID(void) const { return ushort(this.GetProperty(PEND_REQ_PROP_MQL_REQ_MAGIC) & 0xFFFF);} bool IsHedge(void) const { return this.m_is_hedge; } public: //--- Конструктор по умолчанию CPendRequest(){;} //--- Устанавливает (1) целочисленное, (2) вещественное и (3) строковое свойство запроса void SetProperty(ENUM_PEND_REQ_PROP_INTEGER property,long value) { this.m_long_prop[property]=value; } void SetProperty(ENUM_PEND_REQ_PROP_DOUBLE property,double value){ this.m_double_prop[this.IndexProp(property)]=value; } void SetProperty(ENUM_PEND_REQ_PROP_STRING property,string value){ this.m_string_prop[this.IndexProp(property)]=value; } //--- Возвращает из массива свойств (1) целочисленное, (2) вещественное и (3) строковое свойство запроса long GetProperty(ENUM_PEND_REQ_PROP_INTEGER property) const { return this.m_long_prop[property]; } double GetProperty(ENUM_PEND_REQ_PROP_DOUBLE property) const { return this.m_double_prop[this.IndexProp(property)]; } string GetProperty(ENUM_PEND_REQ_PROP_STRING property) const { return this.m_string_prop[this.IndexProp(property)]; } //--- Возвращает флаг поддержания запросом данного свойства virtual bool SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property) { return true; } virtual bool SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property) { return true; } virtual bool SupportProperty(ENUM_PEND_REQ_PROP_STRING property) { return true; } //--- Сравнивает объекты CPendRequest между собой по заданному свойству (для сортировки списков по указанному свойству объекта-запроса) virtual int Compare(const CObject *node,const int mode=0) const; //--- Сравнивает объекты CPendRequest между собой по всем свойствам (для поиска равных объектов-запросов) bool IsEqual(CPendRequest* compared_obj); //+------------------------------------------------------------------+ //| Методы упрощённого доступа к свойствам объекта-запроса | //+------------------------------------------------------------------+ //--- Возвращает (1) структуру запроса, (2) статус, (3) тип запроса, (4) цену при создании запроса, //--- (5) время создания запроса, (6) время активации очередной попытки, //--- (7) продолжительность ожидания между запросами, (8) номер текущей попытки, //--- (9) количество попыток, (10) идентификатор запроса //--- (11) результат, на основании которого создан запрос, //--- (12) тикет ордера, (13) тикет позиции, (14) тип торговой операции MqlTradeRequest MqlRequest(void) const { return this.m_request; } ENUM_PEND_REQ_STATUS Status(void) const { return (ENUM_PEND_REQ_STATUS)this.GetProperty(PEND_REQ_PROP_STATUS); } ENUM_PEND_REQ_TYPE TypeRequest(void) const { return (ENUM_PEND_REQ_TYPE)this.GetProperty(PEND_REQ_PROP_TYPE); } double PriceCreate(void) const { return this.GetProperty(PEND_REQ_PROP_PRICE_CREATE); } ulong TimeCreate(void) const { return this.GetProperty(PEND_REQ_PROP_TIME_CREATE); } ulong TimeActivate(void) const { return this.GetProperty(PEND_REQ_PROP_TIME_ACTIVATE); } ulong WaitingMSC(void) const { return this.GetProperty(PEND_REQ_PROP_WAITING); } uchar CurrentAttempt(void) const { return (uchar)this.GetProperty(PEND_REQ_PROP_CURENT); } uchar TotalAttempts(void) const { return (uchar)this.GetProperty(PEND_REQ_PROP_TOTAL); } uchar ID(void) const { return (uchar)this.GetProperty(PEND_REQ_PROP_ID); } int Retcode(void) const { return (int)this.GetProperty(PEND_REQ_PROP_RETCODE); } ulong Order(void) const { return this.GetProperty(PEND_REQ_PROP_MQL_REQ_ORDER); } ulong Position(void) const { return this.GetProperty(PEND_REQ_PROP_MQL_REQ_POSITION); } ENUM_TRADE_REQUEST_ACTIONS Action(void) const { return (ENUM_TRADE_REQUEST_ACTIONS)this.GetProperty(PEND_REQ_PROP_MQL_REQ_ACTION);} //--- Устанавливает (1) цену при создании запроса, (2) время создания запроса, //--- (3) время текущей попытки, (4) продолжительность ожидания между запросами, //--- (5) номер текущей попытки, (6) количество попыток, (7) идентификатор, //--- (8) тикет ордера, (9) тикет позиции void SetPriceCreate(const double price) { this.SetProperty(PEND_REQ_PROP_PRICE_CREATE,price); } void SetTimeCreate(const ulong time) { this.SetProperty(PEND_REQ_PROP_TIME_CREATE,time); } void SetTimeActivate(const ulong time) { this.SetProperty(PEND_REQ_PROP_TIME_ACTIVATE,time); } void SetWaitingMSC(const ulong miliseconds) { this.SetProperty(PEND_REQ_PROP_WAITING,miliseconds); } void SetCurrentAttempt(const uchar number) { this.SetProperty(PEND_REQ_PROP_CURENT,number); } void SetTotalAttempts(const uchar number) { this.SetProperty(PEND_REQ_PROP_TOTAL,number); } void SetID(const uchar id) { this.SetProperty(PEND_REQ_PROP_ID,id); } void SetOrder(const ulong ticket) { this.SetProperty(PEND_REQ_PROP_MQL_REQ_ORDER,ticket); } void SetPosition(const ulong ticket) { this.SetProperty(PEND_REQ_PROP_MQL_REQ_POSITION,ticket); } //+------------------------------------------------------------------+ //| Описания свойств объекта-запроса | //+------------------------------------------------------------------+ //--- Возвращает описание (1) целочисленного, (2) вещественного и (3) строкового свойства запроса string GetPropertyDescription(ENUM_PEND_REQ_PROP_INTEGER property); string GetPropertyDescription(ENUM_PEND_REQ_PROP_DOUBLE property); string GetPropertyDescription(ENUM_PEND_REQ_PROP_STRING property); //--- Возвращает наименования параметров объекта-отложенного запроса string StatusDescription(void) const; string TypeRequestDescription(void) const; string IDDescription(void) const; string RetcodeDescription(void) const; string TimeCreateDescription(void) const; string TimeActivateDescription(void) const; string TimeWaitingDescription(void) const; string CurrentAttemptDescription(void) const; string TotalAttemptsDescription(void) const; string PriceCreateDescription(void) const; //--- Возвращает наименования параметров структуры торгового запроса в объекте-запросе string MqlReqActionDescription(void) const; string MqlReqMagicDescription(void) const; string MqlReqOrderDescription(void) const; string MqlReqSymbolDescription(void) const; string MqlReqVolumeDescription(void) const; string MqlReqPriceDescription(void) const; string MqlReqStopLimitDescription(void) const; string MqlReqStopLossDescription(void) const; string MqlReqTakeProfitDescription(void) const; string MqlReqDeviationDescription(void) const; string MqlReqTypeOrderDescription(void) const; string MqlReqTypeFillingDescription(void) const; string MqlReqTypeTimeDescription(void) const; string MqlReqExpirationDescription(void) const; string MqlReqCommentDescription(void) const; string MqlReqPositionDescription(void) const; string MqlReqPositionByDescription(void) const; //--- Выводит в журнал (1) описание свойств запроса (full_prop=true - все свойства, false - только поддерживаемые), //--- (2) краткое сообщение о событии (реализация в потомках класса) void Print(const bool full_prop=false); virtual void PrintShort(void){;} }; //+------------------------------------------------------------------+
Идентичные объекты мы уже создавали много раз с подробным описанием их устройства. Думаю, что здесь не будем останавливаться на рассмотрении принципов устройства объекта — в нём, как и у остальных похожих, есть три массива для хранения целочисленных, вещественных и строковых свойств. И есть методы доступа к этим свойствам как посредством указания константы свойства — GetProperty(), так и упрощённые — с "говорящим" наименованием метода. Также есть методы, выводящие описания всех свойств объекта. В общем — всё стандартно для объектов библиотеки. Об устройстве объектов библиотеки можно заново прочесть в самой первой статье.
За пределами тела класса напишем закрытый конструктор класса:
//+------------------------------------------------------------------+ //| Конструктор | //+------------------------------------------------------------------+ CPendRequest::CPendRequest(const ENUM_PEND_REQ_STATUS status, const uchar id, const double price, const ulong time, const MqlTradeRequest &request, const int retcode) { this.CopyRequest(request); this.m_is_hedge=#ifdef __MQL4__ true #else bool(::AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) #endif; this.m_digits=(int)::SymbolInfoInteger(this.GetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL),SYMBOL_DIGITS); int dg=(int)DigitsLots(this.GetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL)); this.m_digits_lot=(dg==0 ? 1 : dg); this.SetProperty(PEND_REQ_PROP_STATUS,status); this.SetProperty(PEND_REQ_PROP_ID,id); this.SetProperty(PEND_REQ_PROP_RETCODE,retcode); this.SetProperty(PEND_REQ_PROP_TYPE,this.GetProperty(PEND_REQ_PROP_RETCODE)>0 ? PEND_REQ_TYPE_ERROR : PEND_REQ_TYPE_REQUEST); this.SetProperty(PEND_REQ_PROP_TIME_CREATE,time); this.SetProperty(PEND_REQ_PROP_PRICE_CREATE,price); } //+------------------------------------------------------------------+
Итак, что у нас тут:
Первым делом копируем данные структуры
торгового запроса в массивы целочисленных, вещественных и строковых свойств при помощи метода CopyRequest(), который
рассмотрим ниже.
Затем устанавливаем флаг счёта с типом "хедж", устанавливаем
количество знаков после запятой в котировке символа и в значении лота символа (это потребуется для корректного вывода информации
в журнал). Причём, если количество знаков после запятой в значении лота равно нулю, то выводить будем с одним знаком псле запятой — так
значение лота смотрится нагляднее: вместо "1" будет выводиться "1.0".
Далее просто устанавливаем переданные значения некоторых
свойств в конструктор класса при создании объекта-запроса значениям соответствующих свойств объекта.
Таким образом мы заполняем
все свойства объекта-отложенного запроса сразу же при его создании.
Метод сравнения двух объектов-отложенных запросов по указанному свойству (mode):
//+------------------------------------------------------------------+ //| Сравнивает объекты CPendRequest между собой по заданному свойству| //+------------------------------------------------------------------+ int CPendRequest::Compare(const CObject *node,const int mode=0) const { const CPendRequest *compared_obj=node; //--- сравнение целочисленных свойств двух событий if(mode<PEND_REQ_PROP_INTEGER_TOTAL) { long value_compared=compared_obj.GetProperty((ENUM_PEND_REQ_PROP_INTEGER)mode); long value_current=this.GetProperty((ENUM_PEND_REQ_PROP_INTEGER)mode); return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0); } //--- сравнение вещественных свойств двух событий if(mode<PEND_REQ_PROP_DOUBLE_TOTAL+PEND_REQ_PROP_INTEGER_TOTAL) { double value_compared=compared_obj.GetProperty((ENUM_PEND_REQ_PROP_DOUBLE)mode); double value_current=this.GetProperty((ENUM_PEND_REQ_PROP_DOUBLE)mode); return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0); } //--- сравнение строковых свойств двух событий else if(mode<PEND_REQ_PROP_DOUBLE_TOTAL+PEND_REQ_PROP_INTEGER_TOTAL+PEND_REQ_PROP_STRING_TOTAL) { string value_compared=compared_obj.GetProperty((ENUM_PEND_REQ_PROP_STRING)mode); string value_current=this.GetProperty((ENUM_PEND_REQ_PROP_STRING)mode); return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0); } return 0; } //+------------------------------------------------------------------+
И метод полного сравнения двух объектов-отложенных запросов по всем их свойствам:
//+------------------------------------------------------------------+ //| Сравнивает объекты CPendRequest между собой по всем свойствам | //+------------------------------------------------------------------+ bool CPendRequest::IsEqual(CPendRequest *compared_obj) { int beg=0, end=PEND_REQ_PROP_INTEGER_TOTAL; for(int i=beg; i<end; i++) { ENUM_PEND_REQ_PROP_INTEGER prop=(ENUM_PEND_REQ_PROP_INTEGER)i; if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; } beg=end; end+=PEND_REQ_PROP_DOUBLE_TOTAL; for(int i=beg; i<end; i++) { ENUM_PEND_REQ_PROP_DOUBLE prop=(ENUM_PEND_REQ_PROP_DOUBLE)i; if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; } beg=end; end+=PEND_REQ_PROP_STRING_TOTAL; for(int i=beg; i<end; i++) { ENUM_PEND_REQ_PROP_STRING prop=(ENUM_PEND_REQ_PROP_STRING)i; if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; } //--- Все свойства равны return true; } //+------------------------------------------------------------------+
Такие методы так же уже не раз рассматривались при создании предыдущих объектов библиотеки.
Повторю лишь, что
виртуальный метод Compare() объекта-запроса, служащий для сравнения по указанному свойству, сравнивает указанные свойства
текущего объекта класса CPendRequest и переданного в метод объекта такого же класса. Если значение у текущего объекта больше значения
сравниваемого объекта, то метод возвращает 1, если меньше, то -1, иначе 0. Это нужно для работы со списками указателей на объекты — с его
методом Searsh(), который
использует для быстрого сравнения виртуальный метод Compare()
базового объекта стандартной библиотеки. Так как метод виртуальный, то его необходимо переопределять в наследниках класса CObject,
что мы тут и сделали.
А метод IsEqual() сравнивает поочерёдно каждое свойство двух сравниваемых объектов, и при первом же
неравенстве возвращает false — объекты не равны. По завершении трёх циклов по всем
свойствам двух сравниваемых объектов возвращается true — все свойства объектов равны.
Метод для копирования структуры торгового запроса в массивы свойств объекта-отложенного запроса:
//+------------------------------------------------------------------+ //| Копирует данные торгового запроса | //+------------------------------------------------------------------+ void CPendRequest::CopyRequest(const MqlTradeRequest &request) { //--- Копируем переданную структуру в структуру объекта this.m_request=request; //--- Целочисленные свойства структуры торгового запроса this.SetProperty(PEND_REQ_PROP_MQL_REQ_ACTION,request.action); // Тип выполняемого действия в структуре запроса this.SetProperty(PEND_REQ_PROP_MQL_REQ_TYPE,request.type); // Тип ордера в структуре запроса this.SetProperty(PEND_REQ_PROP_MQL_REQ_MAGIC,request.magic); // Штамп эксперта (идентификатор magic number) в структуре запроса this.SetProperty(PEND_REQ_PROP_MQL_REQ_ORDER,request.order); // Тикет ордера в структуре запроса this.SetProperty(PEND_REQ_PROP_MQL_REQ_POSITION,request.position); // Тикет позиции в структуре запроса this.SetProperty(PEND_REQ_PROP_MQL_REQ_POSITION_BY,request.position_by); // Тикет встречной позиции в структуре запроса this.SetProperty(PEND_REQ_PROP_MQL_REQ_DEVIATION,request.deviation); // Максимально приемлемое отклонение от запрашиваемой цены в структуре запроса this.SetProperty(PEND_REQ_PROP_MQL_REQ_EXPIRATION,request.expiration); // Срок истечения ордера (для ордеров типа ORDER_TIME_SPECIFIED) в структуре запроса this.SetProperty(PEND_REQ_PROP_MQL_REQ_TYPE_FILLING,request.type_filling); // Тип ордера по исполнению в структуре запроса this.SetProperty(PEND_REQ_PROP_MQL_REQ_TYPE_TIME,request.type_time); // Тип ордера по времени действия в структуре запроса //--- Вещественные свойства структуры торгового запроса this.SetProperty(PEND_REQ_PROP_MQL_REQ_VOLUME,request.volume); // Запрашиваемый объем сделки в лотах в структуре запроса this.SetProperty(PEND_REQ_PROP_MQL_REQ_PRICE,request.price); // Цена в структуре запроса this.SetProperty(PEND_REQ_PROP_MQL_REQ_STOPLIMIT,request.stoplimit); // Уровень StopLimit ордера в структуре запроса this.SetProperty(PEND_REQ_PROP_MQL_REQ_SL,request.sl); // Уровень Stop Loss ордера в структуре запроса this.SetProperty(PEND_REQ_PROP_MQL_REQ_TP,request.tp); // Уровень Take Profit ордера в структуре запроса //--- Строковые свойства структуры торгового запроса this.SetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL,request.symbol); // Имя торгового инструмента в структуре запроса this.SetProperty(PEND_REQ_PROP_MQL_REQ_COMMENT,request.comment); // Комментарий к ордеру в структуре запроса } //+------------------------------------------------------------------+
Здесь сначала копируем значения всех полей переданной в метод структуры торгового
запроса в такую же структуру объекта-запроса, а затем
значения всех полей структуры устанавливаем свойствам объекта при помощи методов установки свойств SetProperty().
Методы, возвращающие описания целочисленных, вещественных и строковых свойств объекта-отложенного запроса:
//+------------------------------------------------------------------+ //| Возвращает описание целочисленного свойства запроса | //+------------------------------------------------------------------+ string CPendRequest::GetPropertyDescription(ENUM_PEND_REQ_PROP_INTEGER property) { return ( property==PEND_REQ_PROP_STATUS ? this.StatusDescription() : property==PEND_REQ_PROP_TYPE ? this.TypeRequestDescription() : property==PEND_REQ_PROP_ID ? this.IDDescription() : property==PEND_REQ_PROP_RETCODE ? this.RetcodeDescription() : property==PEND_REQ_PROP_TIME_CREATE ? this.TimeCreateDescription() : property==PEND_REQ_PROP_TIME_ACTIVATE ? this.TimeActivateDescription() : property==PEND_REQ_PROP_WAITING ? this.TimeWaitingDescription() : property==PEND_REQ_PROP_CURENT ? this.CurrentAttemptDescription() : property==PEND_REQ_PROP_TOTAL ? this.TotalAttemptsDescription() : //--- MqlTradeRequest property==PEND_REQ_PROP_MQL_REQ_ACTION ? this.MqlReqActionDescription() : property==PEND_REQ_PROP_MQL_REQ_TYPE ? this.MqlReqTypeOrderDescription() : property==PEND_REQ_PROP_MQL_REQ_MAGIC ? this.MqlReqMagicDescription() : property==PEND_REQ_PROP_MQL_REQ_ORDER ? this.MqlReqOrderDescription() : property==PEND_REQ_PROP_MQL_REQ_POSITION ? this.MqlReqPositionDescription() : property==PEND_REQ_PROP_MQL_REQ_POSITION_BY ? this.MqlReqPositionByDescription() : property==PEND_REQ_PROP_MQL_REQ_DEVIATION ? this.MqlReqDeviationDescription() : property==PEND_REQ_PROP_MQL_REQ_EXPIRATION ? this.MqlReqExpirationDescription() : property==PEND_REQ_PROP_MQL_REQ_TYPE_FILLING ? this.MqlReqTypeFillingDescription() : property==PEND_REQ_PROP_MQL_REQ_TYPE_TIME ? this.MqlReqTypeTimeDescription() : ::EnumToString(property) ); } //+------------------------------------------------------------------+ //| Возвращает описание вещественного свойства запроса | //+------------------------------------------------------------------+ string CPendRequest::GetPropertyDescription(ENUM_PEND_REQ_PROP_DOUBLE property) { return ( property==PEND_REQ_PROP_PRICE_CREATE ? this.PriceCreateDescription() : //--- MqlTradeRequest property==PEND_REQ_PROP_MQL_REQ_VOLUME ? this.MqlReqVolumeDescription() : property==PEND_REQ_PROP_MQL_REQ_PRICE ? this.MqlReqPriceDescription() : property==PEND_REQ_PROP_MQL_REQ_STOPLIMIT ? this.MqlReqStopLimitDescription() : property==PEND_REQ_PROP_MQL_REQ_SL ? this.MqlReqStopLossDescription() : property==PEND_REQ_PROP_MQL_REQ_TP ? this.MqlReqTakeProfitDescription() : ::EnumToString(property) ); } //+------------------------------------------------------------------+ //| Возвращает описание строкового свойства запроса | //+------------------------------------------------------------------+ string CPendRequest::GetPropertyDescription(ENUM_PEND_REQ_PROP_STRING property) { return ( property==PEND_REQ_PROP_MQL_REQ_SYMBOL ? this.MqlReqSymbolDescription() : property==PEND_REQ_PROP_MQL_REQ_COMMENT ? this.MqlReqCommentDescription() : ::EnumToString(property) ); } //+------------------------------------------------------------------+
В метод передаётся свойство, и далее в зависимости от значения
свойства возвращается его строковое описание
при помощи методов, возвращающих описание этого свойства:
//+------------------------------------------------------------------+ //| Возвращает наименование статуса отложенного запроса | //+------------------------------------------------------------------+ string CPendRequest::StatusDescription(void) const { int code_descr= ( this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_OPEN ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_OPEN : this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_CLOSE ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_CLOSE : this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_SLTP ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_SLTP : this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_PLACE ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_PLACE : this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_REMOVE ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_REMOVE : this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_MODIFY ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_MODIFY : MSG_EVN_STATUS_UNKNOWN ); return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_STATUS)+": "+CMessage::Text(code_descr); } //+------------------------------------------------------------------+ //| Возвращает наименование типа отложенного запроса | //+------------------------------------------------------------------+ string CPendRequest::TypeRequestDescription(void) const { int code_descr= ( this.GetProperty(PEND_REQ_PROP_TYPE)==PEND_REQ_TYPE_ERROR ? MSG_LIB_TEXT_PEND_REQUEST_BY_ERROR : this.GetProperty(PEND_REQ_PROP_TYPE)==PEND_REQ_TYPE_REQUEST ? MSG_LIB_TEXT_PEND_REQUEST_BY_REQUEST : MSG_SYM_MODE_UNKNOWN ); return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_TYPE)+": "+CMessage::Text(code_descr); } //+------------------------------------------------------------------+ //| Возвращает описание идентификатора отложенного запроса | //+------------------------------------------------------------------+ string CPendRequest::IDDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_ID)+": #"+(string)this.GetProperty(PEND_REQ_PROP_ID); } //+------------------------------------------------------------------+ //| Возвращает описание кода ошибки, по которому создан запрос | //+------------------------------------------------------------------+ string CPendRequest::RetcodeDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_RETCODE)+": "+ CMessage::Text((int)this.GetProperty(PEND_REQ_PROP_RETCODE))+ " ("+(string)this.GetProperty(PEND_REQ_PROP_RETCODE)+")"; } //+------------------------------------------------------------------+ //| Возвращает описание времени создания отложенного запроса | //+------------------------------------------------------------------+ string CPendRequest::TimeCreateDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_TIME_CREATE)+": "+::TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)); } //+------------------------------------------------------------------+ //| Возвращает описание времени активации отложенного запроса | //+------------------------------------------------------------------+ string CPendRequest::TimeActivateDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_TIME_ACTIVATE)+": "+::TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_ACTIVATE)); } //+------------------------------------------------------------------+ //| Возвращает описание времени ожидания отложенного запроса | //+------------------------------------------------------------------+ string CPendRequest::TimeWaitingDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_WAITING)+": "+ (string)this.GetProperty(PEND_REQ_PROP_WAITING)+ " ("+::TimeToString(this.GetProperty(PEND_REQ_PROP_WAITING)/1000,TIME_MINUTES|TIME_SECONDS)+")"; } //+------------------------------------------------------------------+ //| Возвращает описание текущей попытки отложенного запроса | //+------------------------------------------------------------------+ string CPendRequest::CurrentAttemptDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_CURRENT_ATTEMPT)+": "+(string)this.GetProperty(PEND_REQ_PROP_CURENT); } //+------------------------------------------------------------------+ //| Возвращает описание количества попыток отложенного запроса | //+------------------------------------------------------------------+ string CPendRequest::TotalAttemptsDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_TOTAL_ATTEMPTS)+": "+(string)this.GetProperty(PEND_REQ_PROP_TOTAL); } //+------------------------------------------------------------------+ //| Возвращает описание значения цены при создании запроса | //+------------------------------------------------------------------+ string CPendRequest::PriceCreateDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_PRICE_CREATE)+": "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_PRICE_CREATE),this.m_digits); } //+------------------------------------------------------------------+ //| Возвращает описание типа выполняемого действия | //+------------------------------------------------------------------+ string CPendRequest::MqlReqActionDescription(void) const { int code_descr= ( this.GetProperty(PEND_REQ_PROP_MQL_REQ_ACTION)==TRADE_ACTION_DEAL ? MSG_LIB_TEXT_REQUEST_ACTION_DEAL : this.GetProperty(PEND_REQ_PROP_MQL_REQ_ACTION)==TRADE_ACTION_PENDING ? MSG_LIB_TEXT_REQUEST_ACTION_PENDING : this.GetProperty(PEND_REQ_PROP_MQL_REQ_ACTION)==TRADE_ACTION_SLTP ? MSG_LIB_TEXT_REQUEST_ACTION_SLTP : this.GetProperty(PEND_REQ_PROP_MQL_REQ_ACTION)==TRADE_ACTION_MODIFY ? MSG_LIB_TEXT_REQUEST_ACTION_MODIFY : this.GetProperty(PEND_REQ_PROP_MQL_REQ_ACTION)==TRADE_ACTION_REMOVE ? MSG_LIB_TEXT_REQUEST_ACTION_REMOVE : this.GetProperty(PEND_REQ_PROP_MQL_REQ_ACTION)==TRADE_ACTION_CLOSE_BY ? MSG_LIB_TEXT_REQUEST_ACTION_CLOSE_BY : MSG_LIB_TEXT_REQUEST_ACTION_UNCNOWN ); return CMessage::Text(MSG_LIB_TEXT_REQUEST_ACTION)+": "+CMessage::Text(code_descr); } //+------------------------------------------------------------------+ //| Возвращает описание значения магического номера | //+------------------------------------------------------------------+ string CPendRequest::MqlReqMagicDescription(void) const { return CMessage::Text(MSG_ORD_MAGIC)+": "+(string)this.GetProperty(PEND_REQ_PROP_MQL_REQ_MAGIC)+ (this.GetMagicID()!=this.GetProperty(PEND_REQ_PROP_MQL_REQ_MAGIC) ? " ("+(string)this.GetMagicID()+")" : ""); } //+------------------------------------------------------------------+ //| Возвращает описание значения тикета ордера | //+------------------------------------------------------------------+ string CPendRequest::MqlReqOrderDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_ORDER)+": "+ (this.GetProperty(PEND_REQ_PROP_MQL_REQ_ORDER)>0 ? "#"+(string)this.GetProperty(PEND_REQ_PROP_MQL_REQ_ORDER) : CMessage::Text(MSG_LIB_PROP_NOT_SET)); } //+------------------------------------------------------------------+ //| Возвращает описание тикета позиции в запросе | //+------------------------------------------------------------------+ string CPendRequest::MqlReqPositionDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_POSITION)+": "+ (this.GetProperty(PEND_REQ_PROP_MQL_REQ_POSITION)>0 ? (string)this.GetProperty(PEND_REQ_PROP_MQL_REQ_POSITION) : CMessage::Text(MSG_LIB_PROP_NOT_SET)); } //+------------------------------------------------------------------+ //| Возвращает описание тикета встречной позиции в запросе | //+------------------------------------------------------------------+ string CPendRequest::MqlReqPositionByDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_POSITION_BY)+": "+ (this.GetProperty(PEND_REQ_PROP_MQL_REQ_POSITION_BY)>0 ? (string)this.GetProperty(PEND_REQ_PROP_MQL_REQ_POSITION_BY) : CMessage::Text(MSG_LIB_PROP_NOT_SET)); } //+------------------------------------------------------------------+ //| Возвращает описание значения размера отклонения в запросе | //+------------------------------------------------------------------+ string CPendRequest::MqlReqDeviationDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_DEVIATION)+": "+(string)this.GetProperty(PEND_REQ_PROP_MQL_REQ_DEVIATION); } //+------------------------------------------------------------------+ //| Возвращает описание типа ордера в запросе | //+------------------------------------------------------------------+ string CPendRequest::MqlReqTypeOrderDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_TYPE)+": "+OrderTypeDescription((ENUM_ORDER_TYPE)this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE)); } //+------------------------------------------------------------------+ //| Возвращает описание режима заливки ордера в запросе | //+------------------------------------------------------------------+ string CPendRequest::MqlReqTypeFillingDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_TYPE_FILLING)+": "+OrderTypeFillingDescription((ENUM_ORDER_TYPE_FILLING)this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE_FILLING)); } //+------------------------------------------------------------------+ //| Возвращает описание типа срока действия ордера в запросе | //+------------------------------------------------------------------+ string CPendRequest::MqlReqTypeTimeDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_TYPE_TIME)+": "+OrderTypeTimeDescription((ENUM_ORDER_TYPE_TIME)this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE_TIME)); } //+------------------------------------------------------------------+ //| Возвращает описание срока истечения ордера в запросе | //+------------------------------------------------------------------+ string CPendRequest::MqlReqExpirationDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_EXPIRATION)+": "+ (this.GetProperty(PEND_REQ_PROP_MQL_REQ_EXPIRATION)>0 ? ::TimeToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_EXPIRATION)) : CMessage::Text(MSG_LIB_PROP_NOT_SET)); } //+------------------------------------------------------------------+ //| Возвращает описание объёма в запросе | //+------------------------------------------------------------------+ string CPendRequest::MqlReqVolumeDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_VOLUME)+": "+ (this.GetProperty(PEND_REQ_PROP_MQL_REQ_VOLUME)>0 ? ::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_VOLUME),this.m_digits_lot) : CMessage::Text(MSG_LIB_PROP_NOT_SET)); } //+------------------------------------------------------------------+ //| Возвращает описание значения цены в запросе | //+------------------------------------------------------------------+ string CPendRequest::MqlReqPriceDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE)+": "+ (this.GetProperty(PEND_REQ_PROP_MQL_REQ_PRICE)>0 ? ::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_PRICE),this.m_digits) : CMessage::Text(MSG_LIB_PROP_NOT_SET)); } //+------------------------------------------------------------------+ //| Возвращает описание значения цены StopLimit-ордера запросе | //+------------------------------------------------------------------+ string CPendRequest::MqlReqStopLimitDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_STOPLIMIT)+": "+ (this.GetProperty(PEND_REQ_PROP_MQL_REQ_STOPLIMIT)>0 ? ::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_STOPLIMIT),this.m_digits) : CMessage::Text(MSG_LIB_PROP_NOT_SET)); } //+------------------------------------------------------------------+ //| Возвращает описание значения цены StopLoss-ордера запросе | //+------------------------------------------------------------------+ string CPendRequest::MqlReqStopLossDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_SL)+": "+ (this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL)>0 ? ::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL),this.m_digits) : CMessage::Text(MSG_LIB_PROP_NOT_SET)); } //+------------------------------------------------------------------+ //| Возвращает описание значения цены TakeProfit-ордера запросе | //+------------------------------------------------------------------+ string CPendRequest::MqlReqTakeProfitDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_TP)+": "+ (this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP)>0 ? ::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP),this.m_digits) : CMessage::Text(MSG_LIB_PROP_NOT_SET)); } //+------------------------------------------------------------------+ //| Возвращает описание имени торгового инструмента в запросе | //+------------------------------------------------------------------+ string CPendRequest::MqlReqSymbolDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_SYMBOL)+": "+this.GetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL); } //+------------------------------------------------------------------+ //| Возвращает описание комментария ордера в запросе | //+------------------------------------------------------------------+ string CPendRequest::MqlReqCommentDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_COMMENT)+": "+ (this.GetProperty(PEND_REQ_PROP_MQL_REQ_COMMENT)!="" && this.GetProperty(PEND_REQ_PROP_MQL_REQ_COMMENT)!=NULL ? "\""+this.GetProperty(PEND_REQ_PROP_MQL_REQ_COMMENT)+"\"" : CMessage::Text(MSG_LIB_PROP_NOT_SET)); } //+------------------------------------------------------------------+
В методах проверяется значение переданного свойства, создаётся его текстовое описание и возвращается созданная строка текста.
Для полного вывода всех свойств объекта в журнал служит метод Print():
//+------------------------------------------------------------------+ //| Выводит в журнал свойства отложенного запроса | //+------------------------------------------------------------------+ void CPendRequest::Print(const bool full_prop=false) { int header_code= ( this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_OPEN ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_OPEN : this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_CLOSE ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_CLOSE : this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_SLTP ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_SLTP : this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_PLACE ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_PLACE : this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_REMOVE ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_REMOVE : this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_MODIFY ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_MODIFY : WRONG_VALUE ); ::Print("============= \"",CMessage::Text(header_code),"\" ============="); int beg=0, end=PEND_REQ_PROP_INTEGER_TOTAL; for(int i=beg; i<end; i++) { ENUM_PEND_REQ_PROP_INTEGER prop=(ENUM_PEND_REQ_PROP_INTEGER)i; if(!full_prop && !this.SupportProperty(prop)) continue; ::Print(this.GetPropertyDescription(prop)); } ::Print("------"); beg=end; end+=PEND_REQ_PROP_DOUBLE_TOTAL; for(int i=beg; i<end; i++) { ENUM_PEND_REQ_PROP_DOUBLE prop=(ENUM_PEND_REQ_PROP_DOUBLE)i; if(!full_prop && !this.SupportProperty(prop)) continue; ::Print(this.GetPropertyDescription(prop)); } ::Print("------"); beg=end; end+=PEND_REQ_PROP_STRING_TOTAL; for(int i=beg; i<end; i++) { ENUM_PEND_REQ_PROP_STRING prop=(ENUM_PEND_REQ_PROP_STRING)i; if(!full_prop && !this.SupportProperty(prop)) continue; ::Print(this.GetPropertyDescription(prop)); } ::Print("================== ",CMessage::Text(MSG_LIB_PARAMS_LIST_END),": \"",CMessage::Text(header_code),"\" ==================\n"); } //+------------------------------------------------------------------+
Такие методы мы создавали для всех предыдущих объектов библиотеки и разбирали их устройство с самого начала описания библиотеки, поэтому
здесь ограничимся таким его кратким описанием:
Проходим в трёх циклах по трём массивам свойств объекта, получаем каждое очередное
свойство объекта и выводим его описание в журнал в зависимости от флага вывода только поддерживаемых свойств объекта.
Метод PrintShort(), предназначенный для вывода краткого описания объекта-запроса, сделан виртуальным. В базовом объекте он
ничего не делает, и должен переопределяться в объектах-наследниках чтобы каждый наследник мог выводить в журнал сугубо свои,
пренадлежащие только ему, свойства.
Базовый объект абстрактного отложенного запроса мы создали.
Далее, для уточнения того, какой именно запрос необходимо
создавать, нам нужно создать шесть объектов-наследников от абстрактного объекта-запроса. И именно они и будут создаваться в торговых
методах торгового класса при обработке ошибок, требующих ожидания. А так же именно они будут создаваться как самостоятельные торговые
приказы при создании торговой логики при помощи отложенных торговых запросов.
Объекты-наследники базового объекта-отложенного запроса
Итак. В каждом торговом методе торгового класса у нас есть блоки создания отложенных запросов. Исходя из проводимой торговым методом операции мы будем создавать соответствующие отложенные запросы. Но пока у нас есть только базовый абстрактный отложенный запрос. Чтобы на его основании создавать разные торговые запросы по типу выполняемой операции, нам нужно создать шесть его наследников, где каждый наследуемый класс будет отсылать на сервер только присущую ему торговую операцию. Выше я приводил уже список таких объектов:
- открытие позиции
- модификация стоп-приказов открытой позиции
- закрытие позиции
- установка отложенного ордера
- модификация свойств отложенного ордера
- удаление ранее выставленного отложенного ордера
Как мы помним, в защищённом конструкторе базового абстрактного отложенного запроса есть параметр, указывающий на статус создаваемого запроса:
//--- Защищённый параметрический конструктор CPendRequest(const ENUM_PEND_REQ_STATUS status, const uchar id, const double price, const ulong time, const MqlTradeRequest &request, const int retcode);
Этот статус мы и будем указывать (передавать из конструктора наследуемого объекта в конструктор базового) при создании нового отложенного
запроса. Тем самым мы будем указывать какой тип запроса по выполняемой операции мы создаём. Это поведение мы разбирали во второй статье при создании
объектов исторических ордеров и сделок. Поэтому здесь не будем на этом останавливаться, а сразу рассмотрим все шесть
объектов отложенных запросов по типу проводимых торговых операций.
Все классы объектов-наследников базового торгового запроса
будем создавать в той же папке, в которой находится базовый объект:
\MQL5\Include\DoEasy\Objects\ PendRequest\
Класс объекта отложенного запроса на открытие позиции (Файл класса PendReqOpen.mqh):
//+------------------------------------------------------------------+ //| PendReqOpen.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 "PendRequest.mqh" //+------------------------------------------------------------------+ //| Отложенный запрос на открытие позиции | //+------------------------------------------------------------------+ class CPendReqOpen : public CPendRequest { public: //--- Конструктор CPendReqOpen(const uchar id, const double price, const ulong time, const MqlTradeRequest &request, const int retcode) : CPendRequest(PEND_REQ_STATUS_OPEN,id,price,time,request,retcode) {} //--- Поддерживаемые свойства сделки (1) вещественные, (2) целочисленные virtual bool SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_STRING property); //--- Выводит в журнал краткое сообщение с данными запроса virtual void PrintShort(void); }; //+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| целочисленное свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqOpen::SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property) { if(property==PEND_REQ_PROP_MQL_REQ_ORDER || property==PEND_REQ_PROP_MQL_REQ_POSITION || property==PEND_REQ_PROP_MQL_REQ_POSITION_BY || property==PEND_REQ_PROP_MQL_REQ_EXPIRATION || property==PEND_REQ_PROP_MQL_REQ_TYPE_TIME ) return false; return true; } //+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| вещественное свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqOpen::SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property) { return(property==PEND_REQ_PROP_MQL_REQ_STOPLIMIT ? false : true); } //+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| строковое свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqOpen::SupportProperty(ENUM_PEND_REQ_PROP_STRING property) { return true; } //+------------------------------------------------------------------+ //| Выводит в журнал краткое сообщение с данными запроса | //+------------------------------------------------------------------+ void CPendReqOpen::PrintShort(void) { string params=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_VOLUME),this.m_digits_lot)+" "+ OrderTypeDescription((ENUM_ORDER_TYPE)this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE)); string price=CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_PRICE),this.m_digits); string sl=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_SL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL),this.m_digits) : ""; string tp=this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_TP)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP),this.m_digits) : ""; string time=this.IDDescription()+", "+CMessage::Text(MSG_LIB_TEXT_CREATED)+" "+TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)); string attempts=CMessage::Text(MSG_LIB_TEXT_ATTEMPTS)+" "+(string)this.GetProperty(PEND_REQ_PROP_TOTAL); string wait=CMessage::Text(MSG_LIB_TEXT_WAIT)+" "+::TimeToString(this.GetProperty(PEND_REQ_PROP_WAITING)/1000,TIME_SECONDS); string end=CMessage::Text(MSG_LIB_TEXT_END)+" "+ TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)+this.GetProperty(PEND_REQ_PROP_WAITING)*this.GetProperty(PEND_REQ_PROP_TOTAL)); //--- string message=CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_STATUS_OPEN)+": "+ "\n- "+params+", "+price+sl+tp+ "\n- "+time+", "+attempts+", "+wait+", "+end+"\n"; ::Print(message); } //+------------------------------------------------------------------+
Метод достаточно примитивен. Всё, что он делает — передаёт в своём конструкторе в списке инициализации в конструктор базового объекта статус создаваемого объекта (открытие позиции) и все входные параметры своего конструктора:
//--- Конструктор CPendReqOpen(const uchar id, const double price, const ulong time, const MqlTradeRequest &request, const int retcode) : CPendRequest(PEND_REQ_STATUS_OPEN,id,price,time,request,retcode) {}
Виртуальные методы, возвращающие флаг поддержания объектом некоторых целочисленных, вещественных и строковых свойств:
//+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| целочисленное свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqOpen::SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property) { if(property==PEND_REQ_PROP_MQL_REQ_ORDER || property==PEND_REQ_PROP_MQL_REQ_POSITION || property==PEND_REQ_PROP_MQL_REQ_POSITION_BY || property==PEND_REQ_PROP_MQL_REQ_EXPIRATION || property==PEND_REQ_PROP_MQL_REQ_TYPE_TIME ) return false; return true; } //+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| вещественное свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqOpen::SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property) { return(property==PEND_REQ_PROP_MQL_REQ_STOPLIMIT ? false : true); } //+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| строковое свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqOpen::SupportProperty(ENUM_PEND_REQ_PROP_STRING property) { return true; } //+------------------------------------------------------------------+
Если объектом-наследником базового абстрактного торгового запроса не поддерживается какое-либо свойство, то метод возвращает ложь, иначе — истину. Как это всё работает мы тоже рассматривали во второй статье описания библиотеки при рассмотрении создания объектов исторических ордеров и сделок.
Виртуальный метод создания и вывода краткого описания запроса:
//+------------------------------------------------------------------+ //| Выводит в журнал краткое сообщение с данными запроса | //+------------------------------------------------------------------+ void CPendReqOpen::PrintShort(void) { string params=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_VOLUME),this.m_digits_lot)+" "+ OrderTypeDescription((ENUM_ORDER_TYPE)this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE)); string price=CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_PRICE),this.m_digits); string sl=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_SL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL),this.m_digits) : ""; string tp=this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_TP)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP),this.m_digits) : ""; string time=this.IDDescription()+", "+CMessage::Text(MSG_LIB_TEXT_CREATED)+" "+TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)); string attempts=CMessage::Text(MSG_LIB_TEXT_ATTEMPTS)+" "+(string)this.GetProperty(PEND_REQ_PROP_TOTAL); string wait=CMessage::Text(MSG_LIB_TEXT_WAIT)+" "+::TimeToString(this.GetProperty(PEND_REQ_PROP_WAITING)/1000,TIME_SECONDS); string end=CMessage::Text(MSG_LIB_TEXT_END)+" "+ TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)+this.GetProperty(PEND_REQ_PROP_WAITING)*this.GetProperty(PEND_REQ_PROP_TOTAL)); //--- string message=CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_STATUS_OPEN)+": "+ "\n- "+params+", "+price+sl+tp+ "\n- "+time+", "+attempts+", "+wait+", "+end+"\n"; ::Print(message); } //+------------------------------------------------------------------+
В методе создаются строки описания некоторых используемых объектом параметров и составляется из них итоговое сообщение, которое и
выводится в журнал. Метод виртуальный, и реализован по-своему в каждом из объектов-наследников базового объекта абстрактного запроса.
Класс объекта отложенного запроса на модификацию стоп-приказов открытой позиции (Файл класса PendReqSLTP.mqh):
//+------------------------------------------------------------------+ //| PendReqSLTP.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 "PendRequest.mqh" //+------------------------------------------------------------------+ //| Отложенный запрос на мидификацию стоп-приказов позиции | //+------------------------------------------------------------------+ class CPendReqSLTP : public CPendRequest { public: //--- Конструктор CPendReqSLTP(const uchar id, const double price, const ulong time, const MqlTradeRequest &request, const int retcode) : CPendRequest(PEND_REQ_STATUS_SLTP,id,price,time,request,retcode) {} //--- Поддерживаемые свойства сделки (1) вещественные, (2) целочисленные virtual bool SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_STRING property); //--- Выводит в журнал краткое сообщение с данными запроса virtual void PrintShort(void); }; //+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| целочисленное свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqSLTP::SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property) { if(property==PEND_REQ_PROP_MQL_REQ_POSITION_BY || property==PEND_REQ_PROP_MQL_REQ_ORDER || property==PEND_REQ_PROP_MQL_REQ_EXPIRATION || property==PEND_REQ_PROP_MQL_REQ_DEVIATION || property==PEND_REQ_PROP_MQL_REQ_TYPE_FILLING || property==PEND_REQ_PROP_MQL_REQ_TYPE_TIME ) return false; return true; } //+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| вещественное свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqSLTP::SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property) { if(property==PEND_REQ_PROP_PRICE_CREATE || property==PEND_REQ_PROP_MQL_REQ_SL || property==PEND_REQ_PROP_MQL_REQ_TP ) return true; return false; } //+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| строковое свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqSLTP::SupportProperty(ENUM_PEND_REQ_PROP_STRING property) { return true; } //+------------------------------------------------------------------+ //| Выводит в журнал краткое сообщение с данными запроса | //+------------------------------------------------------------------+ void CPendReqSLTP::PrintShort(void) { string params=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_VOLUME),this.m_digits_lot)+" "+ PositionTypeDescription((ENUM_POSITION_TYPE)this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE))+" #"+(string)this.GetProperty(PEND_REQ_PROP_MQL_REQ_POSITION); string sl=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_SL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL),this.m_digits) : ""; string tp=this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_TP)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP),this.m_digits) : ""; string time=this.IDDescription()+", "+CMessage::Text(MSG_LIB_TEXT_CREATED)+" "+TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)); string attempts=CMessage::Text(MSG_LIB_TEXT_ATTEMPTS)+" "+(string)this.GetProperty(PEND_REQ_PROP_TOTAL); string wait=CMessage::Text(MSG_LIB_TEXT_WAIT)+" "+::TimeToString(this.GetProperty(PEND_REQ_PROP_WAITING)/1000,TIME_SECONDS); string end=CMessage::Text(MSG_LIB_TEXT_END)+" "+ TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)+this.GetProperty(PEND_REQ_PROP_WAITING)*this.GetProperty(PEND_REQ_PROP_TOTAL)); //--- string message=CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_STATUS_SLTP)+": "+ "\n- "+params+sl+tp+ "\n- "+time+", "+attempts+", "+wait+", "+end+"\n"; ::Print(message); } //+------------------------------------------------------------------+
Класс объекта отложенного запроса на закрытие позиции (Файл класса PendReqClose.mqh):
//+------------------------------------------------------------------+ //| PendReqClose.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 "PendRequest.mqh" //+------------------------------------------------------------------+ //| Отложенный запрос на закрытие позиции | //+------------------------------------------------------------------+ class CPendReqClose : public CPendRequest { public: //--- Конструктор CPendReqClose(const uchar id, const double price, const ulong time, const MqlTradeRequest &request, const int retcode) : CPendRequest(PEND_REQ_STATUS_CLOSE,id,price,time,request,retcode) {} //--- Поддерживаемые свойства сделки (1) вещественные, (2) целочисленные virtual bool SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_STRING property); //--- Выводит в журнал краткое сообщение с данными запроса virtual void PrintShort(void); }; //+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| целочисленное свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqClose::SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property) { if(( property==PEND_REQ_PROP_MQL_REQ_POSITION_BY && this.GetProperty(property)==0) || property==PEND_REQ_PROP_MQL_REQ_ORDER || property==PEND_REQ_PROP_MQL_REQ_EXPIRATION || property==PEND_REQ_PROP_MQL_REQ_TYPE_TIME ) return false; return true; } //+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| вещественное свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqClose::SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property) { if(property==PEND_REQ_PROP_MQL_REQ_STOPLIMIT || property==PEND_REQ_PROP_MQL_REQ_SL || property==PEND_REQ_PROP_MQL_REQ_TP ) return false; return true; } //+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| строковое свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqClose::SupportProperty(ENUM_PEND_REQ_PROP_STRING property) { return true; } //+------------------------------------------------------------------+ //| Выводит в журнал краткое сообщение с данными запроса | //+------------------------------------------------------------------+ void CPendReqClose::PrintShort(void) { string params=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_VOLUME),this.m_digits_lot)+" "+ PositionTypeDescription((ENUM_POSITION_TYPE)this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE))+" #"+(string)this.GetProperty(PEND_REQ_PROP_MQL_REQ_POSITION); string pos_by=(this.GetProperty(PEND_REQ_PROP_MQL_REQ_POSITION_BY)>0 ? ", "+CMessage::Text(MSG_ORD_DEAL_OUT_BY)+" #"+(string)this.GetProperty(PEND_REQ_PROP_MQL_REQ_POSITION_BY) : ""); string price=CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_PRICE_CREATE),this.m_digits); string time=this.IDDescription()+", "+CMessage::Text(MSG_LIB_TEXT_CREATED)+" "+TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)); string attempts=CMessage::Text(MSG_LIB_TEXT_ATTEMPTS)+" "+(string)this.GetProperty(PEND_REQ_PROP_TOTAL); string wait=CMessage::Text(MSG_LIB_TEXT_WAIT)+" "+::TimeToString(this.GetProperty(PEND_REQ_PROP_WAITING)/1000,TIME_SECONDS); string end=CMessage::Text(MSG_LIB_TEXT_END)+" "+ TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)+this.GetProperty(PEND_REQ_PROP_WAITING)*this.GetProperty(PEND_REQ_PROP_TOTAL)); //--- string message=CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_STATUS_CLOSE)+": "+ "\n- "+params+", "+price+pos_by+ "\n- "+time+", "+attempts+", "+wait+", "+end+"\n"; ::Print(message); } //+------------------------------------------------------------------+
Класс объекта отложенного запроса на установку отложенного ордера (Файл класса PendReqPlace.mqh):
//+------------------------------------------------------------------+ //| PendReqPlace.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 "PendRequest.mqh" //+------------------------------------------------------------------+ //| Отложенный запрос на установку отложенного ордера | //+------------------------------------------------------------------+ class CPendReqPlace : public CPendRequest { public: //--- Конструктор CPendReqPlace(const uchar id, const double price, const ulong time, const MqlTradeRequest &request, const int retcode) : CPendRequest(PEND_REQ_STATUS_PLACE,id,price,time,request,retcode) {} //--- Поддерживаемые свойства сделки (1) вещественные, (2) целочисленные virtual bool SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_STRING property); //--- Выводит в журнал краткое сообщение с данными запроса virtual void PrintShort(void); }; //+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| целочисленное свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqPlace::SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property) { if(property==PEND_REQ_PROP_MQL_REQ_ORDER || property==PEND_REQ_PROP_MQL_REQ_POSITION || property==PEND_REQ_PROP_MQL_REQ_POSITION_BY || property==PEND_REQ_PROP_MQL_REQ_DEVIATION ) return false; return true; } //+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| вещественное свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqPlace::SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property) { return true; } //+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| строковое свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqPlace::SupportProperty(ENUM_PEND_REQ_PROP_STRING property) { return true; } //+------------------------------------------------------------------+ //| Выводит в журнал краткое сообщение с данными запроса | //+------------------------------------------------------------------+ void CPendReqPlace::PrintShort(void) { string params=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_VOLUME),this.m_digits_lot)+" "+ OrderTypeDescription((ENUM_ORDER_TYPE)this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE)); string price=CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_PRICE),this.m_digits); string stoplimit=this.GetProperty(PEND_REQ_PROP_MQL_REQ_STOPLIMIT)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_STOPLIMIT)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_STOPLIMIT),this.m_digits) : ""; string sl=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_SL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL),this.m_digits) : ""; string tp=this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_TP)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP),this.m_digits) : ""; string time=this.IDDescription()+", "+CMessage::Text(MSG_LIB_TEXT_CREATED)+" "+TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)); string attempts=CMessage::Text(MSG_LIB_TEXT_ATTEMPTS)+" "+(string)this.GetProperty(PEND_REQ_PROP_TOTAL); string wait=CMessage::Text(MSG_LIB_TEXT_WAIT)+" "+::TimeToString(this.GetProperty(PEND_REQ_PROP_WAITING)/1000,TIME_SECONDS); string end=CMessage::Text(MSG_LIB_TEXT_END)+" "+ TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)+this.GetProperty(PEND_REQ_PROP_WAITING)*this.GetProperty(PEND_REQ_PROP_TOTAL)); //--- string message=CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_STATUS_PLACE)+": "+ "\n- "+params+", "+price+stoplimit+sl+tp+ "\n- "+time+", "+attempts+", "+wait+", "+end+"\n"; ::Print(message); } //+------------------------------------------------------------------+
Класс объекта отложенного запроса на модификацию параметров установленного отложенного ордера (Файл класса PendReqModify.mqh):
//+------------------------------------------------------------------+ //| PendReqModify.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 "PendRequest.mqh" //+------------------------------------------------------------------+ //| Отложенный запрос на мидификацию параметров отложенного ордера | //+------------------------------------------------------------------+ class CPendReqModify : public CPendRequest { public: //--- Конструктор CPendReqModify(const uchar id, const double price, const ulong time, const MqlTradeRequest &request, const int retcode) : CPendRequest(PEND_REQ_STATUS_MODIFY,id,price,time,request,retcode) {} //--- Поддерживаемые свойства сделки (1) вещественные, (2) целочисленные virtual bool SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_STRING property); //--- Выводит в журнал краткое сообщение с данными запроса virtual void PrintShort(void); }; //+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| целочисленное свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqModify::SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property) { if(property==PEND_REQ_PROP_MQL_REQ_POSITION || property==PEND_REQ_PROP_MQL_REQ_POSITION_BY || property==PEND_REQ_PROP_MQL_REQ_DEVIATION ) return false; return true; } //+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| вещественное свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqModify::SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property) { return(property==PEND_REQ_PROP_MQL_REQ_VOLUME ? false : true); } //+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| строковое свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqModify::SupportProperty(ENUM_PEND_REQ_PROP_STRING property) { return true; } //+------------------------------------------------------------------+ //| Выводит в журнал краткое сообщение с данными запроса | //+------------------------------------------------------------------+ void CPendReqModify::PrintShort(void) { string params=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_VOLUME),this.m_digits_lot)+" "+ OrderTypeDescription((ENUM_ORDER_TYPE)this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE))+" #"+(string)this.GetProperty(PEND_REQ_PROP_MQL_REQ_ORDER); string price=CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_PRICE),this.m_digits); string stoplimit=this.GetProperty(PEND_REQ_PROP_MQL_REQ_STOPLIMIT)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_STOPLIMIT)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_STOPLIMIT),this.m_digits) : ""; string sl=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_SL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL),this.m_digits) : ""; string tp=this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_TP)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP),this.m_digits) : ""; string expiration=this.GetProperty(PEND_REQ_PROP_MQL_REQ_EXPIRATION)>0 ? this.MqlReqExpirationDescription() : ""; string type_filling=this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE_FILLING)>WRONG_VALUE ? "\n- "+this.MqlReqTypeFillingDescription() : ""; string type_time=this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE_TIME)>WRONG_VALUE ? "\n- "+this.MqlReqTypeTimeDescription() : ""; string time=this.IDDescription()+", "+CMessage::Text(MSG_LIB_TEXT_CREATED)+" "+TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)); string attempts=CMessage::Text(MSG_LIB_TEXT_ATTEMPTS)+" "+(string)this.GetProperty(PEND_REQ_PROP_TOTAL); string wait=CMessage::Text(MSG_LIB_TEXT_WAIT)+" "+::TimeToString(this.GetProperty(PEND_REQ_PROP_WAITING)/1000,TIME_SECONDS); string end=CMessage::Text(MSG_LIB_TEXT_END)+" "+ TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)+this.GetProperty(PEND_REQ_PROP_WAITING)*this.GetProperty(PEND_REQ_PROP_TOTAL)); //--- string message=CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_STATUS_MODIFY)+": "+ "\n- "+params+", "+price+stoplimit+sl+tp+expiration+type_filling+type_time+ "\n- "+time+", "+attempts+", "+wait+", "+end+"\n"; ::Print(message); } //+------------------------------------------------------------------+
Класс объекта отложенного запроса на удаление отложенного ордера (Файл класса PendReqRemove.mqh):
//+------------------------------------------------------------------+ //| PendReqRemove.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 "PendRequest.mqh" //+------------------------------------------------------------------+ //| Отложенный запрос на удаление отложенного ордера | //+------------------------------------------------------------------+ class CPendReqRemove : public CPendRequest { public: //--- Конструктор CPendReqRemove(const uchar id, const double price, const ulong time, const MqlTradeRequest &request, const int retcode) : CPendRequest(PEND_REQ_STATUS_REMOVE,id,price,time,request,retcode) {} //--- Поддерживаемые свойства сделки (1) вещественные, (2) целочисленные virtual bool SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_STRING property); //--- Выводит в журнал краткое сообщение с данными запроса virtual void PrintShort(void); }; //+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| целочисленное свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqRemove::SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property) { return(property>PEND_REQ_PROP_MQL_REQ_ORDER ? false : true); } //+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| вещественное свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqRemove::SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property) { return(property==PEND_REQ_PROP_PRICE_CREATE || property==PEND_REQ_PROP_MQL_REQ_PRICE ? true : false); } //+------------------------------------------------------------------+ //| Возвращает истину, если ордер поддерживает переданное | //| строковое свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CPendReqRemove::SupportProperty(ENUM_PEND_REQ_PROP_STRING property) { return true; } //+------------------------------------------------------------------+ //| Выводит в журнал краткое сообщение с данными запроса | //+------------------------------------------------------------------+ void CPendReqRemove::PrintShort(void) { string params=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_VOLUME),this.m_digits_lot)+" "+ OrderTypeDescription((ENUM_ORDER_TYPE)this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE))+" #"+(string)this.GetProperty(PEND_REQ_PROP_MQL_REQ_ORDER); string price=CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_PRICE),this.m_digits); string stoplimit=this.GetProperty(PEND_REQ_PROP_MQL_REQ_STOPLIMIT)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_STOPLIMIT)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_STOPLIMIT),this.m_digits) : ""; string time=this.IDDescription()+", "+CMessage::Text(MSG_LIB_TEXT_CREATED)+" "+TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)); string attempts=CMessage::Text(MSG_LIB_TEXT_ATTEMPTS)+" "+(string)this.GetProperty(PEND_REQ_PROP_TOTAL); string wait=CMessage::Text(MSG_LIB_TEXT_WAIT)+" "+::TimeToString(this.GetProperty(PEND_REQ_PROP_WAITING)/1000,TIME_SECONDS); string end=CMessage::Text(MSG_LIB_TEXT_END)+" "+ TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)+this.GetProperty(PEND_REQ_PROP_WAITING)*this.GetProperty(PEND_REQ_PROP_TOTAL)); //--- string message=CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_STATUS_REMOVE)+": "+ "\n- "+params+", "+price+stoplimit+ "\n- "+time+", "+attempts+", "+wait+", "+end+"\n"; ::Print(message); } //+------------------------------------------------------------------+
Самым важным отличительным моментом всех этих классов друг от друга является передача
статуса
отложенного запроса в конструктор родительского объекта — именно статус определяет какой тип проводимой торговой
операции будет делать каждый из этих объектов. Остальные же методы классов служат лишь вспомогательным целям, и на торговый результат не
влияют.
На этом мы закончили создание новых классов отложенных торговых запросов.
Теперь нужно удалить временно созданный
нами класс отложенного запроса из файла торгового класса и внести дополнительные исправления для работы с новыми объектами отложенных
торговых запросов.
Откроем файл Trading.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" #include "Collections\EventsCollection.mqh" //+------------------------------------------------------------------+ //| Класс объекта-отложенного запроса | //+------------------------------------------------------------------+ class CPendingReq : public CObject { private: MqlTradeRequest m_request; // Структура торгового запроса uchar m_id; // Идентификатор торгового запроса int m_type; // Тип отложенного запроса int m_retcode; // Результат, на основании которого создан запрос double m_price_create; // Цена при создании запроса ulong m_time_create; // Время создания запроса ulong m_time_activate; // Время активации очередной попытки ulong m_waiting_msc; // Продолжительность ожидания между запросами uchar m_current_attempt; // Номер текущей попытки uchar m_total_attempts; // Количество попыток //--- Копирует данные торгового запроса void CopyRequest(const MqlTradeRequest &request) { this.m_request=request; } //--- Сравнивает объекты CPendingReq между собой по идентификаторам virtual int Compare(const CObject *node,const int mode=0) const; public: //--- Возвращает (1) структуру запроса, (2) цену при создании запроса, //--- (3) время создания запроса, (4) время активации очередной попытки, //--- (5) продолжительность ожидания между запросами, (6) номер текущей попытки, //--- (7) количество попыток, (8) идентификатор запроса //--- (9) результат, на основании которого создан запрос, //--- (10) тикет ордера, (11) тикет позиции, (12) тип торговой операции MqlTradeRequest MqlRequest(void) const { return this.m_request; } double PriceCreate(void) const { return this.m_price_create; } ulong TimeCreate(void) const { return this.m_time_create; } ulong TimeActivate(void) const { return this.m_time_activate; } ulong WaitingMSC(void) const { return this.m_waiting_msc; } uchar CurrentAttempt(void) const { return this.m_current_attempt; } uchar TotalAttempts(void) const { return this.m_total_attempts; } uchar ID(void) const { return this.m_id; } int Retcode(void) const { return this.m_retcode; } ulong Order(void) const { return this.m_request.order; } ulong Position(void) const { return this.m_request.position;} ENUM_TRADE_REQUEST_ACTIONS Action(void) const { return this.m_request.action; } //--- Устанавливает (1) цену при создании запроса, (2) время создания запроса, //--- (3) время текущей попытки, (4) продолжительность ожидания между запросами, //--- (5) номер текущей попытки, (6) количество попыток, (7) идентификатор, //--- (8) тикет ордера, (9) тикет позиции void SetPriceCreate(const double price) { this.m_price_create=price; } void SetTimeCreate(const ulong time) { this.m_time_create=time; } void SetTimeActivate(const ulong time) { this.m_time_activate=time; } void SetWaitingMSC(const ulong miliseconds) { this.m_waiting_msc=miliseconds;} void SetCurrentAttempt(const uchar number) { this.m_current_attempt=number; } void SetTotalAttempts(const uchar number) { this.m_total_attempts=number; } void SetID(const uchar id) { this.m_id=id; } void SetOrder(const ulong ticket) { this.m_request.order=ticket; } void SetPosition(const ulong ticket) { this.m_request.position=ticket;} //--- Возвращает описание (1) структуры запроса, (2) цены при создании запроса, //--- (3) времени создания запроса, (4) времени текущей попытки, //--- (5) продолжительности ожидания между запросами, (6) номера текущей попытки, //--- (7) количества попыток, (8) идентификатора запроса string MqlRequestDescription(void) const { return RequestActionDescription(this.m_request); } string TypeDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_TYPE) + (this.Type()==PENDING_REQUEST_ID_TYPE_ERR ? CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_BY_ERROR) : CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_BY_REQUEST) ); } string PriceCreateDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_PRICE_CREATE)+": "+ ::DoubleToString(this.PriceCreate(),(int)::SymbolInfoInteger(this.m_request.symbol,SYMBOL_DIGITS)); } string TimeCreateDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_TIME_CREATE)+TimeMSCtoString(this.TimeCreate()); } string TimeActivateDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_TIME_ACTIVATE)+TimeMSCtoString(this.TimeActivate());} string WaitingMSCDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_WAITING)+(string)this.WaitingMSC(); } string CurrentAttemptDescription(void) const { return (CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_CURRENT_ATTEMPT)+ (this.CurrentAttempt()==0 ? CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_WAITING_ONSET) : (string)this.CurrentAttempt()) ); } string TotalAttemptsDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_TOTAL_ATTEMPTS)+(string)this.TotalAttempts(); } string IdDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_ID)+"#"+(string)this.ID(); } string RetcodeDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_RETCODE)+(string)this.Retcode(); } string ReasonDescription(void) const { return CMessage::Text(this.m_retcode); } //--- Возвращает тип запроса virtual int Type(void) const { return this.m_type; } //--- Выводит в журнал данные запроса void Print(void); //--- Конструкторы CPendingReq(void){;} CPendingReq(const uchar id,const double price,const ulong time,const MqlTradeRequest &request,const int retcode); }; //+------------------------------------------------------------------+ //| Параметрический конструктор | //+------------------------------------------------------------------+ CPendingReq::CPendingReq(const uchar id,const double price,const ulong time,const MqlTradeRequest &request,const int retcode) : m_price_create(price), m_time_create(time), m_id(id), m_retcode(retcode) { this.CopyRequest(request); this.m_type=(retcode>0 ? PENDING_REQUEST_ID_TYPE_ERR : PENDING_REQUEST_ID_TYPE_REQ); } //+------------------------------------------------------------------+ //| Сравнивает объекты CPendingReq между собой по свойствам | //+------------------------------------------------------------------+ int CPendingReq::Compare(const CObject *node,const int mode=0) const { const CPendingReq *compared_req=node; return ( //--- Сравнение по идентификатору mode==SORT_BY_PEND_REQ_ID ? (this.ID()>compared_req.ID() ? 1 : this.ID()<compared_req.ID() ? -1 : 0) : //--- Сравнение по типу mode==SORT_BY_PEND_REQ_TYPE ? (this.Type()>compared_req.Type() ? 1 : this.Type()<compared_req.Type() ? -1 : 0) : //--- Сравнение по тикету ( //--- модификация sl, tp позиции, открытие/закрытие позиции, или закрытие встречной this.m_request.action==TRADE_ACTION_SLTP || this.m_request.action==TRADE_ACTION_DEAL || this.m_request.action==TRADE_ACTION_CLOSE_BY ? (this.m_request.position>compared_req.m_request.position ? 1 : this.m_request.position<compared_req.m_request.position ? -1 : 0) : //--- модификация параметров, установка/удаление отложенного ордера this.m_request.action==TRADE_ACTION_MODIFY || this.m_request.action==TRADE_ACTION_PENDING || this.m_request.action==TRADE_ACTION_REMOVE ? (this.m_request.order>compared_req.m_request.order ? 1 : this.m_request.order<compared_req.m_request.order ? -1 : 0) : //--- иначе 0 ) ); } //+------------------------------------------------------------------+ //| Выводит в журнал данные запроса | //+------------------------------------------------------------------+ void CPendingReq::Print(void) { string action=" - "+RequestActionDescription(this.m_request)+"\n"; string symbol="",order="",volume="",price="",stoplimit="",sl="",tp="",deviation="",type="",type_filling=""; string type_time="",expiration="",position="",position_by="",magic="",comment="",request_data=""; string type_req=" - "+this.TypeDescription()+"\n"; if(this.m_request.action==TRADE_ACTION_DEAL) { symbol=" - "+RequestSymbolDescription(this.m_request)+"\n"; volume=" - "+RequestVolumeDescription(this.m_request)+"\n"; price=" - "+RequestPriceDescription(this.m_request)+"\n"; sl=" - "+RequestStopLossDescription(this.m_request)+"\n"; tp=" - "+RequestTakeProfitDescription(this.m_request)+"\n"; deviation=" - "+RequestDeviationDescription(this.m_request)+"\n"; type=" - "+RequestTypeDescription(this.m_request)+"\n"; type_filling=" - "+RequestTypeFillingDescription(this.m_request)+"\n"; magic=" - "+RequestMagicDescription(this.m_request)+"\n"; comment=" - "+RequestCommentDescription(this.m_request)+"\n"; request_data= ("================== "+ CMessage::Text(MSG_LIB_TEXT_REQUEST_DATAS)+" ==================\n"+ action+symbol+volume+price+sl+tp+deviation+type+type_filling+magic+comment+ " ==================\n" ); } else if(this.m_request.action==TRADE_ACTION_SLTP) { symbol=" - "+RequestSymbolDescription(this.m_request)+"\n"; sl=" - "+RequestStopLossDescription(this.m_request)+"\n"; tp=" - "+RequestTakeProfitDescription(this.m_request)+"\n"; position=" - "+RequestPositionDescription(this.m_request)+"\n"; request_data= ("================== "+ CMessage::Text(MSG_LIB_TEXT_REQUEST_DATAS)+" ==================\n"+ action+symbol+sl+tp+position+ " ==================\n" ); } else if(this.m_request.action==TRADE_ACTION_PENDING) { symbol=" - "+RequestSymbolDescription(this.m_request)+"\n"; volume=" - "+RequestVolumeDescription(this.m_request)+"\n"; price=" - "+RequestPriceDescription(this.m_request)+"\n"; stoplimit=" - "+RequestStopLimitDescription(this.m_request)+"\n"; sl=" - "+RequestStopLossDescription(this.m_request)+"\n"; tp=" - "+RequestTakeProfitDescription(this.m_request)+"\n"; type=" - "+RequestTypeDescription(this.m_request)+"\n"; type_filling=" - "+RequestTypeFillingDescription(this.m_request)+"\n"; type_time=" - "+RequestTypeTimeDescription(this.m_request)+"\n"; expiration=" - "+RequestExpirationDescription(this.m_request)+"\n"; magic=" - "+RequestMagicDescription(this.m_request)+"\n"; comment=" - "+RequestCommentDescription(this.m_request)+"\n"; request_data= ("================== "+ CMessage::Text(MSG_LIB_TEXT_REQUEST_DATAS)+" ==================\n"+ action+symbol+volume+price+stoplimit+sl+tp+type+type_filling+type_time+expiration+magic+comment+ " ==================\n" ); } else if(this.m_request.action==TRADE_ACTION_MODIFY) { order=" - "+RequestOrderDescription(this.m_request)+"\n"; price=" - "+RequestPriceDescription(this.m_request)+"\n"; sl=" - "+RequestStopLossDescription(this.m_request)+"\n"; tp=" - "+RequestTakeProfitDescription(this.m_request)+"\n"; type_time=" - "+RequestTypeTimeDescription(this.m_request)+"\n"; expiration=" - "+RequestExpirationDescription(this.m_request)+"\n"; request_data= ("================== "+ CMessage::Text(MSG_LIB_TEXT_REQUEST_DATAS)+" ==================\n"+ action+order+price+sl+tp+type_time+expiration+ " ==================\n" ); } else if(this.m_request.action==TRADE_ACTION_REMOVE) { order=" - "+RequestOrderDescription(this.m_request)+"\n"; request_data= ("================== "+ CMessage::Text(MSG_LIB_TEXT_REQUEST_DATAS)+" ==================\n"+ action+order+ " ==================\n" ); } else if(this.m_request.action==TRADE_ACTION_CLOSE_BY) { position=" - "+RequestPositionDescription(this.m_request)+"\n"; position_by=" - "+RequestPositionByDescription(this.m_request)+"\n"; magic=" - "+RequestMagicDescription(this.m_request)+"\n"; request_data= ("================== "+ CMessage::Text(MSG_LIB_TEXT_REQUEST_DATAS)+" ==================\n"+ action+position+position_by+magic+ " ==================\n" ); } string datas= ( " - "+this.TypeDescription()+"\n"+ " - "+this.IdDescription()+"\n"+ " - "+this.RetcodeDescription()+" \""+this.ReasonDescription()+"\"\n"+ " - "+this.TimeCreateDescription()+"\n"+ " - "+this.PriceCreateDescription()+"\n"+ " - "+this.TimeActivateDescription()+"\n"+ " - "+this.WaitingMSCDescription()+" ("+TimeToString(this.WaitingMSC()/1000,TIME_MINUTES|TIME_SECONDS)+")"+"\n"+ " - "+this.CurrentAttemptDescription()+"\n"+ " - "+this.TotalAttemptsDescription()+"\n" ); ::Print("================== ",CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_DATAS)," ==================\n",datas,request_data); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Торговый класс | //+------------------------------------------------------------------+ class CTrading {
Для того чтобы торговый класс видел объекты новых классов отложенных запросов, подключим
их к листингу файла торгового класса:
//+------------------------------------------------------------------+ //| 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 "Objects\PendRequest\PendReqOpen.mqh" #include "Objects\PendRequest\PendReqSLTP.mqh" #include "Objects\PendRequest\PendReqClose.mqh" #include "Objects\PendRequest\PendReqPlace.mqh" #include "Objects\PendRequest\PendReqModify.mqh" #include "Objects\PendRequest\PendReqRemove.mqh" #include "Collections\AccountsCollection.mqh" #include "Collections\SymbolsCollection.mqh" #include "Collections\MarketCollection.mqh" #include "Collections\HistoryCollection.mqh" #include "Collections\EventsCollection.mqh" //+------------------------------------------------------------------+
В метод создания нового отложенного запроса теперь дополнительно будем передавать статус создаваемого торгового запроса.
Впишем статус
в объявление метода:
//--- Создаёт отложенный запрос bool CreatePendingRequest(const ENUM_PEND_REQ_STATUS status, const uchar id, const uchar attempts, const ulong wait, const MqlTradeRequest &request, const int retcode, CSymbol *symbol_obj);
И подправим реализацию метода создания нового отложенного запроса:
//+------------------------------------------------------------------+ //| Создаёт отложенный запрос | //+------------------------------------------------------------------+ bool CTrading::CreatePendingRequest(const ENUM_PEND_REQ_STATUS status, const uchar id, const uchar attempts, const ulong wait, const MqlTradeRequest &request, const int retcode, CSymbol *symbol_obj) { //--- Создаём новый объект-отложенный запрос в зависимости от статуса запроса CPendRequest *req_obj=NULL; switch(status) { case PEND_REQ_STATUS_OPEN : req_obj=new CPendReqOpen(id,symbol_obj.BidLast(),symbol_obj.Time(),request,retcode); break; case PEND_REQ_STATUS_CLOSE : req_obj=new CPendReqClose(id,symbol_obj.BidLast(),symbol_obj.Time(),request,retcode); break; case PEND_REQ_STATUS_SLTP : req_obj=new CPendReqSLTP(id,symbol_obj.BidLast(),symbol_obj.Time(),request,retcode); break; case PEND_REQ_STATUS_PLACE : req_obj=new CPendReqPlace(id,symbol_obj.BidLast(),symbol_obj.Time(),request,retcode); break; case PEND_REQ_STATUS_REMOVE : req_obj=new CPendReqRemove(id,symbol_obj.BidLast(),symbol_obj.Time(),request,retcode); break; case PEND_REQ_STATUS_MODIFY : req_obj=new CPendReqModify(id,symbol_obj.BidLast(),symbol_obj.Time(),request,retcode); break; default: req_obj=NULL; break; } if(req_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_TEXT_FAILING_CREATE_PENDING_REQ)); return false; } //--- Если не удалось добавить запрос в список - выводим об этом сообщение, //--- удаляем созданный объект и возвращаем false if(!this.m_list_request.Add(req_obj)) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_TEXT_FAILING_CREATE_PENDING_REQ)); delete req_obj; return false; } //--- Заполняем поля успешно созданного объекта переданными в метод значениями req_obj.SetTimeActivate(symbol_obj.Time()+wait); req_obj.SetWaitingMSC(wait); req_obj.SetCurrentAttempt(0); req_obj.SetTotalAttempts(attempts); //--- Выводим краткое описание созданного отложенного запроса if(this.m_log_level>LOG_LEVEL_NO_MSG) { ::Print(CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_CREATED)," #",req_obj.ID(),":"); req_obj.PrintShort(); } //--- успешно return true; } //+------------------------------------------------------------------+
В метод теперь дополнительно передаётся статус создаваемого
объекта отложенного запроса.
Ранее у нас объект отложенного запроса имел тип класса CPendingReq. Сейчас данный класс мы удалили
совсем, и теперь у нас новый класс объекта отложенного запроса CPendRequest, и его наследники.
Поэтому здесь при
создании пустого объекта мы используем новый объект базового абстрактного запроса CPendRequest.
Затем, в зависимости от переданного в метод статуса, создаём соответствующий
ему новый объект-отложенный запрос.
При удачном создании объекта в
журнал выводится краткое сообщение с параметрами созданного отложенного торгового запроса.
Так как теперь у нас новый объект класса отложенного запроса, то заменим в листинге торгового класса все вхождения прошлого класса CPendingReq на CPendRequest. Сделать это удобно при помощи поиска с заменой Ctrl+H.
В новые объекты отложенных запросов при их создании будем передавать чуть больше информации по проводимой торговой операции. В основном это нужно для корректного вывода в журнал. Передавать будем посредством записи дополнительных данных в структуру торгового запроса при создании нового объекта отложенного запроса.
В методе открытия позиции в блоке создания отложенного запросаукажем статус создаваемого запроса:
//--- Если результат проверки "ожидание" - устанавливаем код последней ошибки в структуру возврата, //--- создаём отложенный запрос и возвращаем false if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- Если в магике торгового запроса нет идентификатора отложенного запроса if(this.GetPendReqID((uint)magic)==0) { //--- Проиграем звук ошибки if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type); //--- устанавливаем код последней ошибки в структуру возврата int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED) code=10027; trade_obj.SetResultRetcode(code); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); } //--- Время ожидания в милисекундах: //--- для метода обработки "Подождать и повторить" - значение ожидания соответствует значению method, ulong wait=method; //--- Ищем наименьший из возможных идентификаторов, и если найти не удалось, //--- или произошла ошибка обновления текущих данных символа - возвращаем false int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Записываем в магик идентификатор объекта-отложенного запроса и заполняем остальные незаполненные поля структуры торгового запроса uint mn=(magic==ULONG_MAX ? (uint)trade_obj.GetMagic() : (uint)magic); this.SetPendReqID((uchar)id,mn); this.m_request.magic=mn; this.m_request.action=TRADE_ACTION_DEAL; this.m_request.symbol=symbol_obj.Name(); this.m_request.type=order_type; //--- Устанавливаем количество торговых попыток и создаём отложенный запрос uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest(PEND_REQ_STATUS_OPEN,(uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); } return false; }
В методе модификации стоп-приказов открытой позиции в блоке
создания отложенного запроса
допишем передачу
через структуру в объект-запрос типа ордера, объёма
позиции, и укажем статус создаваемого запроса:
//--- Если результат проверки "ожидание" - устанавливаем код последней ошибки в структуру возврата, //--- создаём отложенный запрос и возвращаем false if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- Если объекта-отложенного запроса с тикетом позиции нет в списке if(this.GetIndexPendingRequestByPosition(ticket)==WRONG_VALUE) { //--- Проиграем звук ошибки if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type,(sl<0 ? false : true),(tp<0 ? false : true)); //--- устанавливаем код последней ошибки в структуру возврата int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED) code=10027; trade_obj.SetResultRetcode(code); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); } //--- Время ожидания в милисекундах: //--- для метода обработки "Подождать и повторить" - значение ожидания соответствует значению method, //--- для метода обработки "Создать отложенный запрос" - пока будет нулевое время ожидания ulong wait=method; //--- Ищем наименьший из возможных идентификаторов, и если найти не удалось, //--- или произошла ошибка обновления текущих данных символа - возвращаем false int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Записываем тип проводимой операции, символ и тикет модифицируемой позиции в структуру запроса this.m_request.action=TRADE_ACTION_SLTP; this.m_request.symbol=symbol_obj.Name(); this.m_request.position=ticket; this.m_request.type=order_type; this.m_request.volume=order.Volume(); //--- Устанавливаем количество торговых попыток и создаём отложенный запрос uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest(PEND_REQ_STATUS_SLTP,(uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); } return false; }
В методе закрытия позиции в его блоке создания отложенного запроса
допишем передачу
через структуру в объект-запрос
типа ордера, объёма позиции, и укажем
статус создаваемого запроса:
//--- Если результат проверки "ожидание" - устанавливаем код последней ошибки в структуру возврата, //--- создаём отложенный запрос и возвращаем false if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- Если объекта-отложенного запроса с тикетом позиции нет в списке if(this.GetIndexPendingRequestByPosition(ticket)==WRONG_VALUE) { //--- Проиграем звук ошибки if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type); //--- устанавливаем код последней ошибки в структуру возврата int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED) code=10027; trade_obj.SetResultRetcode(code); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); } //--- Время ожидания в милисекундах: //--- для метода обработки "Подождать и повторить" - значение ожидания соответствует значению method, ulong wait=method; //--- Ищем наименьший из возможных идентификаторов, и если найти не удалось, //--- или произошла ошибка обновления текущих данных символа - возвращаем false int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Записываем в структуру запроса тип торговой операции, символ, тикет и объём закрываемой позиции this.m_request.action=TRADE_ACTION_DEAL; this.m_request.symbol=symbol_obj.Name(); this.m_request.position=ticket; this.m_request.volume=(volume==WRONG_VALUE || volume>order.Volume() ? order.Volume() : volume); this.m_request.type=order_type; //--- Устанавливаем количество торговых попыток и создаём отложенный запрос uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest(PEND_REQ_STATUS_CLOSE,(uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); } return false;
Объём позиции у нас может быть в методе указан отрицательным (-1),
что говорит о полном закрытии позиции, либо объём может быть указан значением, что говорит о частичном закрытии позиции. Всё это
обрабатывается в базовом торговом объекте символа при отправке торгового запроса на сервер.
Здесь же мы сразу проверяем значение
объёма, переданного в метод, и устанавливаем требуемый объём в структуру торгового запроса.
В методе закрытия позиции встречной в его блоке создания
отложенного запроса
допишем передачу
через структуру в объект-запрос
типа ордера, объёма позиции, и укажем
статус создаваемого запроса:
//--- Если результат проверки "ожидание" - устанавливаем код последней ошибки в структуру возврата, //--- создаём отложенный запрос и возвращаем false if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- Если объекта-отложенного запроса с тикетом позиции нет в списке if(this.GetIndexPendingRequestByPosition(ticket)==WRONG_VALUE) { //--- Проиграем звук ошибки if(this.IsUseSounds()) trade_obj_pos.PlaySoundError(action,order_type); //--- устанавливаем код последней ошибки в структуру возврата int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED) code=10027; trade_obj_pos.SetResultRetcode(code); trade_obj_pos.SetResultComment(CMessage::Text(trade_obj_pos.GetResultRetcode())); } //--- Время ожидания в милисекундах: //--- для метода обработки "Подождать и повторить" - значение ожидания соответствует значению method, ulong wait=method; //--- Ищем наименьший из возможных идентификаторов, и если найти не удалось, //--- или произошла ошибка обновления текущих данных символа - возвращаем false int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Записываем в структуру запроса тип торговой операции, символ и тикеты двух позиций this.m_request.action=TRADE_ACTION_CLOSE_BY; this.m_request.symbol=symbol_obj.Name(); this.m_request.position=ticket; this.m_request.position_by=ticket_by; this.m_request.type=order_type; this.m_request.volume=order.Volume(); //--- Устанавливаем количество торговых попыток и создаём отложенный запрос uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest(PEND_REQ_STATUS_CLOSE,(uchar)id,attempts,wait,this.m_request,trade_obj_pos.GetResultRetcode(),symbol_obj); } return false; }
В методе установки отложенного ордера в его блоке создания отложенного запроса укажем статус создаваемого запроса:
//--- Если результат проверки "ожидание" - устанавливаем код последней ошибки в структуру возврата, //--- создаём отложенный запрос и возвращаем false if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- Если в магике торгового запроса нет идентификатора отложенного запроса if(this.GetPendReqID((uint)magic)==0) { //--- Проиграем звук ошибки if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type); //--- устанавливаем код последней ошибки в структуру возврата int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED) code=10027; trade_obj.SetResultRetcode(code); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); } //--- Время ожидания в милисекундах: //--- для метода обработки "Подождать и повторить" - значение ожидания соответствует значению method, //--- для метода обработки "Создать отложенный запрос" - пока будет нулевое время ожидания ulong wait=method; //--- Ищем наименьший из возможных идентификаторов, и если найти не удалось, //--- или произошла ошибка обновления текущих данных символа - возвращаем false int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Записываем в магик идентификатор запроса, в структуру запроса наименование символа, //--- устанавливаем тип торговой операции и тип ордера uint mn=(magic==ULONG_MAX ? (uint)trade_obj.GetMagic() : (uint)magic); this.SetPendReqID((uchar)id,mn); this.m_request.magic=mn; this.m_request.symbol=symbol_obj.Name(); this.m_request.action=TRADE_ACTION_PENDING; this.m_request.type=order_type; //--- Устанавливаем количество торговых попыток и создаём отложенный запрос uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest(PEND_REQ_STATUS_PLACE,(uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); } return false; }
В методе модификации параметров отложенного ордера в его блоке
создания отложенного запроса
допишем
передачу
через структуру в объект-запрос
типа ордера и укажем статус создаваемого запроса:
//--- Если результат проверки "ожидание" - устанавливаем код последней ошибки в структуру возврата, //--- создаём отложенный запрос и возвращаем false if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- Если объекта-отложенного запроса с тикетом ордера нет в списке if(this.GetIndexPendingRequestByOrder(ticket)==WRONG_VALUE) { //--- Проиграем звук ошибки if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type,(sl<0 ? false : true),(tp<0 ? false : true),(price>0 || limit>0 ? true : false)); //--- устанавливаем код последней ошибки в структуру возврата int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED) code=10027; trade_obj.SetResultRetcode(code); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); } //--- Время ожидания в милисекундах: //--- для метода обработки "Подождать и повторить" - значение ожидания соответствует значению method, //--- для метода обработки "Создать отложенный запрос" - пока будет нулевое время ожидания ulong wait=method; //--- Ищем наименьший из возможных идентификаторов, и если найти не удалось, //--- или произошла ошибка обновления текущих данных символа - возвращаем false int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Устанавливаем тип торговой операции, символ и тикет модифицируемого ордера в структуру запроса this.m_request.action=TRADE_ACTION_MODIFY; this.m_request.symbol=symbol_obj.Name(); this.m_request.order=ticket; this.m_request.type=order_type; //--- Устанавливаем количество торговых попыток и создаём отложенный запрос uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest(PEND_REQ_STATUS_MODIFY,(uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); } return false; }
В методе удаления отложенного ордера в его блоке создания
отложенного запроса
допишем передачу
через структуру в объект-запрос
типа и объёма ордера, его цену
установки, и укажем статус создаваемого запроса:
//--- Если результат проверки "ожидание" - устанавливаем код последней ошибки в структуру возврата, //--- создаём отложенный запрос и возвращаем false if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- Если объекта-отложенного запроса с тикетом ордера нет в списке if(this.GetIndexPendingRequestByOrder(ticket)==WRONG_VALUE) { //--- Проиграем звук ошибки if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type); //--- устанавливаем код последней ошибки в структуру возврата int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED) code=10027; trade_obj.SetResultRetcode(code); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); } //--- Время ожидания в милисекундах: //--- для метода обработки "Подождать и повторить" - значение ожидания соответствует значению method, //--- для метода обработки "Создать отложенный запрос" - пока будет нулевое время ожидания ulong wait=method; //--- Ищем наименьший из возможных идентификаторов, и если найти не удалось, //--- или произошла ошибка обновления текущих данных символа - возвращаем false int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Устанавливаем тип торговой операции, символ и тикет удаляемого ордера в структуру запроса this.m_request.action=TRADE_ACTION_REMOVE; this.m_request.symbol=symbol_obj.Name(); this.m_request.order=ticket; this.m_request.type=order_type; this.m_request.volume=order.Volume(); this.m_request.price=order.PriceOpen(); //--- Устанавливаем количество торговых попыток и создаём отложенный запрос uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest(PEND_REQ_STATUS_REMOVE,(uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); } return false; }
Таких блоков в каждом торговом методе у нас по два. Поэтому — в каждом из них нужно внести такие правки.
В методах поиска свободного идентификатора и возвращения индексов объектов-запросов укажем
типы сортировки:
//+------------------------------------------------------------------+ //| Ищет первый свободный идентификатор отложенного запроса | //+------------------------------------------------------------------+ int CTrading::GetFreeID(void) { int id=WRONG_VALUE; CPendRequest *element=new CPendRequest(); if(element==NULL) return 0; for(int i=1;i<256;i++) { element.SetID((uchar)i); this.m_list_request.Sort(SORT_BY_PEND_REQ_ID); if(this.m_list_request.Search(element)==WRONG_VALUE) { id=i; break; } } delete element; return id; } //+------------------------------------------------------------------+ //| Возвращает индекс объекта-запроса в списке по идентификатору | //+------------------------------------------------------------------+ int CTrading::GetIndexPendingRequestByID(const uchar id) { CPendRequest *req=new CPendRequest(); if(req==NULL) return WRONG_VALUE; req.SetID(id); this.m_list_request.Sort(SORT_BY_PEND_REQ_ID); int index=this.m_list_request.Search(req); delete req; return index; } //+------------------------------------------------------------------+ //| Возвращает индекс объекта-запроса в списке по тикету ордера | //+------------------------------------------------------------------+ int CTrading::GetIndexPendingRequestByOrder(const ulong ticket) { CPendRequest *req=new CPendRequest(); if(req==NULL) return WRONG_VALUE; req.SetOrder(ticket); this.m_list_request.Sort(SORT_BY_PEND_REQ_MQL_REQ_ORDER); int index=this.m_list_request.Search(req); delete req; return index; } //+------------------------------------------------------------------+ //| Возвращает индекс объекта-запроса в списке по тикету позиции | //+------------------------------------------------------------------+ int CTrading::GetIndexPendingRequestByPosition(const ulong ticket) { CPendRequest *req=new CPendRequest(); if(req==NULL) return WRONG_VALUE; req.SetPosition(ticket); this.m_list_request.Sort(SORT_BY_PEND_REQ_MQL_REQ_POSITION); int index=this.m_list_request.Search(req); delete req; return index; } //+------------------------------------------------------------------+
Для поиска объекта в списке по указанному свойству при помощи метода Searsh() класса динамического массива указателей на экземпляры класса CObject, нужно предварительно при помощи метода Sort() базового класса динамического массива переменных CArray указать тип сортировки списка, в котором производится поиск — так как поиск производится только в сортированных массивах. Что мы тут и делаем.
Теперь в таймере класса подправим вывод сообщений о номере торговой попытки в журнал.
Такой код
//--- Устанавливаем номер попытки в объекте-запросе req_obj.SetCurrentAttempt(uchar(req_obj.CurrentAttempt()+1)); //--- Выводим в журнал номер торговой попытки if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_REQUEST)+(string)req_obj.GetProperty(PEND_REQ_PROP_ID)+" "+CMessage::Text(MSG_LIB_TEXT_RE_TRY_N)+(string)req_obj.CurrentAttempt()); //--- В зависимости от типа выполняемого действия в торговом запросе switch(request.action) {
заменим на такой:
//--- Устанавливаем номер попытки в объекте-запросе req_obj.SetCurrentAttempt(uchar(req_obj.CurrentAttempt()+1)); //--- Выводим в журнал номер торговой попытки if(this.m_log_level>LOG_LEVEL_NO_MSG) { ::Print(CMessage::Text(MSG_LIB_TEXT_RE_TRY_N)+(string)req_obj.CurrentAttempt()+":"); req_obj.PrintShort(); } //--- В зависимости от типа выполняемого действия в торговом запросе switch(request.action) {
Это даст нам более информативное сообщение в журнал о том, для какого объекта отложенного запроса осуществляется очередная торговая
попытка.
Это на сегодня все необходимые изменения дляработы библиотеки с объектами-отложенными торговыми запросами.
Тестирование
Для тестирования новых объектов-отложенных запросов возьмём советник из прошлой статьи
и сохраним его в новой папке
\MQL5\Experts\TestDoEasy\ Part29\ под новым именем TestDoEasyPart29.mq5.
Все изменения, которые нужно внести — это в блоках закрытия половины позиции Buy и половины позиции Sell убрать лишнюю проверку — у нас давно уже всё делается в торговых методах торгового класса.
В блоке частичного закрытия позиции Buy вместо этого кода:
//--- Если нажата кнопка BUTT_CLOSE_BUY2: Закрыть половину Buy с максимальной прибылью else if(button==EnumToString(BUTT_CLOSE_BUY2)) { //--- Получаем список всех открытых позиций CArrayObj* list=engine.GetListMarketPosition(); //--- Выбираем из списка только позиции Buy list=CSelect::ByOrderProperty(list,ORDER_PROP_TYPE,POSITION_TYPE_BUY,EQUAL); //--- Сортируем список по прибыли с учётом комиссии и свопа list.Sort(SORT_BY_ORDER_PROFIT_FULL); //--- Получаем индекс позиции Buy с наибольшей прибылью int index=CSelect::FindOrderMax(list,ORDER_PROP_PROFIT_FULL); if(index>WRONG_VALUE) { COrder* position=list.At(index); if(position!=NULL) { //--- Если счёт хеджевый, закрываем половину позиции Buy по тикету if(engine.IsHedge()) engine.ClosePositionPartially((ulong)position.Ticket(),position.Volume()/2.0); //--- Если счёт неттинговый, открываем позицию Sell с половиной объёма позиции Buy else engine.OpenSell(NormalizeLot(position.Symbol(),position.Volume()/2.0),position.Symbol(),position.Magic(),position.StopLoss(),position.TakeProfit(),"Частичное закрытие Buy #"+(string)position.Ticket()); } } }
напишем этот:
//--- Если нажата кнопка BUTT_CLOSE_BUY2: Закрыть половину Buy с максимальной прибылью else if(button==EnumToString(BUTT_CLOSE_BUY2)) { //--- Получаем список всех открытых позиций CArrayObj* list=engine.GetListMarketPosition(); //--- Выбираем из списка только позиции Buy list=CSelect::ByOrderProperty(list,ORDER_PROP_TYPE,POSITION_TYPE_BUY,EQUAL); //--- Сортируем список по прибыли с учётом комиссии и свопа list.Sort(SORT_BY_ORDER_PROFIT_FULL); //--- Получаем индекс позиции Buy с наибольшей прибылью int index=CSelect::FindOrderMax(list,ORDER_PROP_PROFIT_FULL); if(index>WRONG_VALUE) { COrder* position=list.At(index); //--- Закрываем частично позицию Buy if(position!=NULL) engine.ClosePositionPartially((ulong)position.Ticket(),position.Volume()/2.0); } }
И точно так же перепишем частичное закрытие позиции Sell:
//--- Если нажата кнопка BUTT_CLOSE_SELL2: Закрыть половину Sell с максимальной прибылью else if(button==EnumToString(BUTT_CLOSE_SELL2)) { //--- Получаем список всех открытых позиций CArrayObj* list=engine.GetListMarketPosition(); //--- Выбираем из списка только позиции Sell list=CSelect::ByOrderProperty(list,ORDER_PROP_TYPE,POSITION_TYPE_SELL,EQUAL); //--- Сортируем список по прибыли с учётом комиссии и свопа list.Sort(SORT_BY_ORDER_PROFIT_FULL); //--- Получаем индекс позиции Sell с наибольшей прибылью int index=CSelect::FindOrderMax(list,ORDER_PROP_PROFIT_FULL); if(index>WRONG_VALUE) { COrder* position=list.At(index); //--- Закрываем частично позицию Sell if(position!=NULL) engine.ClosePositionPartially((ulong)position.Ticket(),position.Volume()/2.0); } }
Скомпилируем и запустим советник.
На данный момент у меня выставлено четыре отложенных ордера. Отключаю кнопку "Авто-торговля" и нажимаю кнопку тестового советника "Delete pending" для удаления всех отложенных ордеров. В журнал выводятся сообщения:
2019.12.19 04:25:04.385 CTrading::DeleteOrder: Invalid request: 2019.12.19 04:25:04.385 There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled) 2019.12.19 04:25:04.385 Correction of trade request parameters ... 2019.12.19 04:25:04.385 Pending request created #1: 2019.12.19 04:25:04.385 Pending request to remove a pending order: 2019.12.19 04:25:04.385 - EURUSD 0.10 Pending order Buy Limit #497568391, Price 1.11076 2019.12.19 04:25:04.385 - Pending request ID: #1, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:04.385 2019.12.19 04:25:04.386 CTrading::DeleteOrder: Invalid request: 2019.12.19 04:25:04.386 There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled) 2019.12.19 04:25:04.386 Correction of trade request parameters ... 2019.12.19 04:25:04.386 Pending request created #2: 2019.12.19 04:25:04.386 Pending request to remove a pending order: 2019.12.19 04:25:04.386 - EURUSD 0.10 Pending order Buy Limit #497563913, Price 1.11099 2019.12.19 04:25:04.386 - Pending request ID: #2, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:04.386 2019.12.19 04:25:04.386 CTrading::DeleteOrder: Invalid request: 2019.12.19 04:25:04.386 There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled) 2019.12.19 04:25:04.386 Correction of trade request parameters ... 2019.12.19 04:25:04.386 Pending request created #3: 2019.12.19 04:25:04.386 Pending request to remove a pending order: 2019.12.19 04:25:04.386 - EURUSD 0.10 Pending order Sell Limit #496816788, Price 1.11829 2019.12.19 04:25:04.386 - Pending request ID: #3, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:04.386 2019.12.19 04:25:04.386 CTrading::DeleteOrder: Invalid request: 2019.12.19 04:25:04.386 There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled) 2019.12.19 04:25:04.386 Correction of trade request parameters ... 2019.12.19 04:25:04.387 Pending request created #4: 2019.12.19 04:25:04.387 Pending request to remove a pending order: 2019.12.19 04:25:04.387 - EURUSD 0.10 Pending order Sell Limit #496816707, Price 1.11784 2019.12.19 04:25:04.387 - Pending request ID: #4, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:04.387
Здесь видно что советник сделал четыре попытки удаления четырёх отложенных ордеров и, встретив ошибку запрета торговли со стороны терминала, создал четыре отложенных запроса, о которых вывел краткие сообщения с их параметрами.
Далее ничего не делаем — ждём.
Спустя некоторое время (20 секунд ожидания, но зависит от прихода тиков) в журнал выводятся
сообщения от объектов-отложенных запросов о повторных попытках удалить четыре ордера:
2019.12.19 04:25:38.780 Retry trading attempt #1: 2019.12.19 04:25:38.780 Pending request to remove a pending order: 2019.12.19 04:25:38.780 - EURUSD 0.10 Pending order Sell Limit #496816707, Price 1.11784 2019.12.19 04:25:38.780 - Pending request ID: #4, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:38.780 2019.12.19 04:25:38.780 Retry trading attempt #1: 2019.12.19 04:25:38.780 Pending request to remove a pending order: 2019.12.19 04:25:38.780 - EURUSD 0.10 Pending order Buy Limit #497563913, Price 1.11099 2019.12.19 04:25:38.780 - Pending request ID: #2, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:38.780 2019.12.19 04:25:38.781 Retry trading attempt #1: 2019.12.19 04:25:38.781 Pending request to remove a pending order: 2019.12.19 04:25:38.781 - EURUSD 0.10 Pending order Sell Limit #496816788, Price 1.11829 2019.12.19 04:25:38.781 - Pending request ID: #3, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:38.781 2019.12.19 04:25:39.103 Retry trading attempt #1: 2019.12.19 04:25:39.103 Pending request to remove a pending order: 2019.12.19 04:25:39.103 - EURUSD 0.10 Pending order Buy Limit #497568391, Price 1.11076 2019.12.19 04:25:39.103 - Pending request ID: #1, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:39.103 2019.12.19 04:25:42.006 Retry trading attempt #2: 2019.12.19 04:25:42.006 Pending request to remove a pending order: 2019.12.19 04:25:42.006 - EURUSD 0.10 Pending order Buy Limit #497568391, Price 1.11076 2019.12.19 04:25:42.006 - Pending request ID: #1, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:42.006 2019.12.19 04:25:42.007 Retry trading attempt #2: 2019.12.19 04:25:42.007 Pending request to remove a pending order: 2019.12.19 04:25:42.007 - EURUSD 0.10 Pending order Buy Limit #497563913, Price 1.11099 2019.12.19 04:25:42.007 - Pending request ID: #2, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:42.007 2019.12.19 04:25:42.007 Retry trading attempt #2: 2019.12.19 04:25:42.007 Pending request to remove a pending order: 2019.12.19 04:25:42.007 - EURUSD 0.10 Pending order Sell Limit #496816788, Price 1.11829 2019.12.19 04:25:42.007 - Pending request ID: #3, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:42.007 2019.12.19 04:25:42.008 Retry trading attempt #2: 2019.12.19 04:25:42.008 Pending request to remove a pending order: 2019.12.19 04:25:42.008 - EURUSD 0.10 Pending order Sell Limit #496816707, Price 1.11784 2019.12.19 04:25:42.008 - Pending request ID: #4, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:42.008 2019.12.19 04:26:03.026 Retry trading attempt #3: 2019.12.19 04:26:03.026 Pending request to remove a pending order: 2019.12.19 04:26:03.026 - EURUSD 0.10 Pending order Buy Limit #497568391, Price 1.11076 2019.12.19 04:26:03.026 - Pending request ID: #1, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:26:03.026 2019.12.19 04:26:03.027 Retry trading attempt #3: 2019.12.19 04:26:03.027 Pending request to remove a pending order: 2019.12.19 04:26:03.027 - EURUSD 0.10 Pending order Buy Limit #497563913, Price 1.11099 2019.12.19 04:26:03.027 - Pending request ID: #2, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:26:03.027 2019.12.19 04:26:03.027 Retry trading attempt #3: 2019.12.19 04:26:03.028 Pending request to remove a pending order: 2019.12.19 04:26:03.028 - EURUSD 0.10 Pending order Sell Limit #496816788, Price 1.11829 2019.12.19 04:26:03.028 - Pending request ID: #3, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:26:03.028 2019.12.19 04:26:03.028 Retry trading attempt #3: 2019.12.19 04:26:03.028 Pending request to remove a pending order: 2019.12.19 04:26:03.028 - EURUSD 0.10 Pending order Sell Limit #496816707, Price 1.11784 2019.12.19 04:26:03.028 - Pending request ID: #4, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:26:03.028 2019.12.19 04:26:22.357 Retry trading attempt #4: 2019.12.19 04:26:22.357 Pending request to remove a pending order: 2019.12.19 04:26:22.357 - EURUSD 0.10 Pending order Buy Limit #497568391, Price 1.11076 2019.12.19 04:26:22.357 - Pending request ID: #1, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:26:22.357 2019.12.19 04:26:22.358 Retry trading attempt #4: 2019.12.19 04:26:22.358 Pending request to remove a pending order: 2019.12.19 04:26:22.358 - EURUSD 0.10 Pending order Buy Limit #497563913, Price 1.11099 2019.12.19 04:26:22.358 - Pending request ID: #2, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:26:22.358 2019.12.19 04:26:22.358 Retry trading attempt #4: 2019.12.19 04:26:22.358 Pending request to remove a pending order: 2019.12.19 04:26:22.358 - EURUSD 0.10 Pending order Sell Limit #496816788, Price 1.11829 2019.12.19 04:26:22.358 - Pending request ID: #3, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:26:22.358 2019.12.19 04:26:22.359 Retry trading attempt #4: 2019.12.19 04:26:22.359 Pending request to remove a pending order: 2019.12.19 04:26:22.359 - EURUSD 0.10 Pending order Sell Limit #496816707, Price 1.11784 2019.12.19 04:26:22.359 - Pending request ID: #4, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920
И опять ждём наступления следующей торговой попытки. При наступлении времени объекты-отложенные запросы удаляются в связи с истечением отведённого времени на все торговые попытки:
2019.12.19 04:26:44.004 Pending request ID: #1: Deleted due to expiration 2019.12.19 04:26:44.004 Pending request ID: #2: Deleted due to expiration 2019.12.19 04:26:44.004 Pending request ID: #3: Deleted due to expiration 2019.12.19 04:26:44.004 Pending request ID: #4: Deleted due to expiration
Если бы в отведённое время на все торговые попытки была нажата кнопка "Авто-торговля", то объекты отложенных запросов отправили бы приказ на сервер об удалении отложенных ордеров, и они были бы удалены.
Точно таким же образом я проверял работу объектов отложенных торговых запросов на открытие/закрытие позиций, установку ордеров, модификацию стоп-приказов позиций и параметров отложенных ордеров. На закрытие позиции встречным. И вот что выяснилось: отложенные торговые запросы правильно отрабатывают в большинстве случаев. Но есть одно "Но": если сначала, например, модифицировать отложенный ордер, а потом опять попробовать произвести любую его модификацию, то это уже сделать не получится. Равно как и производить с одним и тем же тикетом две и более торговые операции. Отложенные запросы просто-напросто будут удаляться сразу же после их создания с причиной "Выполнено". Дело в том, что в прошлых статьях проверки отработки отложенных запросов производились только по тикету в таймере торгового класса. И метод проверки находил в истории счёта, что такая-то операция с таким-то тикетом только что уже была проведена. Соответственно — считалось что всё отработано, и стоит удалить этот объект-запрос. Эту ситуацию мы исправим уже далее.
Пожалуйста, имейте в виду:
Настоятельно обращаю ваше внимание на то, что работа с классом объектов-отложенных запросов до конца ещё не доведена, поэтому результаты, описанные в данной статье и тестовый советник, прилагаемый к статье, ни в коем случае не стоит пытаться использовать в своих наработках для реальной торговли!Данная статья, её материалы и результат в данном виде ещё не являются законченным продуктом для использования на реальных счетах — только для использования в демо-режиме или тестере.
Что дальше
В следующей статье создадим класс управления отложенными торговыми запросами и избавимся от невозможности несколько раз подряд
произвести одну и ту же торговую операцию с одним и тем же ордером или позицией.
Ниже прикреплены все файлы текущей версии библиотеки и файлы тестового советника. Их можно скачать и протестировать всё
самостоятельно.
При возникновении вопросов, замечаний и пожеланий вы можете озвучить их в комментариях к статье.
Статьи этой серии:
Часть 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. Торговые классы — Базовый кроссплатформенный торговый объект
Часть 22. Торговые классы — Основной торговый класс, контроль ограничений
Часть 23. Торговые классы — Основной торговый класс, контроль допустимых параметров
Часть 24. Торговые классы — Основной торговый класс, автоматическая коррекция ошибочных
параметров
Часть 25. Торговые классы — Основной торговый класс, обработка
ошибок, возвращаемых торговым сервером
Часть 26. Работа с отложенными торговыми
запросами - первая реализация (открытие позиций)
Часть 27. Работа с отложенными
торговыми запросами - выставление отложенных ордеров
Часть 28. Работа с
отложенными торговыми запросами - закрытие, удаление, модификации
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Вот ты накрутил Артем, чем дальше в лес тем больше кода...
Спасибо!
Вот ты накрутил Артем, чем дальше в лес тем больше кода...
Спасибо!
:) Было бы круто, если б чем дальше - тем меньше.., но я пока так не умею ;)