Ордер -> сделка -> позиция. Какой ордер сработал

Dmitry Fedoseev  
Очень интересно! Ждем.
Alexey Busygin  
Karputov Vladimir:

Будут рассмотрены несколько ситуаций.

  1. Самая простая ситуация - пользователь выставил отложенные ордера. И через пол-часа хочет проверить какой именно ордер сработал. Причём проверка будет именно через историю ордеров.
  2.  -

И что же все таки дальше? Будем ждать понедельника или когда ордер сработает?
[Удален]  

   1 .2 - это продолжение предыдущий незаконченной темы? 

где: 

1. В момент открытия нового бара на High предыдущего бара размещается ордер BuyStop, а на Low предыдущего бара размещается ордер SellStop:

теперь продолжаем: 

2.   Через пол-часа проеряем какой именно ордер сработал. Причём проверка будет именно через историю ордеров.

3. - 

Vladimir Karputov  
О, уже понаписали :) . Я спать хотел, сейчас всё будет...
Vladimir Karputov  
  1. Самая простая ситуация - пользователь выставил отложенные ордера. И через пол-часа хочет проверить какой именно ордер сработал. Причём проверка будет именно через историю ордеров.

Обращаю внимание, что проверка идёт ИСТОРИИ ОРДЕРОВ - то есть, если отложенный ордер был выставлен, но ещё не сработал, то такой ордер в истории не появится. А вот когда отложенный ордер сработает, тогда он и появится истории ордеров.

