English 中文 Español Deutsch 日本語 Português
preview
Торговые транзакции. Структуры запросов и ответов, описание и вывод в журнал

Торговые транзакции. Структуры запросов и ответов, описание и вывод в журнал

MetaTrader 5Примеры | 3 августа 2023, 10:09
1 689 82
Artyom Trishkin
Artyom Trishkin

Содержание


Введение

В MQL5 для выставления отложенных ордеров, открытия позиций, изменения ордеров и позиций существует функция OrderSend(). Первым входным параметром функции является структура торгового запроса MqlTradeRequest. В поле action структуры указывается тип выполняемого действия, а остальные поля заполняются в зависимости от выбранного действия в поле action. Таким образом мы, передавая необходимые для торгового запроса параметры в функцию, осуществляем отсылку различных запросов на сервер.

Структура торгового запроса (MqlTradeRequest)

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

struct MqlTradeRequest
  {
   ENUM_TRADE_REQUEST_ACTIONS    action;           // Тип выполняемого действия
   ulong                         magic;            // Штамп эксперта (идентификатор magic number)
   ulong                         order;            // Тикет ордера
   string                        symbol;           // Имя торгового инструмента
   double                        volume;           // Запрашиваемый объем сделки в лотах
   double                        price;            // Цена 
   double                        stoplimit;        // Уровень StopLimit ордера
   double                        sl;               // Уровень Stop Loss ордера
   double                        tp;               // Уровень Take Profit ордера
   ulong                         deviation;        // Максимально приемлемое отклонение от запрашиваемой цены
   ENUM_ORDER_TYPE               type;             // Тип ордера
   ENUM_ORDER_TYPE_FILLING       type_filling;     // Тип ордера по исполнению
   ENUM_ORDER_TYPE_TIME          type_time;        // Тип ордера по времени действия
   datetime                      expiration;       // Срок истечения ордера (для ордеров типа ORDER_TIME_SPECIFIED)
   string                        comment;          // Комментарий к ордеру
   ulong                         position;         // Тикет позиции
   ulong                         position_by;      // Тикет встречной позиции
  };

В первом же поле action как раз и указывается тип выполняемого действия.

Тип торговой операции. Значение может быть одним из значений перечисления ENUM_TRADE_REQUEST_ACTIONS:

Идентификатор
Описание
TRADE_ACTION_DEAL
Установить торговый ордер на немедленное совершение сделки с указанными параметрами (поставить рыночный ордер)
TRADE_ACTION_PENDING
Установить торговый ордер на совершение сделки при указанных условиях (отложенный ордер)
TRADE_ACTION_SLTP
Изменить значения Stop Loss и Take Profit у открытой позиции
TRADE_ACTION_MODIFY
Изменить параметры ранее установленного торгового ордера
TRADE_ACTION_REMOVE
Удалить ранее выставленный отложенный торговый ордер
TRADE_ACTION_CLOSE_BY
Закрыть позицию встречной

Для каждого типа действий поля структуры должны заполняться индивидуально.

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

struct MqlTradeCheckResult
  {
   uint         retcode;             // Код ответа
   double       balance;             // Баланс после совершения сделки
   double       equity;              // Эквити после совершения сделки
   double       profit;              // Плавающая прибыль
   double       margin;              // Маржевые требования
   double       margin_free;         // Свободная маржа
   double       margin_level;        // Уровень маржи
   string       comment;             // Комментарий к коду ответа (описание ошибки)
  };

В случае нехватки средств в результате проверки приказа, или ошибочно заполненных параметров функция возвращает false. В случае успешной базовой проверки структур (проверка указателей) возвращается true это не является свидетельством того, что запрашиваемая торговая операция непременно выполнится успешно. Для получения подробного описания результата выполнения функции следует анализировать поля структуры result, представленные выше.

После успешной проверки заполнения полей структуры торгового приказа, его можно отсылать на сервер. Успешность выполнения функции OrderSend() не говорит о том, что приказ исполнен. Мы всего лишь понимаем, что приказ обработан и принят сервером. Результатом отсылки торгового приказа не сервер будут заполненные поля структуры MqlTradeResult, которая содержит ответ торгового сервера на запрос, отправленный функцией OrderSend().

Результат торговой операции возвращается в переменную типа MqlTradeResult, которая передается вторым параметром в функцию OrderSend() для проведения торговых операций.

Терминал записывает идентификатор запроса в поле request_id при его отправке на торговый сервер функциями OrdersSend() и OrderSendAsync(). От торгового сервера терминал получает сообщения о совершенных торговых транзакциях и передает их на обработку в функцию OnTradeTransaction(), которая содержит в качестве параметров:

  • описание самой торговой транзакции в структуре MqlTradeTransaction;
  • описание торгового запроса, отправленного из функции OrderSend() или OrdersSendAsync(). Идентификатор запроса отправляется терминалом на торговый сервер, а сам запрос и его request_id сохраняются в памяти терминала;
  • результат исполнения торгового запроса в виде структуры MqlTradeResult, в котором поле request_id содержит идентификатор этого самого запроса.

Функция OnTradeTransaction() получает три входных параметра, но последние два параметра имеет смысл анализировать только для торговых транзакций, имеющих тип TRADE_TRANSACTION_REQUEST. Во всех остальных случаях данные о торговом запросе и результате его выполнения не заполняются. Пример анализа параметров приведен в разделе Структура торговой транзакции.

Установка терминалом идентификатора request_id для торгового запроса при его отправке на сервер в первую очередь предназначена для работы с асинхронной функцией OrderSendAsync(). Этот идентификатор позволяет связать выполненное действие (вызов функций OrderSend или OrderSendAsync) с результатом этого действия, передаваемым в OnTradeTransaction().

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

Порядок работы с торговыми приказами вкратце таков:

  1. Заполняем структуру торгового запроса,
  2. Проверяем корректность заполнения структуры и возможность выставления такого ордера,
  3. Отсылаем торговый приказ на сервер,
  4. При необходимости анализируем структуру результата отправки приказа на сервер,
  5. Получаем события и при необходимости анализируем сообщения в логе от обработчика OnTradeTransaction().
Но прежде, чем начать писать функции для вывода описания полей структур в журнал, напишем вспомогательные функции, возвращающие описания некоторых типов ордеров, представленных в виде констант перечислений, а также другие полезные и нужные нам функции.

Вспомогательные функции

Советник, который будет представлен в конце статьи будет управляться нажатием сочетаний клавиш на клавиатуре. Для определения нажатий клавиш Ctrl и Shift напишем две функции:

//+------------------------------------------------------------------+
//| Возвращает состояние клавиши Ctrl                                |
//+------------------------------------------------------------------+
bool IsCtrlKeyPressed(void) 
  { 
   return(::TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL)<0);
  }
//+------------------------------------------------------------------+
//| Возвращает состояние клавиши Shift                               |
//+------------------------------------------------------------------+
bool IsShiftKeyPressed(void) 
  { 
   return(::TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT)<0);
  }

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


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

//+------------------------------------------------------------------+
//| Возвращает описание кода возврата торгового сервера              |
//+------------------------------------------------------------------+
string RetcodeDescription(const uint retcode,bool ext_descr=false)
  {
   switch(retcode)
     {
      //--- Выполнено
      case 0                                 :  return "OK (0)";
      //--- Реквота
      case TRADE_RETCODE_REQUOTE             :  return "10004 REQUOTE"+(ext_descr ? " (Requote)" : "");
      //--- Запрос отклонен
      case TRADE_RETCODE_REJECT              :  return "10006 REJECT"+(ext_descr ? " (Request rejected)" : "");
      //--- Запрос отменен трейдером
      case TRADE_RETCODE_CANCEL              :  return "10007 CANCEL"+(ext_descr ? " (Request canceled by trader)" : "");
      //--- Ордер размещен
      case TRADE_RETCODE_PLACED              :  return "10008 PLACED"+(ext_descr ? " (Order placed)" : "");
      //--- Заявка выполнена
      case TRADE_RETCODE_DONE                :  return "10009 DONE"+(ext_descr ? " (Request completed)" : "");
      //--- Заявка выполнена частично
      case TRADE_RETCODE_DONE_PARTIAL        :  return "10010 DONE_PARTIAL"+(ext_descr ? " (Only part of the request was completed)" : "");
      //--- Ошибка обработки запроса
      case TRADE_RETCODE_ERROR               :  return "10011 ERROR"+(ext_descr ? " (Request processing error)" : "");
      //--- Запрос отменен по истечению времени
      case TRADE_RETCODE_TIMEOUT             :  return "10012 TIMEOUT"+(ext_descr ? " (Request canceled by timeout)" : "");
      //--- Неправильный запрос
      case TRADE_RETCODE_INVALID             :  return "10013 INVALID"+(ext_descr ? " (Invalid request)" : "");
      //--- Неправильный объем в запросе
      case TRADE_RETCODE_INVALID_VOLUME      :  return "10014 INVALID_VOLUME"+(ext_descr ? " (Invalid volume in the request)" : "");
      //--- Неправильная цена в запросе
      case TRADE_RETCODE_INVALID_PRICE       :  return "10015 INVALID_PRICE"+(ext_descr ? " (Invalid price in the request)" : "");
      //--- Неправильные стопы в запросе
      case TRADE_RETCODE_INVALID_STOPS       :  return "10016 INVALID_STOPS"+(ext_descr ? " (Invalid stops in the request)" : "");
      //--- Торговля запрещена
      case TRADE_RETCODE_TRADE_DISABLED      :  return "10017 TRADE_DISABLED"+(ext_descr ? " (Trade is disabled)" : "");
      //--- Рынок закрыт
      case TRADE_RETCODE_MARKET_CLOSED       :  return "10018 MARKET_CLOSED"+(ext_descr ? " (Market is closed)" : "");
      //--- Нет достаточных денежных средств для выполнения запроса
      case TRADE_RETCODE_NO_MONEY            :  return "10019 NO_MONEY"+(ext_descr ? " (There is not enough money to complete the request)" : "");
      //--- Цены изменились
      case TRADE_RETCODE_PRICE_CHANGED       :  return "10020 PRICE_CHANGED"+(ext_descr ? " (Prices changed)" : "");
      //--- Отсутствуют котировки для обработки запроса
      case TRADE_RETCODE_PRICE_OFF           :  return "10021 PRICE_OFF"+(ext_descr ? " (There are no quotes to process the request)" : "");
      //--- Неверная дата истечения ордера в запросе
      case TRADE_RETCODE_INVALID_EXPIRATION  :  return "10022 INVALID_EXPIRATION"+(ext_descr ? " (Invalid order expiration date in the request)" : "");
      //--- Состояние ордера изменилось
      case TRADE_RETCODE_ORDER_CHANGED       :  return "10023 ORDER_CHANGED"+(ext_descr ? " (Order state changed)" : "");
      //--- Слишком частые запросы
      case TRADE_RETCODE_TOO_MANY_REQUESTS   :  return "10024 TOO_MANY_REQUESTS"+(ext_descr ? " (Too frequent requests)" : "");
      //--- В запросе нет изменений
      case TRADE_RETCODE_NO_CHANGES          :  return "10025 NO_CHANGES"+(ext_descr ? " (No changes in request)" : "");
      //--- Автотрейдинг запрещен сервером
      case TRADE_RETCODE_SERVER_DISABLES_AT  :  return "10026 SERVER_DISABLES_AT"+(ext_descr ? " (Autotrading disabled by server)" : "");
      //--- Автотрейдинг запрещен клиентским терминалом
      case TRADE_RETCODE_CLIENT_DISABLES_AT  :  return "10027 CLIENT_DISABLES_AT"+(ext_descr ? " (Autotrading disabled by client terminal)" : "");
      //--- Запрос заблокирован для обработки
      case TRADE_RETCODE_LOCKED              :  return "10028 LOCKED"+(ext_descr ? " (Request locked for processing)" : "");
      //--- Ордер или позиция заморожены
      case TRADE_RETCODE_FROZEN              :  return "10029 FROZEN"+(ext_descr ? " (Order or position frozen)" : "");
      //--- Указан неподдерживаемый тип исполнения ордера по остатку
      case TRADE_RETCODE_INVALID_FILL        :  return "10030 INVALID_FILL"+(ext_descr ? " (Invalid order filling type)" : "");
      //--- Нет соединения с торговым сервером
      case TRADE_RETCODE_CONNECTION          :  return "10031 CONNECTION"+(ext_descr ? " (No connection with the trade server)" : "");
      //--- Операция разрешена только для реальных счетов
      case TRADE_RETCODE_ONLY_REAL           :  return "10032 ONLY_REAL"+(ext_descr ? " (Operation is allowed only for live accounts)" : "");
      //--- Достигнут лимит на количество отложенных ордеров
      case TRADE_RETCODE_LIMIT_ORDERS        :  return "10033 LIMIT_ORDERS"+(ext_descr ? " (The number of pending orders has reached the limit)" : "");
      //--- Достигнут лимит на объем ордеров и позиций для данного символа
      case TRADE_RETCODE_LIMIT_VOLUME        :  return "10034 LIMIT_VOLUME"+(ext_descr ? " (The volume of orders and positions for the symbol has reached the limit)" : "");
      //--- Неверный или запрещённый тип ордера
      case TRADE_RETCODE_INVALID_ORDER       :  return "10035 INVALID_ORDER"+(ext_descr ? " (Incorrect or prohibited order type)" : "");
      //--- Позиция с указанным POSITION_IDENTIFIER уже закрыта
      case TRADE_RETCODE_POSITION_CLOSED     :  return "10036 POSITION_CLOSED"+(ext_descr ? " (Position with the specified POSITION_IDENTIFIER has already been closed)" : "");
      //--- Закрываемый объем превышает текущий объем позиции
      case TRADE_RETCODE_INVALID_CLOSE_VOLUME:  return "10038 INVALID_CLOSE_VOLUME"+(ext_descr ? " (A close volume exceeds the current position volume)" : "");
      //--- Для указанной позиции уже есть ордер на закрытие
      case TRADE_RETCODE_CLOSE_ORDER_EXIST   :  return "10039 CLOSE_ORDER_EXIST"+(ext_descr ? " (A close order already exists for a specified position)" : "");
      //--- Достигнут лимит на количество позиций
      case TRADE_RETCODE_LIMIT_POSITIONS     :  return "10040 LIMIT_POSITIONS"+(ext_descr ? " (The number of positions has reached the limit)" : "");
      //--- Запрос на активацию отложенного ордера отклонен, а сам ордер отменен
      case TRADE_RETCODE_REJECT_CANCEL       :  return "10041 REJECT_CANCEL"+(ext_descr ? " (The pending order activation request is rejected, the order is canceled)" : "");
      //--- Запрос отклонен, так как на символе разрешены только длинные позиции
      case TRADE_RETCODE_LONG_ONLY           :  return "10042 LONG_ONLY"+(ext_descr ? " (Only long positions are allowed)" : "");
      //--- Запрос отклонен, так как на символе разрешены только короткие позиции
      case TRADE_RETCODE_SHORT_ONLY          :  return "10043 SHORT_ONLY"+(ext_descr ? " (Only short positions are allowed)" : "");
      //--- Запрос отклонен, так как на символе разрешено только закрывать существующие позиции
      case TRADE_RETCODE_CLOSE_ONLY          :  return "10044 CLOSE_ONLY"+(ext_descr ? " (Only position closing is allowed)" : "");
      //--- Запрос отклонен, так как для торгового счета разрешено закрывать существующие позиции только по правилу FIFO
      case TRADE_RETCODE_FIFO_CLOSE          :  return "10045 FIFO_CLOSE"+(ext_descr ? " (Position closing is allowed only by FIFO rule)" : "");
      //--- Запрос отклонен, так как для торгового счета запрещено открывать встречные позиции по одному символу
      case TRADE_RETCODE_HEDGE_PROHIBITED    :  return "10046 HEDGE_PROHIBITED"+(ext_descr ? " (Opposite positions on a single symbol are disabled)" : "");
      //--- Неизвестный код возврата
      default                                :  return "Undefined ("+(string)retcode+")";
     }
  }

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

10034 LIMIT_VOLUME

либо с подробным описанием кода ответа сервера:

10034 LIMIT_VOLUME (The volume of orders and positions for the symbol has reached the limit)


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

//+------------------------------------------------------------------+
//| Возвращает описание типа ордера                                  |
//+------------------------------------------------------------------+
string OrderTypeDescription(const ENUM_ORDER_TYPE type,const bool ext_descr=false)
  {
//--- "Вырезаем" из строки, полученной из enum, только тип ордера
   string res=StringSubstr(EnumToString(type),11);
//--- Преобразуем все полученные символы в нижний регистр и
   if(res.Lower())
     {
      //--- заменяем первую букву с маленькой на заглавную
      res.SetChar(0,ushort(res.GetChar(0)-0x20));
      int total=(int)res.Length();  // Длина текста
      int index=0;                  // индекс начала поиска символов "_" в тексте
      //--- В цикле по всем символам ищем в тексте знаки нижнего подчёркивания
      for(int i=0;i<total;i++)
        {
         int pos=StringFind(res,"_",index);
         //--- Если подчёркивание найдено,
         if(pos>0)
           {
            //--- заменяем его на пробел и следующую букву переводим в верхний регистр
            res.SetChar(pos,' ');
            res.SetChar(pos+1,ushort(res.GetChar(pos+1)-0x20));
            //--- Устанавливаем новый индекс начала поиска знаков "_"
            index=pos;
           }
        }
     }
   string descr="";
   switch(type)
     {
      case ORDER_TYPE_BUY              :  descr=" (Market Buy order)";                                                                          break;
      case ORDER_TYPE_SELL             :  descr=" (Market Sell order)";                                                                         break;
      case ORDER_TYPE_BUY_LIMIT        :  descr=" (Buy Limit pending order)";                                                                   break;
      case ORDER_TYPE_SELL_LIMIT       :  descr=" (Sell Limit pending order)";                                                                  break;
      case ORDER_TYPE_BUY_STOP         :  descr=" (Buy Stop pending order)";                                                                    break;
      case ORDER_TYPE_SELL_STOP        :  descr=" (Sell Stop pending order)";                                                                   break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :  descr=" (Upon reaching the order price, a pending Buy Limit order is placed at the StopLimit price)"; break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :  descr=" (Upon reaching the order price, a pending Sell Limit order is placed at the StopLimit price)";break;
      case ORDER_TYPE_CLOSE_BY         :  descr=" (Order to close a position by an opposite one)";                                              break;
      default: break;
     }
   return res+(!ext_descr ? "" : descr);
   /* Пример вывода:
      Sell Limit (Sell Limit pending order)
   */
  }

При отправке торгового запроса функцией OrderSend() для некоторых операций необходимо указать тип ордера. Тип ордера указывается в поле type структуры MqlTradeRequest, и может принимать значения из перечисления ENUM_ORDER_TYPE:

Идентификатор
Описание
ORDER_TYPE_BUY
Рыночный ордер на покупку
ORDER_TYPE_SELL
Рыночный ордер на продажу
ORDER_TYPE_BUY_LIMIT
Отложенный ордер Buy Limit
ORDER_TYPE_SELL_LIMIT
Отложенный ордер Sell Limit
ORDER_TYPE_BUY_STOP
Отложенный ордер Buy Stop
ORDER_TYPE_SELL_STOP
Отложенный ордер Sell Stop
ORDER_TYPE_BUY_STOP_LIMIT
По достижении цены ордера выставляется отложенный ордер Buy Limit по цене StopLimit
ORDER_TYPE_SELL_STOP_LIMIT
По достижении цены ордера выставляется отложенный ордер Sell Limit по цене StopLimit
ORDER_TYPE_CLOSE_BY
Ордер на закрытие позиции встречной позицией


Функция, возвращающая описание типа ордера по исполнению:

//+------------------------------------------------------------------+
//| Возвращает описание типа ордера по исполнению                    |
//+------------------------------------------------------------------+
string OrderTypeFillingDescription(const ENUM_ORDER_TYPE_FILLING type_filling,const bool ext_descr=false)
  {
   string res=StringSubstr(EnumToString(type_filling),14);
//--- Преобразуем все полученные символы в нижний регистр и заменяем первую букву с маленькой на заглавную (для ORDER_FILLING_RETURN)
   if(type_filling==ORDER_FILLING_RETURN && res.Lower())
      res.SetChar(0,ushort(res.GetChar(0)-0x20));
   string descr="";
   switch(type_filling)
     {
      case ORDER_FILLING_FOK     :  descr=" (Fill or Kill. An order can be executed in the specified volume only)";                                               break;
      case ORDER_FILLING_IOC     :  descr=" (Immediate or Cancel. A deal with the volume maximally available in the market within that indicated in the order)";  break;
      case ORDER_FILLING_BOC     :  descr=" (Passive (Book or Cancel). The order can only be placed in the Depth of Market and cannot be immediately executed)";  break;
      case ORDER_FILLING_RETURN  :  descr=" (In case of partial filling, an order with remaining volume is not canceled but processed further)";                  break;
      default: break;
     }
   return res+(!ext_descr ? "" : descr);
   /* Пример вывода:
      Type filling: Return (In case of partial filling, an order with remaining volume is not canceled but processed further)
   */
  }
При отправке торгового запроса функцией OrderSend() нужную политику исполнения по объему можно задать в поле type_filling в структуре MqlTradeRequest, допустимы значения из перечисления ENUM_ORDER_TYPE_FILLING. Для получения значения этого свойства в конкретном действующем/отработавшем ордере используйте функцию OrderGetInteger() или HistoryOrderGetInteger() с модификатором ORDER_TYPE_FILLING.

Перед отправкой ордера с исполнением в текущий момент времени, для правильного выставления значения ORDER_TYPE_FILLING (тип исполнения по объему), для каждого финансового инструмента с помощью функции SymbolInfoInteger() можно получить значение свойства SYMBOL_FILLING_MODE, которое показывает разрешенные для этого символа типы заполнения по объему в виде комбинации флагов. При этом нужно отметить, что тип заливки ORDER_FILLING_RETURN разрешен всегда, кроме режима "Исполнение по рынку" (SYMBOL_TRADE_EXECUTION_MARKET).


Функция, возвращающая описание типа торговой транзакции:

//+------------------------------------------------------------------+
//| Возвращает описание типа торговой транзакции                     |
//+------------------------------------------------------------------+
string TradeTransactionTypeDescription(const ENUM_TRADE_TRANSACTION_TYPE transaction,const bool ext_descr=false)
  {
//--- "Вырезаем" из строки, полученной из enum, только тип транзакции
   string res=StringSubstr(EnumToString(transaction),18);
//--- Преобразуем все полученные символы в нижний регистр и заменяем первую букву с маленькой на заглавную
   if(res.Lower())
      res.SetChar(0,ushort(res.GetChar(0)-0x20));
//--- Заменяем в полученной строке все символы подчёркивания на символ пробела
   StringReplace(res,"_"," ");
   string descr="";
   switch(transaction)
     {
      case TRADE_TRANSACTION_ORDER_ADD       :  descr=" (Adding a new open order)";                                                                   break;
      case TRADE_TRANSACTION_ORDER_UPDATE    :  descr=" (Updating an open order)";                                                                    break;
      case TRADE_TRANSACTION_ORDER_DELETE    :  descr=" (Removing an order from the list of the open ones)";                                          break;
      case TRADE_TRANSACTION_DEAL_ADD        :  descr=" (Adding a deal to the history)";                                                              break;
      case TRADE_TRANSACTION_DEAL_UPDATE     :  descr=" (Updating a deal in the history)";                                                            break;
      case TRADE_TRANSACTION_DEAL_DELETE     :  descr=" (Deleting a deal from the history)";                                                          break;
      case TRADE_TRANSACTION_HISTORY_ADD     :  descr=" (Adding an order to the history as a result of execution or cancellation)";                   break;
      case TRADE_TRANSACTION_HISTORY_UPDATE  :  descr=" (Changing an order located in the orders history)";                                           break;
      case TRADE_TRANSACTION_HISTORY_DELETE  :  descr=" (Deleting an order from the orders history)";                                                 break;
      case TRADE_TRANSACTION_POSITION        :  descr=" (Changing a position not related to a deal execution)";                                       break;
      case TRADE_TRANSACTION_REQUEST         :  descr=" (The trade request has been processed by a server and processing result has been received)";  break;
      default: break;
     }
   return res+(!ext_descr ? "" : descr);
   /* Пример вывода:
      Order add (Adding a new open order)
   */
  }

Функция возвращает описания типов торговых транзакций, выполняющихся на счёте.


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

//+------------------------------------------------------------------+
//| Возвращает описание состояния ордера                             |
//+------------------------------------------------------------------+
string OrderStateDescription(const ENUM_ORDER_STATE state,const bool ext_descr=false)
  {
//--- "Вырезаем" из строки, полученной из enum, только состояние ордера
   string res=StringSubstr(EnumToString(state),12);
//--- Преобразуем все полученные символы в нижний регистр и заменяем первую букву с маленькой на заглавную
   if(res.Lower())
      res.SetChar(0,ushort(res.GetChar(0)-0x20));
//--- Заменяем в полученной строке все символы подчёркивания на символ пробела
   StringReplace(res,"_"," ");
   string descr="";
   switch(state)
     {
      case ORDER_STATE_STARTED         :  descr=" (Order checked, but not yet accepted by broker)";            break;
      case ORDER_STATE_PLACED          :  descr=" (Order accepted)";                                           break;
      case ORDER_STATE_CANCELED        :  descr=" (Order canceled by client)";                                 break;
      case ORDER_STATE_PARTIAL         :  descr=" (Order partially executed)";                                 break;
      case ORDER_STATE_FILLED          :  descr=" (Order fully executed)";                                     break;
      case ORDER_STATE_REJECTED        :  descr=" (Order rejected)";                                           break;
      case ORDER_STATE_EXPIRED         :  descr=" (Order expired)";                                            break;
      case ORDER_STATE_REQUEST_ADD     :  descr=" (Order is being registered (placing to the trading system))";break;
      case ORDER_STATE_REQUEST_MODIFY  :  descr=" (Order is being modified (changing its parameters))";        break;
      case ORDER_STATE_REQUEST_CANCEL  :  descr=" (Order is being deleted (deleting from the trading system))";break;
      default: break;
     }
   return res+(!ext_descr ? "" : descr);
   /* Пример вывода:
      Placed (Order accepted)
   */
  }

Каждый ордер имеет статус, описывающий его состояние. Для получения информации используйте функцию OrderGetInteger() или HistoryOrderGetInteger() с модификатором ORDER_STATE. Допустимые значения хранятся в перечислении ENUM_ORDER_STATE. При отсылке торгового запроса на сервер, статус ордера постепенно меняется. Сначала он проверяется сервером, затем размещается в торговой системе, а далее срабатывает, порождая сделку, либо может быть отменён. В перечислении указаны все возможные состояния ордеров, и их нужно учитывать при работе с торговыми приказами.


Функция, возвращающая описание типа сделки:

//+------------------------------------------------------------------+
//| Возвращает описание типа сделки                                  |
//+------------------------------------------------------------------+
string DealTypeDescription(const ENUM_DEAL_TYPE type,const bool ext_descr=false)
  {
//--- "Вырезаем" из строки, полученной из enum, только тип сделки
   string res=StringSubstr(EnumToString(type),(type==DEAL_DIVIDEND || type==DEAL_DIVIDEND_FRANKED || type==DEAL_TAX ? 5 : 10));
//--- Преобразуем все полученные символы в нижний регистр и заменяем первую букву с маленькой на заглавную
   if(res.Lower())
      res.SetChar(0,ushort(res.GetChar(0)-0x20));
//--- Заменяем в полученной строке все символы подчёркивания на символ пробела
   StringReplace(res,"_"," ");
   string descr="";
//--- Расширенные описания добавляются только к тем сделкам, чьё описание, полученное из enum, не совпадает с расширенным
   switch(type)
     {
      case DEAL_TYPE_CHARGE                  : descr=" (Additional charge)";                          break;
      case DEAL_TYPE_COMMISSION              : descr=" (Additional commission)";                      break;
      case DEAL_TYPE_COMMISSION_DAILY        : descr=" (Daily commission)";                           break;
      case DEAL_TYPE_COMMISSION_MONTHLY      : descr=" (Monthly commission)";                         break;
      case DEAL_TYPE_COMMISSION_AGENT_DAILY  : descr=" (Daily agent commission)";                     break;
      case DEAL_TYPE_COMMISSION_AGENT_MONTHLY: descr=" (Monthly agent commission)";                   break;
      case DEAL_TYPE_INTEREST                : descr=" (Interest rate)";                              break;
      case DEAL_TYPE_BUY_CANCELED            : descr=" (Canceled buy deal)";                          break;
      case DEAL_TYPE_SELL_CANCELED           : descr=" (Canceled sell deal)";                         break;
      case DEAL_DIVIDEND                     : descr=" (Dividend operations)";                        break;
      case DEAL_DIVIDEND_FRANKED             : descr=" (Franked (non-taxable) dividend operations)";  break;
      case DEAL_TAX                          : descr=" (Tax charges)";                                break;
      default: break;
     }
   return res+(!ext_descr ? "" : descr);
   /* Пример вывода:
      Comission (Additional commission)
   */
  }

Каждая сделка характеризуется типом, возможные значения перечислены в ENUM_DEAL_TYPE. Для получения информации о типе сделки используйте функцию HistoryDealGetInteger() с модификатором DEAL_TYPE.


Функция, возвращающая описание типа ордера по истечению:

//+------------------------------------------------------------------+
//| Возвращает описание типа ордера по истечению                     |
//+------------------------------------------------------------------+
string OrderTypeTimeDescription(const ENUM_ORDER_TYPE_TIME type_time,const bool ext_descr=false)
  {
//--- "Вырезаем" из строки, полученной из enum, только тип ордера по истечению
   string res=StringSubstr(EnumToString(type_time),6);
//--- Если тип по истечению ORDER_TIME_GTC, то впишем в res "Time GTC"
   if(type_time==ORDER_TIME_GTC)
      res="Time GTC";
//--- Иначе - преобразуем все полученные символы в нижний регистр и заменяем первую букву с маленькой на заглавную
   else
     {
      if(res.Lower())
         res.SetChar(0,ushort(res.GetChar(0)-0x20));
      //--- Заменяем в полученной строке все символы подчёркивания на символ пробела
      StringReplace(res,"_"," ");
     }
   string descr="";
   switch(type_time)
     {
      case ORDER_TIME_GTC           : descr=" (Good till cancel order)";                                          break;
      case ORDER_TIME_DAY           : descr=" (Good till current trade day order)";                               break;
      case ORDER_TIME_SPECIFIED     : descr=" (Good till expired order)";                                         break;
      case ORDER_TIME_SPECIFIED_DAY : descr=" (The order will be effective till 23:59:59 of the specified day)";  break;
      default: break;
     }
   return res+(!ext_descr ? "" : descr);
   /* Пример вывода:
      Time GTC (Good till cancel order)
   */
  }

Срок действия ордера можно задать в поле type_time структуры MqlTradeRequest при отправке торгового запроса функцией OrderSend(). Допустимы значения из перечисления ENUM_ORDER_TYPE_TIME. Для получения значения этого свойства используйте функцию OrderGetInteger() или HistoryOrderGetInteger() с модификатором ORDER_TYPE_TIME.

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