Сам советник (просто выставляет два противоположных ордера и через определённое время проверяет историю ордеров. Если в истории ордеров есть ордера, то выводится такая информация:

//--- подготовим и выведм информацию об ордере 
         printf("#ticket %d %s %G %s at %G was set up at %s => done at %s, order magic=%d, pos ID=%d",
                ticket,                  // тикет ордера 
                type,                    // тип 
                initial_volume,          // выставленный объем 
                symbol,                  // символ, по которому выставили 
                open_price,              // указанная цена открытия 
                TimeToString(time_setup),// время установки ордера 
                TimeToString(time_done), // время исполнения илм удаления 
                order_magic,             // магик
                positionID               // ID позиции, в которую влилась сделка по ордеру 
                );

Настройки тестирования (MetaEditor -> Настройки):

Настройки тестирования 

Рис. 1. Настройки тестирования 

Тестирование проводить на истории (Ctrl + F5).


Советник стартует:

Старт советника 

Рис. 2. Старт советника 

А вот принты после срабатывания первого ордера:

2016.07.17 10:33:20.684 2016.01.04 10:30:00   #ticket 3 sell limit 0.01 EURUSD at 1.09212 was set up at 2016.01.04 00:00 => done at 2016.01.04 10:01, order magic=4134862, pos ID=3

...

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

Оба ордера сработали 

Рис. 3. Оба ордера сработали 

2016.07.17 10:36:56.861 2016.01.04 17:30:00   #ticket 3 sell limit 0.01 EURUSD at 1.09212 was set up at 2016.01.04 00:00 => done at 2016.01.04 10:01, order magic=4134862, pos ID=3
2016.07.17 10:36:56.861 2016.01.04 17:30:00   #ticket 2 buy limit 0.01 EURUSD at 1.08196 was set up at 2016.01.04 00:00 => done at 2016.01.04 17:13, order magic=4134862, pos ID=3

 

Итак из истории ордеров можно получить тикет ордера, магик советника - который разместил этот ордер, идентификатор позиции - в которой участвовал этот ордер.

 

Листинг советника:

//+------------------------------------------------------------------+
//|                                               Pending Orders.mq5 |
//|                              Copyright © 2016, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2016, Vladimir Karputov"
#property link      "http://wmua.ru/slesar/"
#property version     "1.000"
#property description "Размещение двух отложенных ордеров и периодическая"
#property description "распринтовка истории ордеров и свойств ордеров:"
#property description "тикет ордера, тип ордера, магик эксперта"

#define MACD_MAGIC 4134862
//---
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
//---
input double   InpLots=0.01;           // Лоты
input int      InpIndent=50;           // Отступ от текущей цены
//---
int            ExtTimeOut=1800;        // Время (секунды) таймера
double         m_adjusted_point;       // Значение точки с поправкой на 3 или 5 знака
double         m_indent;               // отступ в ценах инструмента
CTrade         m_trade;                // CTrade обьект
CSymbolInfo    m_symbol;               // CSymbolInfo обьект
bool           ExtOrdersPlaced=false;  // false -> ордера ещё не размещались
datetime       history_start;          // переменная для использования в вызове HistorySelect() 
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create timer
   EventSetTimer(ExtTimeOut);
//--- инициализия общей информации
   m_symbol.Name(Symbol());                  // символ
   m_trade.SetExpertMagicNumber(MACD_MAGIC); // магик
   m_trade.SetMarginMode();
//--- настройка для 3 или 5 разрядов
   int digits_adjust=1;
   if(m_symbol.Digits()==3 || m_symbol.Digits()==5)
      digits_adjust=10;
   m_adjusted_point=m_symbol.Point()*digits_adjust;
//---
   m_indent=InpIndent*m_adjusted_point;
//--- запомним время запуска эксперта для получения торговой истории 
   history_start=TimeCurrent()-60;
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- destroy timer
   EventKillTimer();

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   if(!ExtOrdersPlaced)
     {
      if(!m_symbol.RefreshRates())
         return;
      m_trade.BuyLimit(InpLots,m_symbol.Bid()-m_indent,m_symbol.Name(),0,0,0,0,"buy limit");
      m_trade.SellLimit(InpLots,m_symbol.Ask()+m_indent,m_symbol.Name(),0,0,0,0,"sell limit");
      ExtOrdersPlaced=true;
     }
  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- запросим торговую историю 
   ResetLastError();
   bool update=HistorySelect(history_start,TimeCurrent());
   if(!update)
     {
      Print("Ошибка HistorySelect с ",TimeToString(history_start,TIME_DATE|TIME_MINUTES|TIME_SECONDS),
            " по ",TimeToString(TimeCurrent(),TIME_DATE|TIME_MINUTES|TIME_SECONDS));
      return;
     }
//--- переменные для получения значений из свойств ордера 
   ulong    ticket;
   double   open_price;
   double   initial_volume;
   datetime time_setup;
   datetime time_done;
   string   symbol;
   string   type;
   long     order_magic;
   long     positionID;
//--- количество текущих отложенных ордеров 
   uint     total=HistoryOrdersTotal();
//--- пройдем в цикле по всем ордерам 
   for(uint i=0;i<total;i++)
     {
      //--- получим тикет ордера по его позиции в списке 
      if((ticket=HistoryOrderGetTicket(i))>0)
        {
         //--- получим свойства ордера 
         open_price=       HistoryOrderGetDouble(ticket,ORDER_PRICE_OPEN);
         time_setup=       (datetime)HistoryOrderGetInteger(ticket,ORDER_TIME_SETUP);
         time_done=(datetime)HistoryOrderGetInteger(ticket,ORDER_TIME_DONE);
         symbol=HistoryOrderGetString(ticket,ORDER_SYMBOL);
         order_magic=      HistoryOrderGetInteger(ticket,ORDER_MAGIC);
         positionID =      HistoryOrderGetInteger(ticket,ORDER_POSITION_ID);
         initial_volume=HistoryOrderGetDouble(ticket,ORDER_VOLUME_INITIAL);
         type=GetOrderType(HistoryOrderGetInteger(ticket,ORDER_TYPE));
         //--- подготовим и выведм информацию об ордере 
         printf("#ticket %d %s %G %s at %G was set up at %s => done at %s, order magic=%d, pos ID=%d",
                ticket,                  // тикет ордера 
                type,                    // тип 
                initial_volume,          // выставленный объем 
                symbol,                  // символ, по которому выставили 
                open_price,              // указанная цена открытия 
                TimeToString(time_setup),// время установки ордера 
                TimeToString(time_done), // время исполнения илм удаления 
                order_magic,             // магик
                positionID               // ID позиции, в которую влилась сделка по ордеру 
                );
        }
     }
//--- 
  }