//+------------------------------------------------------------------+
//| Определяет и устанавливает значения принадлежности транзакции    |
//+------------------------------------------------------------------+
void SetTransactionBelong(const ENUM_TRADE_TRANSACTION_TYPE type,bool &request_flag,bool &order_flag,bool &deal_flag,bool &position_flag)
  {
   switch(type)
     {
      //--- Запрос
      case TRADE_TRANSACTION_REQUEST         : request_flag=true; order_flag=false; deal_flag=false; position_flag=false; break;
      //--- Ордер
      case TRADE_TRANSACTION_ORDER_ADD       :
      case TRADE_TRANSACTION_ORDER_UPDATE    :
      case TRADE_TRANSACTION_ORDER_DELETE    :
      case TRADE_TRANSACTION_HISTORY_ADD     :
      case TRADE_TRANSACTION_HISTORY_UPDATE  :
      case TRADE_TRANSACTION_HISTORY_DELETE  : request_flag=false; order_flag=true; deal_flag=false; position_flag=false; break;
      //--- Сделка
      case TRADE_TRANSACTION_DEAL_ADD        :
      case TRADE_TRANSACTION_DEAL_UPDATE     :
      case TRADE_TRANSACTION_DEAL_DELETE     : request_flag=false; order_flag=false; deal_flag=true; position_flag=false; break;
      //--- Позиция
      case TRADE_TRANSACTION_POSITION        : request_flag=false; order_flag=false; deal_flag=false; position_flag=true; break;
      //---
      default: break;
     }
  }

В функцию передаётся тип транзакции и по ссылке три переменных-флага, которые и устанавливаются/сбрасываются в зависимости от того, с чем именно была проведена транзакция.


Функция, возвращающая описание типа торговго запроса:

//+------------------------------------------------------------------+
//| Возвращает описание типа торговго запроса                        |
//+------------------------------------------------------------------+
string TradeActionDescription(const ENUM_TRADE_REQUEST_ACTIONS action,const bool ext_descr=false)
  {
//--- "Вырезаем" из строки, полученной из enum, только тип операции
   string res=StringSubstr(EnumToString(action),13);
//--- Преобразуем все полученные символы в нижний регистр и заменяем первую букву с маленькой на заглавную (кроме TRADE_ACTION_SLTP)
   if(action!=TRADE_ACTION_SLTP && res.Lower())
      res.SetChar(0,ushort(res.GetChar(0)-0x20));
   string descr="";
   switch(action)
     {
      case TRADE_ACTION_DEAL     : descr=" (Place a trade order for an immediate execution with the specified parameters (market order))";break;
      case TRADE_ACTION_PENDING  : descr=" (Place a trade order for the execution under specified conditions (pending order))";           break;
      case TRADE_ACTION_SLTP     : descr=" (Modify Stop Loss and Take Profit values of an opened position)";                              break;
      case TRADE_ACTION_MODIFY   : descr=" (Modify the parameters of the order placed previously)";                                       break;
      case TRADE_ACTION_REMOVE   : descr=" (Delete the pending order placed previously)";                                                 break;
      case TRADE_ACTION_CLOSE_BY : descr=" (Close a position by an opposite one)";                                                        break;
      default: break;
     }
   return res+(!ext_descr ? "" : descr);
   /* Пример вывода:
      Pending (Place a trade order for the execution under specified conditions (pending order)):
   */
  }


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

Структура MqlTradeRequest для создания запроса при проведении торговых операций

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

struct MqlTradeRequest
  {
   ENUM_TRADE_REQUEST_ACTIONS    action;           // Тип выполняемого действия
   ulong                         magic;            // Штамп эксперта (идентификатор magic number)
   ulong                         order;            // Тикет ордера
   string                        symbol;           // Имя торгового инструмента
   double                        volume;           // Запрашиваемый объем сделки в лотах
   double                        price;            // Цена 
   double                        stoplimit;        // Уровень StopLimit ордера
   double                        sl;               // Уровень Stop Loss ордера
   double                        tp;               // Уровень Take Profit ордера
   ulong                         deviation;        // Максимально приемлемое отклонение от запрашиваемой цены
   ENUM_ORDER_TYPE               type;             // Тип ордера
   ENUM_ORDER_TYPE_FILLING       type_filling;     // Тип ордера по исполнению
   ENUM_ORDER_TYPE_TIME          type_time;        // Тип ордера по времени действия
   datetime                      expiration;       // Срок истечения ордера (для ордеров типа ORDER_TIME_SPECIFIED)
   string                        comment;          // Комментарий к ордеру
   ulong                         position;         // Тикет позиции
   ulong                         position_by;      // Тикет встречной позиции
  };

Для отсылки торгового приказа на сервер нужно заполнять поля структуры соответствующим приказу образом. Поле action заполняется обязательно, и от того, какое действие записано в это поле, заполняются только необходимые для данного действия другие поля структуры. Соответственно, неиспользуемые поля будут содержать нули (при условии обнуления полей структуры перед её заполнением). При выводе описания полей структуры нужно учитывать, что некоторые поля не используются и содержат нули. Это нужно отобразить при выводе неиспользуемого поля в журнал, например, вместо использования для значения количества знаков после запятой (1.12345), использовать только один (0.0) — так будет понятнее, что это поле просто не заполнено.

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


Тип выполняемого действия

Тип торговой операции. Значение может быть одним из значений перечисления ENUM_TRADE_REQUEST_ACTIONS.

//+------------------------------------------------------------------+
//| Возвращает в виде строки тип выполняемого действия               |
//+------------------------------------------------------------------+
string MqlTradeRequestAction(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0,const bool ext_descr=false)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Action:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-s",indent,"",w,header,TradeActionDescription(req.action,ext_descr));
   /* Пример вывода:
      Action: Pending (Place a trade order for the execution under specified conditions (pending order)):
   */
  }


Штамп эксперта (идентификатор magic number)

Идентификатор эксперта. Позволяет организовать аналитическую обработку торговых ордеров. Каждый эксперт может выставлять свой собственный уникальный идентификатор при отправке торгового запроса.
//+------------------------------------------------------------------+
//| Возвращает в виде строки штамп эксперта (magic number)           |
//+------------------------------------------------------------------+
string MqlTradeRequestMagic(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Magic:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,req.magic);
   /* Пример вывода:
      Magic: 1024
   */
  }


Тикет ордера

Тикет ордера. Требуется для модификации отложенных ордеров.

//+------------------------------------------------------------------+
//| Возвращает в виде строки тикет ордера                            |
//+------------------------------------------------------------------+
string MqlTradeRequestOrder(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Order:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,req.order);
   /* Пример вывода:
      Order: 1835982676
   */
  }


Имя торгового инструмента

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

//+------------------------------------------------------------------+
//| Возвращает имя торгового инструмента                             |
//+------------------------------------------------------------------+
string MqlTradeRequestSymbol(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Symbol:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-s",indent,"",w,header,req.symbol);
   /* Пример вывода:
      Symbol: EURUSD
   */
  }


Запрашиваемый объем сделки в лотах

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

//+------------------------------------------------------------------+
//| Возвращает в виде строки запрашиваемый объем сделки в лотах      |
//+------------------------------------------------------------------+
string MqlTradeRequestVolume(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Volume:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Получаем количество знаков после запятой в значении лота. Если символ не указан, используем 1
   int dg=(int)ceil(fabs(log10(SymbolInfoDouble(req.symbol,SYMBOL_VOLUME_STEP))));
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,req.volume);
   /* Пример вывода:
      Volume: 0.10
   */
  }


Цена

Цена, при достижении которой ордер должен быть исполнен. Для рыночных ордеров по инструментам с типом исполнения "Market Execution" (SYMBOL_TRADE_EXECUTION_MARKET), имеющих тип TRADE_ACTION_DEAL, указание цены не требуется.

//+------------------------------------------------------------------+
//| Возвращает в виде строки цену                                    |
//+------------------------------------------------------------------+
string MqlTradeRequestPrice(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Price:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Получаем количество знаков после запятой
   int dg=(req.price!=0 ? (int)SymbolInfoInteger(req.symbol,SYMBOL_DIGITS) : 1);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,req.price);
   /* Пример вывода:
      Price: 1.09586
   */
  }


Уровень StopLimit ордера

Для отложенных ордеров BuyStopLimit и SellStopLimit. Цена, по которой будет выставлен отложенный Limit ордер, при достижении ценой значения price (это условие является обязательным). До этого момента отложенный ордер в торговую систему не выводится.

//+------------------------------------------------------------------+
//| Возвращает в виде строки уровень StopLimit ордера                |
//+------------------------------------------------------------------+
string MqlTradeRequestStopLimit(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="StopLimit:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Получаем количество знаков после запятой
   int dg=(req.stoplimit!=0 ? (int)SymbolInfoInteger(req.symbol,SYMBOL_DIGITS) : 1);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,req.stoplimit);
   /* Пример вывода:
      StopLimit: 0.0
   */
  }


Уровень Stop Loss ордера

Цена, по которой сработает Stop Loss ордер при движении цены в неблагоприятном направлении.

//+------------------------------------------------------------------+
//| Возвращает в виде строки уровень Stop Loss ордера                |
//+------------------------------------------------------------------+
string MqlTradeRequestStopLoss(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="SL:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Получаем количество знаков после запятой
   int dg=(req.sl!=0 ? (int)SymbolInfoInteger(req.symbol,SYMBOL_DIGITS) : 1);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,req.sl);
   /* Пример вывода:
      SL: 0.0
   */
  }


Уровень Take Profit ордера

Цена, по которой сработает Take Profit ордер при движении цены в благоприятном направлении.

//+------------------------------------------------------------------+
//| Возвращает в виде строки уровень Take Profit ордера              |
//+------------------------------------------------------------------+
string MqlTradeRequestTakeProfit(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="TP:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Получаем количество знаков после запятой
   int dg=(req.tp!=0 ? (int)SymbolInfoInteger(req.symbol,SYMBOL_DIGITS) : 1);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,req.tp);
   /* Пример вывода:
      TP: 0.0
   */
  }


Отклонение от запрашиваемой цены

Максимально приемлемое отклонение от запрашиваемой цены, задаваемое в пунктах.

//+------------------------------------------------------------------+
//| Возвращает в виде строки максимально приемлемое                  |
//| отклонение от запрашиваемой цены                                 |
//+------------------------------------------------------------------+
string MqlTradeRequestDeviation(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Deviation:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,req.deviation);
   /* Пример вывода:
      Deviation: 5
   */
  }


Тип ордера

Тип ордера. Значение может быть одним из значений перечисления ENUM_ORDER_TYPE.

//+------------------------------------------------------------------+
//| Возвращает в виде строки тип ордера                              |
//+------------------------------------------------------------------+
string MqlTradeRequestType(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0,bool ext_descr=false)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Type:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-s",indent,"",w,header,OrderTypeDescription(req.type,ext_descr));
   /* Пример вывода:
      Type: Buy Limit (Buy Limit pending order)
   */
  }


Тип ордера по исполнению

Тип ордера по исполнению. Значение может быть одним из значений ENUM_ORDER_TYPE_FILLING.

//+------------------------------------------------------------------+
//| Возвращает в виде строки тип ордера по исполнению                |
//+------------------------------------------------------------------+
string MqlTradeRequestTypeFilling(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0,bool ext_descr=false)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Type filling:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-s",indent,"",w,header,OrderTypeFillingDescription(req.type_filling,ext_descr));
   /* Пример вывода:
      Type filling: Return (In case of partial filling, an order with remaining volume is not canceled but processed further)
   */
  }


Тип ордера по времени действия

Тип ордера по истечению. Значение может быть одним из значений ENUM_ORDER_TYPE_TIME.

//+------------------------------------------------------------------+
//| Возвращает в виде строки тип ордера по времени действия          |
//+------------------------------------------------------------------+
string MqlTradeRequestTypeTime(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0,bool ext_descr=false)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Type time:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-s",indent,"",w,header,OrderTypeTimeDescription(req.type_time,ext_descr));
   /* Пример вывода:
      Type time: Time GTC (Good till cancel order)
   */
  }


Срок истечения ордера

Срок истечения отложенного ордера (для ордеров типа ORDER_TIME_SPECIFIED).

//+------------------------------------------------------------------+
//| Возвращает в виде строки срок истечения ордера                   |
//+------------------------------------------------------------------+
string MqlTradeRequestExpiration(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Expiration:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-s",indent,"",w,header,(req.type_time==ORDER_TIME_SPECIFIED || req.type_time==ORDER_TIME_SPECIFIED_DAY ? (string)req.expiration : "0"));
   /* Пример вывода:
      Expiration: 0
   */
  }


Комментарий к ордеру

//+------------------------------------------------------------------+
//| Возвращает комментарий к ордеру                                  |
//+------------------------------------------------------------------+
string MqlTradeRequestComment(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Comment:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-s",indent,"",w,header,req.comment);
   /* Пример вывода:
      Comment: TestMqlTradeTransaction
   */
  }


Тикет позиции

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

//+------------------------------------------------------------------+
//| Возвращает в виде строки тикет позиции                           |
//+------------------------------------------------------------------+
string MqlTradeRequestPosition(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Position:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,req.position);
   /* Пример вывода:
      Position: 1835982676
   */
  }


Тикет встречной позиции

Тикет встречной позиции. Используется при закрытии позиции встречной — открытой по тому же инструменту, но в противоположном направлении.

//+------------------------------------------------------------------+
//| Возвращает в виде строки тикет встречной позиции                 |
//+------------------------------------------------------------------+
string MqlTradeRequestPositionBy(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Position by:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,req.position_by);
   /* Пример вывода:
      Position by: 1835987626
   */
  }


Примеры использования

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

Функция, выводящая в журнал описание торгового запроса:

//+------------------------------------------------------------------+
//| Выводит в журнал описание торгового запроса                      |
//+------------------------------------------------------------------+
void TradeRequestPrint(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0,bool ext_descr=false)
  {
//--- Получаем тип исполнения по символу
   ENUM_SYMBOL_TRADE_EXECUTION exemode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(req.symbol,SYMBOL_TRADE_EXEMODE);
//--- Заголовок
   PrintFormat("Request %s:",TradeActionDescription(req.action,ext_descr));
//--- Установить торговый ордер на немедленное совершение сделки с указанными параметрами (поставить рыночный ордер)
   if(req.action==TRADE_ACTION_DEAL)
     {
      //--- В зависимости от режима заключения сделок 
      switch(exemode)
        {
         //--- Торговый ордер на открытие позиции в режиме Request Execution (режим торговли по запросу текущих цен)
         //--- Торговый ордер на открытие позиции в режиме Instant Execution (режим торговли по потоковым ценам)
         case SYMBOL_TRADE_EXECUTION_REQUEST    :
         case SYMBOL_TRADE_EXECUTION_INSTANT    :
            Print(MqlTradeRequestSymbol(req,header_width,indent));
            Print(MqlTradeRequestVolume(req,header_width,indent));
            Print(MqlTradeRequestPrice(req,header_width,indent));
            if(req.position==0)  // Только для открытия позиции
               Print(MqlTradeRequestStopLoss(req,header_width,indent));
            if(req.position==0)  // Только для открытия позиции
               Print(MqlTradeRequestTakeProfit(req,header_width,indent));
            Print(MqlTradeRequestDeviation(req,header_width,indent));
            Print(MqlTradeRequestType(req,header_width,indent,ext_descr));
            Print(MqlTradeRequestTypeFilling(req,header_width,indent,ext_descr));
            Print(MqlTradeRequestMagic(req,header_width,indent));
            if(req.position==0)  // Только для открытия позиции
               Print(MqlTradeRequestComment(req,header_width,indent));
            //--- Закрытие
            if(req.position!=0)
               Print(MqlTradeRequestPosition(req,header_width,indent));
           break;
         //--- Торговый ордер на открытие позиции в режиме Market Execution (режим исполнения торговых приказов по рынку)
         //--- Торговый ордер на открытие позиции в режиме Exchange Execution (биржевой режим исполнения торговых приказов)
         case SYMBOL_TRADE_EXECUTION_MARKET     :
         case SYMBOL_TRADE_EXECUTION_EXCHANGE   :
            Print(MqlTradeRequestSymbol(req,header_width,indent));
            Print(MqlTradeRequestVolume(req,header_width,indent));
            Print(MqlTradeRequestType(req,header_width,indent,ext_descr));
            Print(MqlTradeRequestTypeFilling(req,header_width,indent,ext_descr));
            Print(MqlTradeRequestMagic(req,header_width,indent));
            if(req.position==0)  // Только для открытия позиции
               Print(MqlTradeRequestComment(req,header_width,indent));
            //--- Закрытие
            if(req.position!=0)
               Print(MqlTradeRequestPosition(req,header_width,indent));
           break;
         default:
           break;
        }
     }
//--- Торговый приказ на закрытие позиции встречной
   if(req.action==TRADE_ACTION_CLOSE_BY)
     {
      Print(MqlTradeRequestSymbol(req,header_width,indent));
      Print(MqlTradeRequestPosition(req,header_width,indent));
      Print(MqlTradeRequestMagic(req,header_width,indent));
      Print(MqlTradeRequestComment(req,header_width,indent));
      Print(MqlTradeRequestPositionBy(req,header_width,indent));
     }
//--- Торговый приказ на модификацию уровней StopLoss и/или TakeProfit
   if(req.action==TRADE_ACTION_SLTP)
     {
      Print(MqlTradeRequestSymbol(req,header_width,indent));
      Print(MqlTradeRequestStopLoss(req,header_width,indent));
      Print(MqlTradeRequestTakeProfit(req,header_width,indent));
      Print(MqlTradeRequestPosition(req,header_width,indent));
     }
//--- Торговый приказ на установку отложенного ордера
   if(req.action==TRADE_ACTION_PENDING)
     {
      Print(MqlTradeRequestSymbol(req,header_width,indent));
      Print(MqlTradeRequestVolume(req,header_width,indent));
      Print(MqlTradeRequestPrice(req,header_width,indent));
      if(req.type==ORDER_TYPE_BUY_STOP_LIMIT || req.type==ORDER_TYPE_SELL_STOP_LIMIT)
         Print(MqlTradeRequestStopLimit(req,header_width,indent));
      Print(MqlTradeRequestStopLoss(req,header_width,indent));
      Print(MqlTradeRequestTakeProfit(req,header_width,indent));
      Print(MqlTradeRequestType(req,header_width,indent,ext_descr));
      Print(MqlTradeRequestTypeFilling(req,header_width,indent,ext_descr));
      Print(MqlTradeRequestTypeTime(req,header_width,indent,ext_descr));
      Print(MqlTradeRequestExpiration(req,header_width,indent));
      Print(MqlTradeRequestMagic(req,header_width,indent));
      Print(MqlTradeRequestComment(req,header_width,indent));
     }
//--- Торговый приказ на модификацию уровней цен отложенного ордера
   if(req.action==TRADE_ACTION_MODIFY)
     {
      Print(MqlTradeRequestOrder(req,header_width,indent));
      Print(MqlTradeRequestPrice(req,header_width,indent));
      if(req.stoplimit!=0)
         Print(MqlTradeRequestStopLimit(req,header_width,indent));
      Print(MqlTradeRequestStopLoss(req,header_width,indent));
      Print(MqlTradeRequestTakeProfit(req,header_width,indent));
      Print(MqlTradeRequestTypeTime(req,header_width,indent,ext_descr));
      Print(MqlTradeRequestExpiration(req,header_width,indent));
     }
//--- Торговый приказ на удаление отложенного ордера
   if(req.action==TRADE_ACTION_REMOVE)
     {
      Print(MqlTradeRequestOrder(req,header_width,indent));
     }
   /* Пример вывода:
      Request Pending (Place a trade order for the execution under specified conditions (pending order)):
        Symbol: EURUSD
        Volume: 0.10
        Price: 1.09586
        SL: 0.0
        TP: 0.0
        Type: Buy Limit (Buy Limit pending order)
        Type filling: Return (In case of partial filling, an order with remaining volume is not canceled but processed further)
        Type time: Time GTC (Good till cancel order)
        Expiration: 0
        Magic: 1024
        Comment: TestMqlTradeTransaction
   */
  }


OpenBuy для открытия позиции на покупку:

//+------------------------------------------------------------------+
//| Открывает позицию Buy                                            |
//+------------------------------------------------------------------+
bool OpenBuy(const string symbol,const double lots,const uint magic,const ulong deviation=5,const string comment="")
  {
//--- Устанавливаем символ для запроса
   string symbol_name=(symbol==NULL ? Symbol() : symbol);
//--- Объявляем и инициализируем структуры запроса и результата
   MqlTradeRequest request={};
   MqlTradeResult  result={};
//--- Получаем нормализованную цену
   double price=NormalizeDouble(SymbolInfoDouble(symbol_name,SYMBOL_ASK),(int)SymbolInfoInteger(symbol_name,SYMBOL_DIGITS));
//--- параметры запроса
   request.action    =  TRADE_ACTION_DEAL;                        // тип торговой операции
   request.symbol    =  symbol_name;                              // символ
   request.volume    =  lots;                                     // объем позиции
   request.type      =  ORDER_TYPE_BUY;                           // тип ордера
   request.price     =  price;                                    // цена для открытия
   request.deviation =  deviation;                                // допустимое отклонение от цены
   request.magic     =  magic;                                    // MagicNumber ордера
   request.comment   =  comment;                                  // Комментарий ордера
//--- Если отправить запрос не удалось - сообщим об этом в журнал и вернём false
   if(!OrderSend(request,result))
     {
      PrintFormat("%s: OrderSend for %s %s error: %s",__FUNCTION__,
                  TradeActionDescription(request.action),OrderTypeDescription(request.type),RetcodeDescription(result.retcode,true)
                 );
      return false;
     }
//--- OrderSend OK, вернём true
   return true;
  }


OpenSell для открытия позиции на продажу:

//+------------------------------------------------------------------+
//| Открывает позицию Sell                                           |
//+------------------------------------------------------------------+
bool OpenSell(const string symbol,const double lots,const uint magic,const ulong deviation=5,const string comment="")
  {
//--- Устанавливаем символ для запроса
   string symbol_name=(symbol==NULL ? Symbol() : symbol);
//--- Объявляем и инициализируем структуры запроса и результата
   MqlTradeRequest request={};
   MqlTradeResult  result={};
//--- Получаем нормализованную цену
   double price=NormalizeDouble(SymbolInfoDouble(symbol_name,SYMBOL_BID),(int)SymbolInfoInteger(symbol_name,SYMBOL_DIGITS));
//--- параметры запроса
   request.action    =  TRADE_ACTION_DEAL;                        // тип торговой операции
   request.symbol    =  symbol_name;                              // символ
   request.volume    =  lots;                                     // объем позиции
   request.type      =  ORDER_TYPE_SELL;                          // тип ордера
   request.price     =  price;                                    // цена для открытия
   request.deviation =  deviation;                                // допустимое отклонение от цены
   request.magic     =  magic;                                    // MagicNumber ордера
   request.comment   =  comment;                                  // Комментарий ордера
//--- Если отправить запрос не удалось - сообщим об этом в журнал и вернём false
   if(!OrderSend(request,result))
     {
      PrintFormat("%s: OrderSend for %s %s error: %s",__FUNCTION__,
                  TradeActionDescription(request.action),OrderTypeDescription(request.type),RetcodeDescription(result.retcode,true)
                 );
      return false;
     }
//--- OrderSend OK, вернём true
   return true;
  }


ClosePosition для закрытия указанной позиции:

//+------------------------------------------------------------------+
//| Закрывает позицию по тикету                                      |
//+------------------------------------------------------------------+
bool ClosePosition(const ulong ticket,const ulong deviation=5)
  {
//--- Объявляем структуры запроса и результата
   MqlTradeRequest request;
   MqlTradeResult  result;
//--- Если позицию не удалось выбрать по тикету - сообщаем об ошибке и уходим
   ResetLastError();
   if(!PositionSelectByTicket(ticket))
     {
      Print("PositionSelectByTicket failed, error: ",(string)GetLastError());
      return false;
     }
//--- Получаем данные закрываемой позиции
   string position_symbol=PositionGetString(POSITION_SYMBOL);                       // символ 
   int    digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS);             // количество знаков после запятой
   double volume=PositionGetDouble(POSITION_VOLUME);                                // объем позиции
   ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);   // тип позиции
   ulong magic=PositionGetInteger(POSITION_MAGIC);                                  // MagicNumber позиции
//--- Обнуляем значения запроса и результата
   ZeroMemory(request);
   ZeroMemory(result);
//--- Устанавливаем параметры операции
   request.action    =  TRADE_ACTION_DEAL;   // тип торговой операции
   request.position  =  ticket;              // тикет позиции
   request.symbol    =  position_symbol;     // символ 
   request.volume    =  volume;              // объем позиции
   request.deviation =  deviation;           // допустимое отклонение от цены
   request.magic     =  magic;               // MagicNumber позиции
//--- Устанавливаем цену и тип ордера в зависимости от типа позиции
   if(type==POSITION_TYPE_BUY)
     {
      request.price=NormalizeDouble(SymbolInfoDouble(position_symbol,SYMBOL_BID),digits);
      request.type =ORDER_TYPE_SELL;
     }
   else
     {
      request.price=NormalizeDouble(SymbolInfoDouble(position_symbol,SYMBOL_ASK),digits);
      request.type =ORDER_TYPE_BUY;
     }
//--- Если отправить запрос не удалось, сообщим об этом в журнал и вернём false
   if(!OrderSend(request,result))
     {
      PrintFormat("%s: OrderSend for %s %s #%llu error: %s",__FUNCTION__,
                  TradeActionDescription(request.action),OrderTypeDescription(request.type),ticket,RetcodeDescription(result.retcode,true)
                 );
      return false;
     }
//--- OrderSend OK, вернём true
   return true;
  }


ClosePositionsAll для закрытия всех позиций:

//+------------------------------------------------------------------+
//| Закрывает все позиции по символу                                 |
//+------------------------------------------------------------------+
uint ClosePositionsAll(const string symbol,const ulong magic=0)
  {
//--- Объявим переменную для хранения результата и количества закрытых позиций
   bool res=true;
   uint num=0;
//--- перебор всех открытых позиций
   int total=PositionsTotal();                     // количество открытых позиций
   for(int i=total-1; i>=0; i--)
     {
      ulong  position_ticket=PositionGetTicket(i); // тикет позиции
      if(position_ticket==0)
         continue;
      if(PositionGetInteger(POSITION_MAGIC)!=magic)
         continue;
      //--- Если MagicNumber не указан (нулевой) или магик позиции соответствует указанному
      if(magic==0 || PositionGetInteger(POSITION_MAGIC)==magic)
        {
         //--- если символ позиции совпадает с переданным или передан NULL - закрываем позицию по тикету
         if(symbol==NULL || PositionGetString(POSITION_SYMBOL)==symbol)
           {
            //--- Получаем результат закрытия позиции по тикету и увеличиваем счётчик закрытых при успехе
            res &=ClosePosition(position_ticket);
            if(res)
               num++;
           }
        }
     }
   if(!res)
      PrintFormat("%s: Not all positions were able to close without errors",__FUNCTION__);
   return num;
  }


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

//+------------------------------------------------------------------+
//| Устанавливает указанный отложенный ордер                         |
//+------------------------------------------------------------------+
bool SetPending(const string symbol,const ENUM_ORDER_TYPE order_type,const double lots,const uint magic,const int distance,const int stoplimit=0,const string comment="")
  {
//--- Устанавливаем символ для запроса
   string symbol_name=(symbol==NULL ? Symbol() : symbol);
//--- Объявляем и инициализируем структуры запроса и результата
   MqlTradeRequest request={};
   MqlTradeResult  result={};
//--- Устанавливаем параметры операции
   request.action    =  TRADE_ACTION_PENDING;                     // тип торговой операции
   request.type      =  order_type;                               // тип ордера
   request.symbol    =  symbol_name;                              // символ
   request.volume    =  lots;                                     // объем
   request.magic     =  magic;                                    // MagicNumber ордера
   request.comment   =  comment;                                  // Комментарий ордера
//--- Получаем Point и Digits
   double point=SymbolInfoDouble(symbol_name,SYMBOL_POINT);
   int digits=(int)SymbolInfoInteger(symbol_name,SYMBOL_DIGITS);
//--- Рассчитываем дистанцию от цены в зависимости от типа ордера
//--- Ордер на покупку
   if(order_type==ORDER_TYPE_BUY_STOP)
      request.price=NormalizeDouble(SymbolInfoDouble(symbol_name,SYMBOL_ASK)+distance*point,digits);  // нормализованная цена установки 
   if(order_type==ORDER_TYPE_BUY_LIMIT)
      request.price=NormalizeDouble(SymbolInfoDouble(symbol_name,SYMBOL_ASK)-distance*point,digits);  // нормализованная цена установки 
   if(order_type==ORDER_TYPE_BUY_STOP_LIMIT)
     {
      request.price=NormalizeDouble(SymbolInfoDouble(symbol_name,SYMBOL_ASK)+distance*point,digits);  // нормализованная цена срабатывания Stop-ордера 
      request.stoplimit=NormalizeDouble(request.price-stoplimit*point,digits);                        // нормализованная цена установки Limit-ордера
     }
//--- Ордер на продажу
   if(order_type==ORDER_TYPE_SELL_STOP)
      request.price=NormalizeDouble(SymbolInfoDouble(symbol_name,SYMBOL_BID)-distance*point,digits);  // нормализованная цена установки 
   if(order_type==ORDER_TYPE_SELL_LIMIT)
      request.price=NormalizeDouble(SymbolInfoDouble(symbol_name,SYMBOL_BID)+distance*point,digits);  // нормализованная цена установки 
   if(order_type==ORDER_TYPE_SELL_STOP_LIMIT)
     {
      request.price=NormalizeDouble(SymbolInfoDouble(symbol_name,SYMBOL_BID)-distance*point,digits);  // нормализованная цена срабатывания Stop-ордера 
      request.stoplimit=NormalizeDouble(request.price+stoplimit*point,digits);                        // нормализованная цена установки Limit-ордера
     }
//--- Если отправить запрос не удалось, сообщим об этом в журнал и вернём false
   if(!OrderSend(request,result))
     {
      PrintFormat("%s: OrderSend for %s %s error: %s",__FUNCTION__,
                  TradeActionDescription(request.action),OrderTypeDescription(request.type),RetcodeDescription(result.retcode,true)
                 );
      return false;
     }
//--- OrderSend OK, вернём true
   return true;
  }


На основе функции, представленной выше, можно сделать функции, устанавливающие конкретный тип отложенного ордера:

SetBuyStop для установки отложенного ордера BuyStop:

//+------------------------------------------------------------------+
//| Устанавливает отложенный ордер BuyStop                           |
//+------------------------------------------------------------------+
bool SetBuyStop(const string symbol,const double lots,const uint magic,const int distance,const string comment="")
  {
//--- Вызываем функцию SetPending с параметрами для BuyStop
   return SetPending(symbol,ORDER_TYPE_BUY_STOP,lots,magic,distance,0,comment);
  }


SetBuyLimit для установки отложенного ордера BuyLimit:

//+------------------------------------------------------------------+
//| Устанавливает отложенный ордер BuyLimit                          |
//+------------------------------------------------------------------+
bool SetBuyLimit(const string symbol,const double lots,const uint magic,const int distance,const string comment="")
  {
//--- Вызываем функцию SetPending с параметрами для BuyLimit
   return SetPending(symbol,ORDER_TYPE_BUY_LIMIT,lots,magic,distance,0,comment);
  }


SetBuyStopLimit для установки отложенного ордера BuyStopLimit:

//+------------------------------------------------------------------+
//| Устанавливает отложенный ордер BuyStopLimit                      |
//+------------------------------------------------------------------+
bool SetBuyStopLimit(const string symbol,const double lots,const uint magic,const int distance,const int stoplimit,const string comment="")
  {
//--- Вызываем функцию SetPending с параметрами для BuyStopLimit
   return SetPending(symbol,ORDER_TYPE_BUY_STOP_LIMIT,lots,magic,distance,stoplimit,comment);
  }


SetSellStop для установки отложенного ордера SellStop:

//+------------------------------------------------------------------+
//| Устанавливает отложенный ордер SellStop                          |
//+------------------------------------------------------------------+
bool SetSellSellStop(const string symbol,const double lots,const uint magic,const int distance,const string comment="")
  {
//--- Вызываем функцию SetPending с параметрами для SellStop
   return SetPending(symbol,ORDER_TYPE_SELL_STOP,lots,magic,distance,0,comment);
  }


SetSellLimit для установки отложенного ордера SellLimit:

//+------------------------------------------------------------------+
//| Устанавливает отложенный ордер SellLimit                         |
//+------------------------------------------------------------------+
bool SetSellLimit(const string symbol,const double lots,const uint magic,const int distance,const string comment="")
  {
//--- Вызываем функцию SetPending с параметрами для SellLimit
   return SetPending(symbol,ORDER_TYPE_SELL_LIMIT,lots,magic,distance,0,comment);
  }


SetSellStopLimit для установки отложенного ордера SellStopLimit:

//+------------------------------------------------------------------+
//| Устанавливает отложенный ордер SellStopLimit                     |
//+------------------------------------------------------------------+
bool SetSellStopLimit(const string symbol,const double lots,const uint magic,const int distance,const int stoplimit,const string comment="")
  {
//--- Вызываем функцию SetPending с параметрами для SellStopLimit
   return SetPending(symbol,ORDER_TYPE_SELL_STOP_LIMIT,lots,magic,distance,stoplimit,comment);
  }


DeleteOrder для удаления указанного отложенного ордера:

//+------------------------------------------------------------------+
//| Удаляет отложенный ордер по тикету                               |
//+------------------------------------------------------------------+
bool DeleteOrder(const ulong ticket)
  {
//-- объявление и инициализация запроса и результата
   MqlTradeRequest request={};
   MqlTradeResult  result={};
   ResetLastError();
//--- Если ордер не удалось выбрать по тикету - сообщаем об ошибке и уходим
   if(!OrderSelect(ticket))
     {
      PrintFormat("%s: OrderSelect failed, error: %d",__FUNCTION__,GetLastError());
      return false;
     }
//--- Обнуляем значения запроса и результата
   ZeroMemory(request);
   ZeroMemory(result);
//--- Устанавливаем параметры операции
   request.action=TRADE_ACTION_REMOVE;                   // тип торговой операции
   request.order = ticket;                               // тикет ордера
//--- Если отправить запрос не удалось, сообщим об этом в журнал и вернём false
   if(!OrderSend(request,result))
     {
      PrintFormat("%s: OrderSend for %s %s #%llu error: %s",__FUNCTION__,
                  TradeActionDescription(request.action),OrderTypeDescription((ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE)),ticket,RetcodeDescription(result.retcode,true)
                 );
      return false;
     }
//--- OrderSend OK, вернём true
   return true;
  }


DeleteOrdersAll для удаления всех отложенных ордеров:

//+------------------------------------------------------------------+
//| Удаляет все отложенные ордера по символу                         |
//+------------------------------------------------------------------+
uint DeleteOrdersAll(const string symbol,const long magic=WRONG_VALUE)
  {
//--- Объявим переменную для хранения результата и количества удалённых ордеров
   bool res=true;
   uint num=0;
//--- перебор всех установленных отложенных ордеров
   int total=OrdersTotal(); // количество установленных отложенных ордеров
   for(int i=total-1; i>=0; i--)
     {
      ulong  order_ticket=OrderGetTicket(i);             // тикет ордера
      if(order_ticket==0)
         continue;
      //--- Если MagicNumber не указан (нулевой) или магик ордера соответствует указанному
      if(magic==WRONG_VALUE || OrderGetInteger(ORDER_MAGIC)==magic)
        {
         //--- если символ ордера совпадает с переданным или передан NULL - удаляем ордер по тикету
         if(symbol==NULL || OrderGetString(ORDER_SYMBOL)==symbol)
           {
            res &=DeleteOrder(order_ticket);
            if(res)
               num++;
           }
        }
     }
   if(!res)
      PrintFormat("%s: Not all orders were able to close without errors",__FUNCTION__);
   return num;
  }

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

После заполнения структуры торгового приказа можно проверить корректность её заполнения. Сделать это можно при помощи функции OrderCheck(), которая проверяет достаточность средств для совершения требуемой торговой операции.

В случае нехватки средств или ошибочно заполненных параметров функция возвращает false. В случае успешной базовой проверки структур (проверка указателей) возвращается true это не является свидетельством того, что запрашиваемая торговая операция непременно выполнится успешно. Для получения подробного описания результата выполнения функции следует анализировать поля структуры result.

Результаты проверки помещаются в поля структуры MqlTradeCheckResult. Для вывода описаний полей этой структуры напишем соответствующие функции.


Структура MqlTradeCheckResult для проверки подготовленного запроса перед его отправкой

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

struct MqlTradeCheckResult
  {
   uint         retcode;             // Код ответа
   double       balance;             // Баланс после совершения сделки
   double       equity;              // Эквити после совершения сделки
   double       profit;              // Плавающая прибыль
   double       margin;              // Маржевые требования
   double       margin_free;         // Свободная маржа
   double       margin_level;        // Уровень маржи
   string       comment;             // Комментарий к коду ответа (описание ошибки)
  };


Код ответа

Код возвратаВсе приказы на совершение торговых операций отправляются в виде структуры торгового запроса MqlTradeRequest с помощью функции OrderSend(). Результат выполнения этой функции помещается в структуру MqlTradeResult, поле retcode которой содержит код возврата торгового сервера.Так же и здесь — после проверки торгового приказа, код ответа можно прочитать в поле retcode структуры MqlTradeCheckResult.

//+------------------------------------------------------------------+
//| Возвращает в виде строки код ответа                              |
//+------------------------------------------------------------------+
string MqlTradeCheckResultRetcode(const MqlTradeCheckResult &result,const uint header_width=0,const uint indent=0,const bool ext_descr=false)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Retcode:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-s",indent,"",w,header,RetcodeDescription(result.retcode,ext_descr));
   /* Пример вывода:
      Retcode: OK (0)
   */
  }


Баланс после совершения сделки

Значение баланса, которое будет после выполнения торговой операции.

//+------------------------------------------------------------------+
//| Возвращает в виде строки баланс после совершения сделки          |
//+------------------------------------------------------------------+
string MqlTradeCheckResultBalance(const MqlTradeCheckResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Balance:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Получаем валюту счёта
   string currency=AccountInfoString(ACCOUNT_CURRENCY);
//--- Получаем количество знаков после запятой
   int dg=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-.*f %s",indent,"",w,header,dg,result.balance,currency);
   /* Пример вывода:
      Balance: 10016.80 USD
   */
  }


Эквити после совершения сделки

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

//+------------------------------------------------------------------+
//| Возвращает в виде строки эквити после совершения сделки          |
//+------------------------------------------------------------------+
string MqlTradeCheckResultEquity(const MqlTradeCheckResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Equity:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Получаем валюту счёта
   string currency=AccountInfoString(ACCOUNT_CURRENCY);
//--- Получаем количество знаков после запятой
   int dg=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-.*f %s",indent,"",w,header,dg,result.equity,currency);
   /* Пример вывода:
      Equity: 10016.80 USD
   */
  }


Плавающая прибыль

Значение плавающей прибыли, которое будет после выполнения торговой операции.

//+------------------------------------------------------------------+
//|Возвращает в виде строки плавающую прибыль после совершения сделки|
//+------------------------------------------------------------------+
string MqlTradeCheckResultProfit(const MqlTradeCheckResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Profit:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Получаем валюту счёта
   string currency=AccountInfoString(ACCOUNT_CURRENCY);
//--- Получаем количество знаков после запятой
   int dg=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-.*f %s",indent,"",w,header,dg,result.profit,currency);
   /* Пример вывода:
      Profit: 0.00 USD
   */
  }


Маржевые требования

Размер маржи необходимый для требуемой торговой операции.

//+------------------------------------------------------------------+
//| Возвращает в виде строки размер маржи,                           |
//| необходимый для требуемой торговой операции                      |
//+------------------------------------------------------------------+
string MqlTradeCheckResultMargin(const MqlTradeCheckResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Margin:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Получаем валюту счёта
   string currency=AccountInfoString(ACCOUNT_CURRENCY);
//--- Получаем количество знаков после запятой
   int dg=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-.*f %s",indent,"",w,header,dg,result.margin,currency);
   /* Пример вывода:
      Margin: 128.66 USD
   */
  }


Свободная маржа

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

//+------------------------------------------------------------------+
//| Возвращает в виде строки размер свободных собственных средств,   |
//| которые останутся после выполнения требуемой торговой операции   |
//+------------------------------------------------------------------+
string MqlTradeCheckResultMarginFree(const MqlTradeCheckResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Margin free:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Получаем валюту счёта
   string currency=AccountInfoString(ACCOUNT_CURRENCY);
//--- Получаем количество знаков после запятой
   int dg=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-.*f %s",indent,"",w,header,dg,result.margin_free,currency);
   /* Пример вывода:
      Margin free: 9888.14 USD
   */
  }


Уровень маржи

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

//+------------------------------------------------------------------+
//| Возвращает в виде строки уровень маржи, который установится      |
//| после выполнения требуемой торговой операции                     |
//+------------------------------------------------------------------+
string MqlTradeCheckResultMarginLevel(const MqlTradeCheckResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Margin level:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-.2f %%",indent,"",w,header,result.margin_level);
   /* Пример вывода:
      Margin level: 7785.48 %
   */
  }


Комментарий к коду ответа

Комментарий к коду ответа, описание ошибки.

//+------------------------------------------------------------------+
//| Возвращает комментарий к коду ответа, описание ошибки            |
//+------------------------------------------------------------------+
string MqlTradeCheckResultComment(const MqlTradeCheckResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Comment:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-s",indent,"",w,header,result.comment);
   /* Пример вывода:
      Comment: Done
   */
  }


Примеры использования

Функция, выводящая в журнал все поля структуры MqlTradeCheckResult:

//+------------------------------------------------------------------+
//| Выводит в журнал поля структуры MqlTradeCheckResult              |
//| в результате OrderCheck                                          |
//+------------------------------------------------------------------+
void OrderCheckResultPrint(const MqlTradeCheckResult &result,const uint header_width=0,const uint indent=0,bool ext_descr=false)
  {
   Print("OrderCheck result:");
   Print(MqlTradeCheckResultRetcode(result,header_width,indent,ext_descr));
   Print(MqlTradeCheckResultBalance(result,header_width,indent));
   Print(MqlTradeCheckResultEquity(result,header_width,indent));
   Print(MqlTradeCheckResultProfit(result,header_width,indent));
   Print(MqlTradeCheckResultMargin(result,header_width,indent));
   Print(MqlTradeCheckResultMarginFree(result,header_width,indent));
   Print(MqlTradeCheckResultMarginLevel(result,header_width,indent));
   Print(MqlTradeCheckResultComment(result,header_width,indent));
   /* Пример вывода:
      OrderCheck result:
        Retcode:      Undefined (0)
        Balance:      10016.80 USD
        Equity:       10016.80 USD
        Profit:       0.00 USD
        Margin:       128.66 USD
        Margin free:  9888.14 USD
        Margin level: 7785.48 %
        Comment:      Done
   */
  }

После проверки заполненного торгового приказа, и при получении ошибки, можно распечатать в журнал заполненную структуру MqlTradeCheckResult для анализа возникшей ошибки.


Структура MqlTradeResult с ответом сервера на запрос, отправленный функцией OrderSend()

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

struct MqlTradeResult
  {
   uint     retcode;          // Код результата операции
   ulong    deal;             // Тикет сделки, если она совершена
   ulong    order;            // Тикет ордера, если он выставлен
   double   volume;           // Объем сделки, подтверждённый брокером
   double   price;            // Цена в сделке, подтверждённая брокером
   double   bid;              // Текущая рыночная цена предложения (цены реквота)
   double   ask;              // Текущая рыночная цена спроса (цены реквота)
   string   comment;          // Комментарий брокера к операции (по умолчанию заполняется расшифровкой кода возврата торгового сервера)
   uint     request_id;       // Идентификатор запроса, устанавливается терминалом при отправке 
   int      retcode_external; // Код ответа внешней торговой системы
  };

Результат торговой операции возвращается в переменную типа MqlTradeResult, которая передается вторым параметром в функцию OrderSend() для проведения торговых операций.

Для вывода описания полей структуры напишем функции:

Код результата операции

Код возврата торгового сервера
//+------------------------------------------------------------------+
//| Возвращает в виде строки код результата операции                 |
//+------------------------------------------------------------------+
string MqlTradeResultRetcode(const MqlTradeResult &result,const uint header_width=0,const uint indent=0,const bool ext_descr=false)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Retcode:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-s",indent,"",w,header,RetcodeDescription(result.retcode,ext_descr));
   /* Пример вывода:
      Retcode: 10009 DONE (Request completed)
   */
  }


Тикет сделки

Тикет сделки, если она совершена. Сообщается при торговой операции TRADE_ACTION_DEAL.
//+------------------------------------------------------------------+
//| Возвращает в виде строки тикет сделки, если она совершена        |
//+------------------------------------------------------------------+
string MqlTradeResultDeal(const MqlTradeResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Deal:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,result.deal);
   /* Пример вывода:
      Deal: 0
   */
  }


Тикет ордера

Тикет ордера, если он выставлен. Сообщается при торговой операции TRADE_ACTION_PENDING.
//+------------------------------------------------------------------+
//| Возвращает в виде строки тикет ордера, если он выставлен         |
//+------------------------------------------------------------------+
string MqlTradeResultOrder(const MqlTradeResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Order:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,result.order);
   /* Пример вывода:
      Order: 1821552382
   */
  }


Объем сделки

Объем сделки, подтверждённый брокером. Зависит от типа ордера по исполнению.
//+------------------------------------------------------------------+
//| Возвращает в виде строки объем сделки, подтверждённый брокером   |
//+------------------------------------------------------------------+
string MqlTradeResultVolume(const string symbol,const MqlTradeResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Volume:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Получаем количество знаков после запятой в значении лота
   int dg=(int)ceil(fabs(log10(SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP))));
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,result.volume);
   /* Пример вывода:
      Volume: 0.10
   */
  }


Цена в сделке

Цена в сделке, подтверждённая брокером. Зависит от поля deviation в торговом запросе и/или от типа торговой операции.

//+------------------------------------------------------------------+
//| Возвращает в виде строки цену в сделке, подтверждённую брокером  |
//+------------------------------------------------------------------+
string MqlTradeResultPrice(const string symbol,const MqlTradeResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Price:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Получаем количество знаков после запятой
   int dg=(result.price!=0 ? (int)SymbolInfoInteger(symbol,SYMBOL_DIGITS) : 1);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,result.price);
   /* Пример вывода:
      Price: 0.0
   */
  }


Текущая рыночная цена Bid

Текущая рыночная цена предложения (цены реквоты).
//+------------------------------------------------------------------+
//| Возвращает в виде строки текущую рыночную цену предложения (Bid) |
//+------------------------------------------------------------------+
string MqlTradeResultBid(const string symbol,const MqlTradeResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Bid:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Получаем количество знаков после запятой
   int dg=(result.bid!=0 ? (int)SymbolInfoInteger(symbol,SYMBOL_DIGITS) : 1);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,result.bid);
   /* Пример вывода:
      Bid: 0.0
   */
  }


Текущая рыночная цена Ask

Текущая рыночная цена спроса (цены реквоты).
//+------------------------------------------------------------------+
//| Возвращает в виде строки текущую рыночную цену спроса (Ask)      |
//+------------------------------------------------------------------+
string MqlTradeResultAsk(const string symbol,const MqlTradeResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Ask:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Получаем количество знаков после запятой
   int dg=(result.ask!=0 ? (int)SymbolInfoInteger(symbol,SYMBOL_DIGITS) : 1);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,result.ask);
   /* Пример вывода:
      Ask: 0.0
   */
  }

При установке отложенного ордера цены Bid и Ask в структуре остаются не заполненными. Если ордер не был принят из-за реквоты, в полях Bid и Ask можно видеть цены, существующие на момент отказа ордера к постановке.


Комментарий брокера к операции

Комментарий брокера к операции (по умолчанию заполняется расшифровкой кода возврата торгового сервера).
//+------------------------------------------------------------------+
//| Возвращает комментарий брокера к операции                        |
//+------------------------------------------------------------------+
string MqlTradeResultComment(const MqlTradeResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Comment:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-s",indent,"",w,header,result.comment);
   /* Пример вывода:
      Comment: Request executed
   */
  }


Идентификатор запроса

Идентификатор запроса, проставляемый терминалом при отсылке на торговый сервер.
//+------------------------------------------------------------------+
//| Возвращает в виде строки идентификатор запроса                   |
//+------------------------------------------------------------------+
string MqlTradeResultRequestID(const MqlTradeResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Request ID:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-lu",indent,"",w,header,result.request_id);
   /* Пример вывода:
      Request ID: 3768213261
   */
  }

Установка терминалом идентификатора request_id для торгового запроса при его отправке на сервер в первую очередь предназначена для работы с асинхронной функцией OrderSendAsync(). Этот идентификатор позволяет связать выполненное действие (вызов функций OrderSend или OrderSendAsync) с результатом этого действия, передаваемым в обработчике OnTradeTransaction().


Код ответа внешней торговой системы

Код ошибки, которую вернула внешняя торговая система. Проставление и виды этих ошибок зависят от брокера и внешней торговой системы, в которую выводятся торговые операции.
//+------------------------------------------------------------------+
//| Возвращает в виде строки код ответа внешней торговой системы     |
//+------------------------------------------------------------------+
string MqlTradeResultRetcodeExternal(const MqlTradeResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Retcode External:";
   uint w=(header_width==0 ? header.Length()+1 : header_width-1);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%- ld",indent,"",w,header,result.retcode_external);
   /* Пример вывода:
      Retcode External:  0
   */
  }


Примеры использования

Функция, выводящая в журнал все поля структуры результата торгового запроса:

//+------------------------------------------------------------------+
//| Выводит в журнал поля структуры MqlTradeResult                   |
//| в результате торгового запроса                                   |
//+------------------------------------------------------------------+
void TradeResultPrint(const string symbol,const MqlTradeResult &result,const uint header_width=0,const uint indent=0,bool ext_descr=false)
  {
   string symbol_name=(symbol==NULL ? Symbol() : symbol);
   Print("OrderSend result:");
   Print(MqlTradeResultRetcode(result,header_width,indent,ext_descr));
   Print(MqlTradeResultDeal(result,header_width,indent));
   Print(MqlTradeResultOrder(result,header_width,indent));
   Print(MqlTradeResultVolume(symbol_name,result,header_width,indent));
   Print(MqlTradeResultPrice(symbol_name,result,header_width,indent));
   Print(MqlTradeResultBid(symbol_name,result,header_width,indent));
   Print(MqlTradeResultAsk(symbol_name,result,header_width,indent));
   Print(MqlTradeResultComment(result,header_width,indent));
   Print(MqlTradeResultRequestID(result,header_width,indent));
   Print(MqlTradeResultRetcodeExternal(result,header_width,indent));
   /* Пример вывода:
      OrderSend result:
        Retcode:          10009 DONE (Request completed)
        Deal:             0
        Order:            1821671230
        Volume:           0.10
        Price:            0.0
        Bid:              0.0
        Ask:              0.0
        Comment:          Request executed
        Request ID:       3768213265
        Retcode External: 0
   */
  }


Структура MqlTradeTransaction с описанием торговой транзакции

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

  • Отсылка торгового запроса любым MQL5-приложением в клиентском терминале при помощи функций OrderSend и OrderSendAsync и его последующее исполнение;
  • Отсылка торгового запроса через графический интерфейс терминала и его последующее исполнение;
  • Срабатывания отложенных ордеров и стоп-ордеров на сервере;
  • Выполнения операций на стороне торгового сервера.

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

  • обработка торгового запроса;
  • изменение открытых ордеров;
  • изменение истории ордеров;
  • изменение истории сделок;
  • изменение позиций.

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

Для получения торговых транзакций, примененных к счету, в MQL5 предусмотрен специальный обработчик OnTradeTransaction(). В первый параметр этого обработчика передается структура MqlTradeTransaction, описывающая торговые транзакции.

struct MqlTradeTransaction
  {
   ulong                         deal;             // Тикет сделки
   ulong                         order;            // Тикет ордера
   string                        symbol;           // Имя торгового инструмента
   ENUM_TRADE_TRANSACTION_TYPE   type;             // Тип торговой транзакции
   ENUM_ORDER_TYPE               order_type;       // Тип ордера
   ENUM_ORDER_STATE              order_state;      // Состояние ордера
   ENUM_DEAL_TYPE                deal_type;        // Тип сделки
   ENUM_ORDER_TYPE_TIME          time_type;        // Тип ордера по времени действия
   datetime                      time_expiration;  // Срок истечения ордера
   double                        price;            // Цена 
   double                        price_trigger;    // Цена срабатывания стоп-лимитного ордера
   double                        price_sl;         // Уровень Stop Loss
   double                        price_tp;         // Уровень Take Profit
   double                        volume;           // Объем в лотах
   ulong                         position;         // Тикет позиции
   ulong                         position_by;      // Тикет встречной позиции
  };


Для возврата описаний всех полей структуры напишем функции.

Тикет сделки

//+------------------------------------------------------------------+
//| Возвращает в виде строки тикет сделки                            |
//+------------------------------------------------------------------+
string MqlTradeTransactionDeal(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Deal:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,trans.deal);
   /* Пример вывода:
      Deal: 0
   */
  }


Тикет ордера

//+------------------------------------------------------------------+
//| Возвращает в виде строки тикет ордера                            |
//+------------------------------------------------------------------+
string MqlTradeTransactionOrder(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Order:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,trans.order);
   /* Пример вывода:
      Order: 1825990224
   */
  }


Имя торгового инструмента

Имя торгового инструмента, по которому совершена транзакция.

//+------------------------------------------------------------------+
//| Возвращает в виде строки символ ордера                           |
//+------------------------------------------------------------------+
string MqlTradeTransactionSymbol(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Symbol:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-s",indent,"",w,header,trans.symbol);
   /* Пример вывода:
      Symbol: EURUSD
   */
  }


Тип торговой транзакции

Тип торговой транзакции. Значение может быть одним из значений перечисления ENUM_TRADE_TRANSACTION_TYPE.

//+------------------------------------------------------------------+
//| Возвращает в виде строки тип торговой транзакции                 |
//+------------------------------------------------------------------+
string MqlTradeTransactionType(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0,const bool ext_descr=false)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Type:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-s",indent,"",w,header,TradeTransactionTypeDescription(trans.type,ext_descr));
   /* Пример вывода:
      Type: Order delete (Removing an order from the list of the open ones)
   */
  }


Тип ордера

Тип торгового ордера. Значение может быть одним из значений перечисления ENUM_ORDER_TYPE.

//+------------------------------------------------------------------+
//| Возвращает в виде строки тип ордера                              |
//+------------------------------------------------------------------+
string MqlTradeTransactionOrderType(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0,const bool ext_descr=false)
  {
//--- Объявляем переменные для указания принадлежности транзакции
   bool trans_req=false;   // Запрос
   bool trans_order=false; // Ордер
   bool trans_deal=false;  // Сделка
   bool trans_pos=false;   // Позиция
//--- Устанавливаем принадлежность транзакции
   SetTransactionBelong(trans.type,trans_req,trans_order,trans_deal,trans_pos);
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Order type:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-s",indent,"",w,header,(trans_order ? OrderTypeDescription(trans.order_type,ext_descr) : "0"));
   /* Пример вывода:
      Order type: Sell Limit (Sell Limit pending order)
   */
  }

В функции определяется принадлежность торговой транзакции и, если транзакция была проведена с ордером, то возвращается его тип, иначе — '0'.


Состояние ордера

Состояние торгового ордера. Значение может быть одним из значений перечисления ENUM_ORDER_STATE.

//+------------------------------------------------------------------+
//| Возвращает в виде строки состояние ордера                        |
//+------------------------------------------------------------------+
string MqlTradeTransactionOrderState(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0,const bool ext_descr=false)
  {
//--- Объявляем переменные для указания принадлежности транзакции
   bool trans_req=false;   // Запрос
   bool trans_order=false; // Ордер
   bool trans_deal=false;  // Сделка
   bool trans_pos=false;   // Позиция
//--- Устанавливаем принадлежность транзакции
   SetTransactionBelong(trans.type,trans_req,trans_order,trans_deal,trans_pos);
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Order state:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-s",indent,"",w,header,(trans_order ? OrderStateDescription(trans.order_state,ext_descr) : "0"));
   /* Пример вывода:
      Order state: Started (Order checked, but not yet accepted by broker)
   */
  }

В функции определяется принадлежность торговой транзакции и, если транзакция была проведена с ордером, то возвращается его состояние, иначе — '0'.


Тип сделки

Тип сделки. Значение может быть одним из значений перечисления ENUM_DEAL_TYPE.

//+------------------------------------------------------------------+
//| Возвращает в виде строки тип сделки                              |
//+------------------------------------------------------------------+
string MqlTradeTransactionDealType(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0,const bool ext_descr=false)
  {
//--- Объявляем переменные для указания принадлежности транзакции
   bool trans_req=false;   // Запрос
   bool trans_order=false; // Ордер
   bool trans_deal=false;  // Сделка
   bool trans_pos=false;   // Позиция
//--- Устанавливаем принадлежность транзакции
   SetTransactionBelong(trans.type,trans_req,trans_order,trans_deal,trans_pos);
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Deal type:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-s",indent,"",w,header,(trans_deal || trans_pos ? DealTypeDescription(trans.deal_type,ext_descr) : "0"));
   /* Пример вывода:
      Deal type: Buy
   */
  }

В функции определяется принадлежность торговой транзакции и, если транзакция была проведена со сделкой, то возвращается её тип, иначе — '0'.


Тип ордера по времени действия

Тип ордера по истечению. Значение может быть одним из значений ENUM_ORDER_TYPE_TIME.

//+------------------------------------------------------------------+
//| Возвращает в виде строки тип ордера по времени действия          |
//+------------------------------------------------------------------+
string MqlTradeTransactionTimeType(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0,const bool ext_descr=false)
  {
//--- Объявляем переменные для указания принадлежности транзакции
   bool trans_req=false;   // Запрос
   bool trans_order=false; // Ордер
   bool trans_deal=false;  // Сделка
   bool trans_pos=false;   // Позиция
//--- Устанавливаем принадлежность транзакции
   SetTransactionBelong(trans.type,trans_req,trans_order,trans_deal,trans_pos);
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Time type:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-s",indent,"",w,header,(trans_order ? OrderTypeTimeDescription(trans.time_type,ext_descr) : "0"));
   /* Пример вывода:
      Order type time: Time GTC (Good till cancel order)
   */
  }

В функции определяется принадлежность торговой транзакции и, если транзакция была проведена с ордером, то возвращается его тип по времени действия, иначе — '0'.


Срок истечения ордера

Срок истечения отложенного ордера (для ордеров типа ORDER_TIME_SPECIFIED и ORDER_TIME_SPECIFIED_DAY).

//+------------------------------------------------------------------+
//| Возвращает в виде строки срок истечения ордера                   |
//+------------------------------------------------------------------+
string MqlTradeTransactionTimeExpiration(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Time expiration:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Запишем время экспирации в виде строки. Если 0, то впишем 0
   string tm=(trans.time_expiration==0 ? "0" : (string)trans.time_expiration);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-s",indent,"",w,header,tm);
   /* Пример вывода:
      Time expiration: 0
   */
  }

Если время экспирации в поле структуры записано как ноль, то выводим '0', иначе — время экспирации в формате даты. Если не проверять значение поля на ноль, то нулевое значение будет выводиться как дата 01.01.1970 00:00:00, что не очень эстетично выглядит для отсутствующего времени истечения ордера.


Цена

Цена. В зависимости от типа торговой транзакции может быть ценой ордера, сделки или позиции.

//+------------------------------------------------------------------+
//| Возвращает в виде строки цену ордера/сделки/позиции              |
//+------------------------------------------------------------------+
string MqlTradeTransactionPrice(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Price:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Получим Digits символа. Если символ не указан, используем 1
   int dg=(trans.symbol!="" ? (int)SymbolInfoInteger(trans.symbol,SYMBOL_DIGITS) : 1);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,trans.price);
   /* Пример вывода:
      Price: 1.10331
   */
  }


Цена срабатывания стоп-лимитного ордера

Стоп-цена (цена срабатывания) стоп-лимитного ордера (ORDER_TYPE_BUY_STOP_LIMIT и ORDER_TYPE_SELL_STOP_LIMIT).

//+------------------------------------------------------------------+
//| Возвращает в виде строки цену срабатывания стоп-лимитного ордера |
//+------------------------------------------------------------------+
string MqlTradeTransactionPriceTrigger(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Price trigger:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Получим Digits символа. Если символ не указан или стоп-цена отсутствует, используем 1
   int dg=(trans.symbol!="" ? (int)SymbolInfoInteger(trans.symbol,SYMBOL_DIGITS) : 1);
   if(trans.price_trigger==0)
      dg=1;
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,trans.price_trigger);
   /* Пример вывода:
      Price trigger: 0.0
   */
  }

Если цена стоп-лимитного ордера не задана, то выводить будем '0.0', иначе — цену ордера.


Уровень Stop Loss

Цена Stop Loss. В зависимости от типа торговой транзакции может относиться к ордеру, сделке или позиции.

//+------------------------------------------------------------------+
//| Возвращает в виде строки цену Stop Loss                          |
//+------------------------------------------------------------------+
string MqlTradeTransactionPriceSL(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Price SL:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Получим Digits символа. Если символ не указан или цена  Stop Loss отсутствует, используем 1
   int dg=(trans.symbol!="" ? (int)SymbolInfoInteger(trans.symbol,SYMBOL_DIGITS) : 1);
   if(trans.price_sl==0)
      dg=1;
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,trans.price_sl);
   /* Пример вывода:
      Price SL: 0.0
   */
  }

Если цена Stop Loss не задана, то выводить будем '0.0', иначе — цену Stop Loss.


Уровень Take Profit

Цена Take Profit. В зависимости от типа торговой транзакции может относиться к ордеру, сделке или позиции.

//+------------------------------------------------------------------+
//| Возвращает в виде строки цену Take Profit                        |
//+------------------------------------------------------------------+
string MqlTradeTransactionPriceTP(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Price TP:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Получим Digits символа. Если символ не указан или цена  Take Profit отсутствует, используем 1
   int dg=(trans.symbol!="" ? (int)SymbolInfoInteger(trans.symbol,SYMBOL_DIGITS) : 1);
   if(trans.price_tp==0)
      dg=1;
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,trans.price_tp);
   /* Пример вывода:
      Price TP: 0.0
   */
  }

Если цена Take Profit не задана, то выводить будем '0.0', иначе — цену Take Profit.


Объем в лотах

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

//+------------------------------------------------------------------+
//| Возвращает в виде строки объём в лотах                           |
//+------------------------------------------------------------------+
string MqlTradeTransactionVolume(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Volume:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Получаем количество знаков после запятой в значении лота. Если символ не указан, используем 1
   int dg=(trans.symbol!="" ? (int)ceil(fabs(log10(SymbolInfoDouble(trans.symbol,SYMBOL_VOLUME_STEP)))) : 1);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,trans.volume);
   /* Пример вывода:
      Volume: 0.10
   */
  }


Тикет позиции

Тикет позиции, на которую повлияла транзакция.

//+------------------------------------------------------------------+
//| Возвращает в виде строки тикет позиции                           |
//+------------------------------------------------------------------+
string MqlTradeTransactionPosition(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Position:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,trans.position);
   /* Пример вывода:
      Position: 0
   */
  }


Тикет встречной позиции

Тикет встречной позиции. Используется при закрытии позиции встречной — открытой по тому же инструменту, но в противоположном направлении.

//+------------------------------------------------------------------+
//| Возвращает в виде строки тикет встречной позиции                 |
//+------------------------------------------------------------------+
string MqlTradeTransactionPositionBy(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Определяем текст заголовка и ширину поля заголовка
//--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
   string header="Position by:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Возвращаем значение свойства с заголовком с нужной шириной и отступом
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,trans.position_by);
   /* Пример вывода:
      Position by: 0
   */
  }


Примеры использования

Используя представленные выше функции, мы можем вывести в журнал все поля структуры MqlTradeTransaction:

//+------------------------------------------------------------------+
//| Выводит в журнал поля структуры MqlTradeTransaction              |
//+------------------------------------------------------------------+
void MqlTradeTransactionPrint(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0,const bool ext_descr=false)
  {
   Print(MqlTradeTransactionDeal(trans,header_width,indent));
   Print(MqlTradeTransactionOrder(trans,header_width,indent));
   Print(MqlTradeTransactionSymbol(trans,header_width,indent));
   Print(MqlTradeTransactionType(trans,header_width,indent,ext_descr));
   Print(MqlTradeTransactionOrderType(trans,header_width,indent,ext_descr));
   Print(MqlTradeTransactionOrderState(trans,header_width,indent,ext_descr));
   Print(MqlTradeTransactionDealType(trans,header_width,indent,ext_descr));
   Print(MqlTradeTransactionTimeType(trans,header_width,indent,ext_descr));
   Print(MqlTradeTransactionTimeExpiration(trans,header_width,indent));
   Print(MqlTradeTransactionPrice(trans,header_width,indent));
   Print(MqlTradeTransactionPriceTrigger(trans,header_width,indent));
   Print(MqlTradeTransactionPriceSL(trans,header_width,indent));
   Print(MqlTradeTransactionPriceTP(trans,header_width,indent));
   Print(MqlTradeTransactionVolume(trans,header_width,indent));
   Print(MqlTradeTransactionPosition(trans,header_width,indent));
   Print(MqlTradeTransactionPositionBy(trans,header_width,indent));
   /* Пример вывода:
      Deal:             0
      Order:            1829189788
      Symbol:           EURUSD
      Type:             Order add
      Order type:       Buy Limit
      Order state:      Started
      Deal type:        0
      Time type:        Time GTC
      Time expiration:  0
      Price:            1.09861
      Price trigger:    0.0
      Price SL:         0.0
      Price TP:         0.0
      Volume:           0.10
      Position:         0
      Position by:      0
   */
  }

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

Определяющим параметром для анализа поступившей транзакции является ее тип, который передается в поле type. Например, если транзакция является типом TRADE_TRANSACTION_REQUEST (получен результат обработки торгового запроса сервером), то структура имеет только одно заполненное поле type, остальные поля анализировать не нужно. В этом случае можно произвести анализ двух дополнительных параметров request и result, которые передаются в обработчик OnTradeTransaction(), как это показано в примере ниже.

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

Структура MqlTradeTransaction заполняется по-разному в зависимости от типа торговой транзакции (ENUM_TRADE_TRANSACTION_TYPE):

TRADE_TRANSACTION_ORDER_* и TRADE_TRANSACTION_HISTORY_*

Для торговых транзакций, касающихся обработки открытых ордеров (TRADE_TRANSACTION_ORDER_ADD, TRADE_TRANSACTION_ORDER_UPDATE и TRADE_TRANSACTION_ORDER_DELETE) и истории ордеров (TRADE_TRANSACTION_HISTORY_ADD, TRADE_TRANSACTION_HISTORY_UPDATE, TRADE_TRANSACTION_HISTORY_DELETE), в структуре MqlTradeTransaction заполняются следующие поля:

  • order — тикет ордера;
  • symbol — имя финансового инструмента в ордере;
  • type — тип торговой транзакции;
  • order_type — тип ордера;
  • orders_state — текущее состояние ордера;
  • time_type — тип истечения ордера;
  • time_expiration — время истечения ордера (для ордеров с типом истечения ORDER_TIME_SPECIFIED и ORDER_TIME_SPECIFIED_DAY);
  • price — цена в ордере, указанная клиентом;
  • price_trigger — стоп-цена срабатывания стоп-лимитного ордера (только для ORDER_TYPE_BUY_STOP_LIMIT и ORDER_TYPE_SELL_STOP_LIMIT);
  • price_sl — цена Stop Loss ордера (заполняется, если указана в ордере);
  • price_tp — цена Take Profit ордера (заполняется, если указана в ордере);
  • volume — текущий объем ордера (не исполненный). Изначальный объем ордера можно узнать из истории ордеров при помощи функций HistoryOrders*.
  • position — тикет позиции, открытой, измененной или закрытой в результате исполнения ордера. Заполняется только для рыночных ордеров. Не заполняется для TRADE_TRANSACTION_ORDER_ADD.
  • position_by — тикет встречной позиции. Заполняется только для ордеров на закрытие позиции встречной (close by).

TRADE_TRANSACTION_DEAL_*

Для торговых транзакций, касающихся обработки сделок (TRADE_TRANSACTION_DEAL_ADD, TRADE_TRANSACTION_DEAL_UPDATE и TRADE_TRANSACTION_DEAL_DELETE), в структуре MqlTradeTransaction заполняются следующие поля:

  • deal — тикет сделки;
  • order — тикет ордера, на основе которого совершена сделка;
  • symbol — имя финансового инструмента в сделке;
  • type — тип торговой транзакции;
  • deal_type — тип сделки;
  • price — цена, по которой совершена сделка;
  • price_sl — цена Stop Loss (заполняется, если указана в ордере, на основе которого совершена сделка);
  • price_tp — цена Take Profit (заполняется, если указана в ордере, на основе которого совершена сделка);
  • volume — объем сделки в лотах.
  • position — тикет позиции, открытой, измененной или закрытой в результате исполнения сделки.
  • position_by — тикет встречной позиции. Заполняется только для сделок на закрытие позиции встречной (out by).

TRADE_TRANSACTION_POSITION

Для торговых транзакций, касающихся изменений позиций, не связанных с исполнением сделок (TRADE_TRANSACTION_POSITION), в структуре MqlTradeTransaction заполняются следующие поля:

  • symbol — имя финансового инструмента позиции;
  • type — тип торговой транзакции;
  • deal_type — тип позиции (DEAL_TYPE_BUY или DEAL_TYPE_SELL);
  • price — средневзвешенная цена открытия позиции;
  • price_sl — цена Stop Loss;
  • price_tp — цена Take Profit;
  • volume — объем позиции в лотах, если он был изменен.
  • position — тикет позиции.

Изменение позиции (добавление, изменение или ликвидация) в результате совершения сделки не влечет за собой появление транзакции TRADE_TRANSACTION_POSITION.

TRADE_TRANSACTION_REQUEST

Для торговых транзакций, описывающих факт, что торговый запрос обработан сервером, и результат его обработки получен (TRADE_TRANSACTION_REQUEST), в структуре MqlTradeTransaction заполняется только одно поле:

  • type — тип торговой транзакции;
Для транзакций данного типа необходимо анализировать только одно поле — type (тип торговой транзакции). Для получения дополнительной информации необходимо анализировать второй и третий параметры функции OnTradeTransaction (request и result).

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

//+------------------------------------------------------------------+
//| Информер торговых транзакций                                     |
//+------------------------------------------------------------------+
void TradeTransactionInformer(const MqlTradeTransaction &trans,const MqlTradeRequest& request,const MqlTradeResult& result,
                              const uint header_width=0,const uint indent=0,const bool ext_descr=false)
  {
//--- Объявляем переменные для указания принадлежности транзакции
   bool trans_req=false;   // Запрос
   bool trans_order=false; // Ордер
   bool trans_deal=false;  // Сделка
   bool trans_pos=false;   // Позиция
//--- Устанавливаем принадлежность транзакции
   SetTransactionBelong(trans.type,trans_req,trans_order,trans_deal,trans_pos);
//--- В зависимости от принадлежности транзакции выводим описания соответствующих полей структуры
   //--- Торговый запрос
   if(trans_req)
     {
      //--- Сообщаем тип транзакции "торговый запрос" и указываем, что нужно анализировать поля структуры торгового запроса и ответа сервера
      PrintFormat("Transaction %s\n%*sThe second and third parameters of OnTradeTransaction function (request and result) must be analyzed for additional data:",
         MqlTradeTransactionType(trans,0,0,true),indent,"");
      //--- Выводим в журнал описание торгового запроса и результата этого запроса, полученного от сервера
      TradeRequestPrint(request,header_width,indent,ext_descr);
      TradeResultPrint(trans.symbol,result,header_width,indent,ext_descr);
     }
   //--- Иначе, если ордер/сделка/позиция
   else
     {
      //--- Выводим в журнал тип транзакции
      PrintFormat("Transaction %s",MqlTradeTransactionType(trans,0,0,true));
      //--- Ордер
      if(trans_order)
        {
         Print(MqlTradeTransactionOrder(trans,header_width,indent));
         Print(MqlTradeTransactionSymbol(trans,header_width,indent));
         Print(MqlTradeTransactionOrderType(trans,header_width,indent,ext_descr));
         Print(MqlTradeTransactionOrderState(trans,header_width,indent,ext_descr));
         Print(MqlTradeTransactionTimeType(trans,header_width,indent,ext_descr));
         if(trans.time_type==ORDER_TIME_SPECIFIED || trans.time_type==ORDER_TIME_SPECIFIED_DAY)
            Print(MqlTradeTransactionTimeExpiration(trans,header_width,indent));
         Print(MqlTradeTransactionPrice(trans,header_width,indent));
         if(trans.order_type==ORDER_TYPE_BUY_STOP_LIMIT || trans.order_type==ORDER_TYPE_SELL_STOP_LIMIT)
            Print(MqlTradeTransactionPriceTrigger(trans,header_width,indent));
         Print(MqlTradeTransactionPriceSL(trans,header_width,indent));
         Print(MqlTradeTransactionPriceTP(trans,header_width,indent));
         Print(MqlTradeTransactionVolume(trans,header_width,indent));
         if(trans.type!=TRADE_TRANSACTION_ORDER_ADD && (trans.order_type==ORDER_TYPE_BUY || trans.order_type==ORDER_TYPE_SELL))
            Print(MqlTradeTransactionPosition(trans,header_width,indent));
         if(trans.order_type==ORDER_TYPE_CLOSE_BY)
            Print(MqlTradeTransactionPositionBy(trans,header_width,indent));
        }
      //--- Сделка
      if(trans_deal)
        {
         Print(MqlTradeTransactionDeal(trans,header_width,indent));
         Print(MqlTradeTransactionOrder(trans,header_width,indent));
         Print(MqlTradeTransactionSymbol(trans,header_width,indent));
         Print(MqlTradeTransactionDealType(trans,header_width,indent,ext_descr));
         Print(MqlTradeTransactionPrice(trans,header_width,indent));
         Print(MqlTradeTransactionPriceSL(trans,header_width,indent));
         Print(MqlTradeTransactionPriceTP(trans,header_width,indent));
         Print(MqlTradeTransactionVolume(trans,header_width,indent));
         Print(MqlTradeTransactionPosition(trans,header_width,indent));
        }
      //--- Позиция
      if(trans_pos)
        {
         Print(MqlTradeTransactionSymbol(trans,header_width,indent));
         Print(MqlTradeTransactionDealType(trans,header_width,indent,ext_descr));
         Print(MqlTradeTransactionPrice(trans,header_width,indent));
         Print(MqlTradeTransactionPriceSL(trans,header_width,indent));
         Print(MqlTradeTransactionPriceTP(trans,header_width,indent));
         Print(MqlTradeTransactionVolume(trans,header_width,indent));
         Print(MqlTradeTransactionPosition(trans,header_width,indent));
        }
     }
   /* Пример вывода при установке ордера Sell Limit:
      Transaction Type: Order add (Adding a new open order)
        Order: 1833072954
        Symbol: EURUSD
        Order type: Sell Limit (Sell Limit pending order)
        Order state: Started (Order checked, but not yet accepted by broker)
        Time type: Time GTC (Good till cancel order)
        Price: 1.10516
        Price SL: 0.0
        Price TP: 0.0
        Volume: 0.10
      Transaction Type: Order update (Updating an open order)
        Order: 1833072954
        Symbol: EURUSD
        Order type: Sell Limit (Sell Limit pending order)
        Order state: Placed (Order accepted)
        Time type: Time GTC (Good till cancel order)
        Price: 1.10516
        Price SL: 0.0
        Price TP: 0.0
        Volume: 0.10
      Transaction Type: Request (The trade request has been processed by a server and processing result has been received)
        The second and third parameters of OnTradeTransaction function (request and result) must be analyzed for additional data:
      Request Pending (Place a trade order for the execution under specified conditions (pending order)):
        Symbol: EURUSD
        Volume: 0.10
        Price: 1.10516
        SL: 0.0
        TP: 0.0
        Type: Sell Limit (Sell Limit pending order)
        Type filling: Return (In case of partial filling, an order with remaining volume is not canceled but processed further)
        Type time: Time GTC (Good till cancel order)
        Expiration: 0
        Magic: 1024
        Comment: TestMqlTradeTransaction
      OrderSend result:
        Retcode: 10009 DONE (Request completed)
        Deal: 0
        Order: 1833072954
        Volume: 0.10
        Price: 0.0
        Bid: 0.0
        Ask: 0.0
        Comment: 
        Request ID: 3768213464
        Retcode External:  0
      //---
      Здесь при установке отложенного ордера Buy Limit мы порлучили три транзакции:
         1. Запрос - запрос на установку отложенного ордера был принят сервером и был получен ответ. 
            Для утечнения информации необходимо анализировать поля структуры торгового запроса MqlTradeRequest 
            и ответа сервера MqlTradeResult – request и result соответственно.
         2. Добавление нового отложенного ордера с тикетом #1829788294. Его состояние - Started.
         3. Изменение открытого ордера с тикетом #1829788294. Его состояние сменилось со Started на Placed.
      Очерёдность транзакций не соблюдена, но об этом явно указано в справке по обработчику OnTradeTransaction: 
      https://www.mql5.com/ru/docs/event_handlers/ontradetransaction.
   */
  }

Советник-информер торговых транзакций

Чтобы проверить работу рассмотренных выше функций, напишем советник, отслеживающий все торговые транзакции, ответы сервера, и выводящий в журнал описания приходящих торговых транзакций. Сделаем его так, чтобы можно было устанавливать отложенные ордера (BuyStop, SellStop, BuyLimit и SellLimit) и открывать позиции (Buy, Sell) при нажатии выбранных в настройках клавишах. По умолчанию для управления торговлей будут назначены такие клавиши:

Тип ордера
Сочетания клавиш для открытия/установки
Сочетания клавиш для закрытия/удаления
 Buy
 B
 X
 Sell
 S
 X
 Buy Stop
 Shift+B
 Shift+X, Ctrl+Shift+X
 Buy Limit
 Ctrl+Shift+B
 Shift+X, Ctrl+Shift+X
 Sell Stop
 Shift+S
 Shift+X, Ctrl+Shift+X
 Sell Limit
 Ctrl+Shift+S
 Shift+X, Ctrl+Shift+X

Клавиши можно назначать в любом регистре в настройках, советник их переведёт в верхний регистр автоматически. Задать можно будет три клавиши — для покупок, для продаж и для закрытия позиций/удаления ордеров. Управляющие клавиши Ctrl и Shift для изменения типа отложенных ордеров в запросе назначены по умолчанию, и не изменяются. При нажатии кнопки 'B' откроется позиция Buy, при удержании Shift и нажатии кнопки 'B' выставится отложенный ордер Buy Stop, при одновременном удержании Ctrl и Shift и нажатии кнопки 'B' выставится отложенный ордер Buy Limit. То же самое относится и к продажам — простое нажатие 'S' откроет позицию Sell, а удержание управляющих клавиш приведёт к выставлению Sell Stop и Sell Limit. Закрытие всех открытых позиций осуществляется нажатием кнопки 'X', а удержание Shift или Ctrl+Shift (не имеет значения) и нажатия 'X' приведёт к удалению всех выставленных отложенных ордеров.

//+------------------------------------------------------------------+
//|                                      TestMqlTradeTransaction.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//--- input parameters
input double   InpLots        =  0.1;     /* Lots                       */ // Объём в запросе
input int      InpMagic       =  1024;    /* Magic number               */ // Идентификатор эксперта
input int      InpDistance    =  300;     /* Orders placement distance  */ // Дистанция установки отложенных ордеров
input uint     InpDeviation   =  5;       /* Price deviation            */ // Допустимое отклонение от цены в запросе
input string   InpKeyBuy      =  "B";     /* Key to open Buy            */ // Клавиша для открытия позиции Buy  (с Shift - Stop, с Ctrl+Shift - Limit)
input string   InpKeySell     =  "S";     /* Key to open Sell           */ // Клавиша для открытия позиции Sell (с Shift - Stop, с Ctrl+Shift - Limit)
input string   InpKeyClose    =  "X";     /* Key to close/delete        */ // Клавиша для закрытия позиции (без управляющих клавиш) или удаления ордера (с Shift или Shift+Ctrl)
//--- Global variables
ushort         key_buy;                   // Клавиша для отправки приказа на покупку
ushort         key_sell;                  // Клавиша для отправки приказа на продажу
ushort         key_close;                 // Клавиша для закрытия или удаления
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Преобразуем в верхний регистр текст, назначенный на Buy и получаем код первого символа
   string tmp=InpKeyBuy;
   tmp.Upper();
   key_buy=StringGetCharacter(tmp,0);
//--- Преобразуем в верхний регистр текст, назначенный на Sell и получаем код первого символа
   tmp=InpKeySell;
   tmp.Upper();
   key_sell=StringGetCharacter(tmp,0);
//--- Преобразуем в верхний регистр текст, назначенный на Close и получаем код первого символа
   tmp=InpKeyClose;
   tmp.Upper();
   key_close=StringGetCharacter(tmp,0);

//--- Если клавиши, назначенные на Buy и Sell совпадают - сообщаем об этом и уходим с ошибкой
   if(key_sell==key_buy)
     {
      PrintFormat("The key assigned to Sell ('%c') is the same as the key assigned to Buy ('%c')",key_sell,key_buy);
      return INIT_PARAMETERS_INCORRECT;
     }
//--- Если клавиши, назначенные на Close и Buy совпадают - сообщаем об этом и уходим с ошибкой
   if(key_close==key_buy)
     {
      PrintFormat("The key assigned to Close ('%c') is the same as the key assigned to Buy ('%c')",key_close,key_buy);
      return INIT_PARAMETERS_INCORRECT;
     }
//--- Если клавиши, назначенные на Close и Sell совпадают - сообщаем об этом и уходим с ошибкой
   if(key_close==key_sell)
     {
      PrintFormat("The key assigned to Close ('%c') is the same as the key assigned to Sell ('%c')",key_close,key_sell);
      return INIT_PARAMETERS_INCORRECT;
     }
//--- Успешная инициализация. Выведем в лог назначенные клавиши и возвратим успешное выполнение
   string kb="Key assigned to Buy: ";
   string ks="Key assigned to Sell: ";
   string kc="Key assigned to Close: ";
   PrintFormat("%-23s%c (key code %lu)\n%-23s%c (key code %lu)\n%-23s%c (key code %lu)",kb,key_buy,key_buy,ks,key_sell,key_sell,kc,key_close,key_close);
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Если нажата клавиша на клавиатуре
   if(id==CHARTEVENT_KEYDOWN)
     {
      //--- Если не удерживаются ни Ctrl, ни Shift
      if(!IsCtrlKeyPressed() && !IsShiftKeyPressed())
        {
         //--- Если кнопка, назначенная на позицию Buy - открываем позицию Buy
         if(lparam==key_buy)
            OpenBuy(NULL,InpLots,InpMagic,InpDeviation,"TestMqlTradeTransaction");
         //--- Если кнопка, назначенная на позицию Sell - открываем позицию Sell
         if(lparam==key_sell)
            OpenSell(NULL,InpLots,InpMagic,InpDeviation,"TestMqlTradeTransaction");
         //--- Если кнопка, назначенная на закрытие позиций - закрываем все позиции
         if(lparam==key_close)
            ClosePositionsAll(Symbol());
        }
      //--- Если удерживается только Shift
      if(IsShiftKeyPressed() && !IsCtrlKeyPressed())
        {
         //--- Если кнопка, назначенная на ордер Buy - открываем ордер Buy Stop
         if(lparam==key_buy)
            SetBuyStop(NULL,InpLots,InpMagic,InpDistance,"TestMqlTradeTransaction");
         //--- Если кнопка, назначенная на ордер Sell - открываем ордер Sell Stop
         if(lparam==key_sell)
            SetSellSellStop(NULL,InpLots,InpMagic,InpDistance,"TestMqlTradeTransaction");
         //--- Если кнопка, назначенная на удаление ордеров - удаляем все ордеры
         if(lparam==key_close)
            DeleteOrdersAll(NULL);
        }
         //--- Если удерживается Shift вместе с Ctrl
      if(IsShiftKeyPressed() && IsCtrlKeyPressed())
        {
         //--- Если кнопка, назначенная на ордер Buy - открываем ордер Buy Limit
         if(lparam==key_buy)
            SetBuyLimit(NULL,InpLots,InpMagic,InpDistance,"TestMqlTradeTransaction");
         //--- Если кнопка, назначенная на ордер Sell - открываем ордер Sell Limit
         if(lparam==key_sell)
            SetSellLimit(NULL,InpLots,InpMagic,InpDistance,"TestMqlTradeTransaction");
         //--- Если кнопка, назначенная на удаление ордеров - удаляем все ордеры
         if(lparam==key_close)
            DeleteOrdersAll(Symbol());
        }
     }
  }
//+------------------------------------------------------------------+
//| TradeTransaction function                                        |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
                        const MqlTradeRequest& request,
                        const MqlTradeResult& result)
  {
//--- Пишем в журнал все приходящие торговые транзакции
   TradeTransactionInformer(trans,request,result,18,2,true);
  }

Выставление ордеров и открытие позиций реализовано в обработчике OnChartEvent() советника. В обработчике OnTradeTransaction() вызывается функция TradeTransactionInformer(), рассмотренная выше, которая и будет каждую приходящую транзакцию выводить в журнал. Советник использует в своей работе все рассмотренные в статье функции, поэтому они должны быть вписаны в файл советника для безошибочной его компиляции.

При установке ордера BuyLimit в журнал будут выведены такие записи о всех обработанных транзакциях:

Transaction Type: Order add (Adding a new open order)
  Order:            1838106218
  Symbol:           EURUSD
  Order type:       Buy Limit (Buy Limit pending order)
  Order state:      Started (Order checked, but not yet accepted by broker)
  Time type:        Time GTC (Good till cancel order)
  Price:            1.09449
  Price SL:         0.0
  Price TP:         0.0
  Volume:           0.10
Transaction Type: Order update (Updating an open order)
  Order:            1838106218
  Symbol:           EURUSD
  Order type:       Buy Limit (Buy Limit pending order)
  Order state:      Placed (Order accepted)
  Time type:        Time GTC (Good till cancel order)
  Price:            1.09449
  Price SL:         0.0
  Price TP:         0.0
  Volume:           0.10
Transaction Type: Request (The trade request has been processed by a server and processing result has been received)
  The second and third parameters of OnTradeTransaction function (request and result) must be analyzed for additional data:
Request Pending (Place a trade order for the execution under specified conditions (pending order)):
  Symbol:           EURUSD
  Volume:           0.10
  Price:            1.09449
  SL:               0.0
  TP:               0.0
  Type:             Buy Limit (Buy Limit pending order)
  Type filling:     Return (In case of partial filling, an order with remaining volume is not canceled but processed further)
  Type time:        Time GTC (Good till cancel order)
  Expiration:       0
  Magic:            1024
  Comment:          TestMqlTradeTransaction
OrderSend result:
  Retcode:          10009 DONE (Request completed)
  Deal:             0
  Order:            1838106218
  Volume:           0.10
  Price:            0.0
  Bid:              0.0
  Ask:              0.0
  Comment:          
  Request ID:       930808478
  Retcode External: 0

При последующем удалении выставленного ордера, получим такие записи в журнале терминала:

Transaction Type: Order update (Updating an open order)
  Order:            1838106218
  Symbol:           EURUSD
  Order type:       Buy Limit (Buy Limit pending order)
  Order state:      Request cancel (Order is being deleted (deleting from the trading system))
  Time type:        Time GTC (Good till cancel order)
  Price:            1.09449
  Price SL:         0.0
  Price TP:         0.0
  Volume:           0.10
Transaction Type: Order delete (Removing an order from the list of the open ones)
  Order:            1838106218
  Symbol:           EURUSD
  Order type:       Buy Limit (Buy Limit pending order)
  Order state:      Canceled (Order canceled by client)
  Time type:        Time GTC (Good till cancel order)
  Price:            1.09449
  Price SL:         0.0
  Price TP:         0.0
  Volume:           0.10
Transaction Type: History add (Adding an order to the history as a result of execution or cancellation)
  Order:            1838106218
  Symbol:           EURUSD
  Order type:       Buy Limit (Buy Limit pending order)
  Order state:      Canceled (Order canceled by client)
  Time type:        Time GTC (Good till cancel order)
  Price:            1.09449
  Price SL:         0.0
  Price TP:         0.0
  Volume:           0.10
Transaction Type: Request (The trade request has been processed by a server and processing result has been received)
  The second and third parameters of OnTradeTransaction function (request and result) must be analyzed for additional data:
Request Remove (Delete the pending order placed previously):
  Order:            1838106218
OrderSend result:
  Retcode:          10009 DONE (Request completed)
  Deal:             0
  Order:            1838106218
  Volume:           0.00
  Price:            0.0
  Bid:              0.0
  Ask:              0.0
  Comment:          
  Request ID:       930808479
  Retcode External: 0


Заключение

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

Все предложенные функции можно использовать "как есть", а можно доработать под своё видение их применения и использования.

Файл советника со всеми рассмотренными в статье функциями имеется в приложении. Его можно скачать и протестировать всё самостоятельно.

Прикрепленные файлы |
Последние комментарии | Перейти к обсуждению на форуме трейдеров (82)
MrBrooklin
MrBrooklin | 23 окт. 2023 в 09:26
Alexey Viktorov #:

Проблема в том, что PositionSelect(_Symbol) выбирает не обязательно последнюю позицию. Следовательно, если в OnTradeTransaction() ты не получил тикет позиции, то рискуешь принять решение на основании не тех данных.

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

С уважением, Владимир.

Alexey Viktorov
Alexey Viktorov | 23 окт. 2023 в 10:33
MrBrooklin #:

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

С уважением, Владимир.

Я не говорил чтобы отказаться. Но пользы от такого её использования ровно ноль.

MrBrooklin
MrBrooklin | 23 окт. 2023 в 10:39
Alexey Viktorov #:
Удали функцию OnTradeTransaсtion() и код будет работать точно так-же

Удалить функцию, в моём понимании - это всё равно, что отказаться от её использования. Да, ладно, не важно кто и как сказал, главное разобраться. :) 

С уважением, Владимир.

MrBrooklin
MrBrooklin | 24 окт. 2023 в 08:32

Более пристальное наблюдение за работой 2-х советников, у которых разные алгоритмы поиска сигнала для определения направления торговли, но один и тот же алгоритм добавления позиций, ПОКАЗАЛО!!!

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

Самому аж стало интересно, как такое может быть - то имеется в истории информация об уже открытой позиции, то нет истории. Ладно, время покажет.

С уважением, Владимир.

MrBrooklin
MrBrooklin | 27 окт. 2023 в 10:51
Denis Kirichenko #:
Владимир, рекомендую плотно изучить материал в статье. Тогда многие вопросы самоответятся ))

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

С уважением, Владимир.

Простая торговая стратегия возврата к среднему Простая торговая стратегия возврата к среднему
Возврат к среднему - это метод контртрендовой торговли, при котором трейдер ожидает, что цена вернется к некоторой форме равновесия, которое обычно измеряется средним значением или другим статистическим показателем усредненной тенденции.
Нейросети — это просто (Часть 52): Исследование с оптимизмом и коррекцией распределения Нейросети — это просто (Часть 52): Исследование с оптимизмом и коррекцией распределения
По мере обучения модели на базе буфера воспроизведения опыта текущая политика Актера все больше отдаляется от сохраненных примеров, что снижает эффективность обучения модели в целом. В данной статье мы рассмотрим алгоритм повышения эффективности использования образцов в алгоритмах обучения с подкреплением.
Нейросети — это просто (Часть 53): Декомпозиция вознаграждения Нейросети — это просто (Часть 53): Декомпозиция вознаграждения
Мы уже не раз говорили о важности правильного подбора функции вознаграждения, которую используем для стимулирования желательного поведения Агента, добавляя вознаграждения или штрафы за отдельные действия. Но остается открытым вопрос о дешифровке наших сигналов Агентом. В данной статье мы поговорим о декомпозиции вознаграждения в части передачи отдельных сигналов обучаемому Агенту.
Прогнозирование с помощью моделей ARIMA в MQL5 Прогнозирование с помощью моделей ARIMA в MQL5
В этой статье мы продолжаем разработку класса CArima для построения моделей ARIMA, добавляя интуитивно понятные методы прогнозирования.