//+------------------------------------------------------------------+ 
//| Возвращает строковое наименование типа ордера                    | 
//+------------------------------------------------------------------+ 
string GetOrderType(long type)
  {
   string str_type="unknown operation";
   switch((int)type)
     {
      case (ORDER_TYPE_BUY):            return("buy");
      case (ORDER_TYPE_SELL):           return("sell");
      case (ORDER_TYPE_BUY_LIMIT):      return("buy limit");
      case (ORDER_TYPE_SELL_LIMIT):     return("sell limit");
      case (ORDER_TYPE_BUY_STOP):       return("buy stop");
      case (ORDER_TYPE_SELL_STOP):      return("sell stop");
      case (ORDER_TYPE_BUY_STOP_LIMIT): return("buy stop limit");
      case (ORDER_TYPE_SELL_STOP_LIMIT):return("sell stop limit");
     }
   return(str_type);
  }
//+------------------------------------------------------------------+
//| TradeTransaction function                                        |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction &trans,
                        const MqlTradeRequest &request,
                        const MqlTradeResult &result)
  {
//---

  }
//+------------------------------------------------------------------+

 

Файлы:
Aleksandr Prishenko  
Alexey Busygin:
И что же все таки дальше? Будем ждать понедельника или когда ордер сработает?

Насчет понедельника.

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

В этом случае надо использовать для ордеров ORDER_POSITION_ID ,а для открытых позиций POSITION_IDENTIFIER который не изменяется в течение всей ее жизни.

Alexey Busygin  
Aleksandr Prishenko:

Насчет понедельника.

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

В этом случае надо использовать для ордеров ORDER_POSITION_ID ,а для открытых позиций POSITION_IDENTIFIER который не изменяется в течение всей ее жизни.

Хорошее замечание, надо это запомнить
Vladimir Karputov  

Скрипт PositionIdentifier.mq5 поможет получать данные для ввода в следующие скрипты или советники: он распечатывает для всех позиций два параметра: 

POSITION_TICKET

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

Значение POSITION_TICKET соответствует MqlTradeRequest::position.

long

POSITION_IDENTIFIER

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

 

Идентификатор позиции указывается в каждом ордере (ORDER_POSITION_ID) и сделке (DEAL_POSITION_ID), которая ее открыла, изменила или закрыла. Используйте это свойство для поиска ордеров и сделок, связанных с позицией.

 

Переворот позиции изменяет ее идентификатор на тикет ордера, в результате которого произошел переворот.

long

 

Работает как на неттинговых, так и на хэдж счетах. 

Листинг скрипта:

//+------------------------------------------------------------------+
//|                                           PositionIdentifier.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property description "Print POSITION_IDENTIFIER and POSITION_TICKET"
#property version   "1.000"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   int pos=PositionsTotal();
   for(int i=0;i<pos;i++)
     {
      ResetLastError();
      string pos_symbol=PositionGetSymbol(i);
      if(pos_symbol==NULL)
        {
         Print("Error PositionGetSymbol #",GetLastError());
         return;
        }
      long pos_ticket=PositionGetInteger(POSITION_TICKET);
      if(pos_ticket==0)
        {
         Print("Error PositionGetInteger(POSITION_TICKET)");
         return;
        }
      long pos_identifier=PositionGetInteger(POSITION_IDENTIFIER);
      if(pos_ticket==0)
        {
         Print("Error PositionGetInteger(POSITION_IDENTIFIER)");
         return;
        }
      PrintFormat("Symbol: %s, ticket: %I64d, identifier: %I64d",pos_symbol,pos_ticket,pos_identifier);
     }
  }
//+------------------------------------------------------------------+
Файлы: