Обработка транзакций OnTradeTransaction

 

Добрый вечер.

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

В терминале на 2 инструментах запускаю 2 разных робота. Мэджики везде разные. Робот выставляет отложенные лимитки, в процедуре OnTradeTransaction отлавливаю транзакции совершения сделки и на основе нее выставляю отложенные стоп ордера.

Ниже код на транзакцию сделки

case TRADE_TRANSACTION_DEAL_ADD:
        {
         drop_info2("TRADE_TRANSACTION_DEAL_ADD\r\n"+TransactionDescription(trans));
         if((trans.deal_type==DEAL_TYPE_BUY || trans.deal_type==DEAL_TYPE_SELL) && trans.order!=0)
           {
            if(getIsDealOfExpert(trans.deal)) //функция проверки принадлежности сделки к роботу
              {
               drop_info2("Сделка наша");
               analyzeFilledOrder(trans.order,trans.volume); //процедура по выставлению отложенных стоп ордеров
              }
           }
        }
      break;

Код функции проверки принадлежности сделки к роботу

bool getIsDealOfExpert(ulong dealTicket)
     {
      if(HistoryDealSelect(dealTicket) && HistoryDealGetInteger(dealTicket,DEAL_MAGIC)==magic_number && HistoryDealGetString(dealTicket,DEAL_SYMBOL)==symbol)
         return true;
      else
         return false;
     }

Код процедуры по выставлению отложенных стоп ордеров

void analyzeFilledOrder(ulong orderTicket,double volume)
  {
   bool isFindOrder=false;
   string fullComment;
   ENUM_ORDER_TYPE orderType;
   if(getIsOrderOfExpert(orderTicket,true)) //Если ордер из сделки уже в истории
     {
      fullComment=HistoryOrderGetString(orderTicket,ORDER_COMMENT);
      orderType=ENUM_ORDER_TYPE(HistoryOrderGetInteger(orderTicket,ORDER_TYPE));
      isFindOrder=true; //локальная переменная, если нашли в истории
     }
   if(!isFindOrder && getIsOrderOfExpert(orderTicket,false)) //Если не нашли ордер в истории и ордер есть не в истории
     {
      fullComment=OrderGetString(ORDER_COMMENT); 
      orderType=ENUM_ORDER_TYPE(OrderGetInteger(ORDER_TYPE));
      isFindOrder=true; //локальная переменная, если нашли не в истории
     }
   if(isFindOrder) //если хоть где-то нашли, то выставляем отложенные стоп ордера
     {
     //выставляем стоп ордера

Код функции поиска ордера в истории и не в истории

bool getIsOrderOfExpert(ulong OrderTicket,bool isHistory)
     {
      bool is_expert=false;
      //если ордер находится в истории
      if(isHistory)
        {
         if(HistoryOrderSelect(OrderTicket) && HistoryOrderGetInteger(OrderTicket,ORDER_MAGIC)==magic_number && HistoryOrderGetString(OrderTicket,ORDER_SYMBOL)==symbol)
            is_expert=true;
        }
      else
        {
         if(OrderSelect(OrderTicket) && OrderGetInteger(ORDER_MAGIC)==magic_number && OrderGetString(ORDER_SYMBOL)==symbol)
            is_expert=true;
        }
      return is_expert;
     }

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

Периодически транзакции приходят в таком порядке TRADE_TRANSACTION_ORDER_DELETE, затем TRADE_TRANSACTION_DEAL_ADD, затем TRADE_TRANSACTION_HISTORY_ADD. Зачастую в этом случае после совершения сделки стоп ордера не выставляются. По моему предположению это связано с тем, что ордер уже удален, но в историю еще не попал. То есть мы не можем найти ордер из сделки ни в истории, ни в терминале. Хотя это сомнительно, но факт остается фактом - стоп ордера не выставляются, так как робот после поиска ордера во всех измерениях его не находит (isFindOrder=false). Порядок транзакций может быть и правильным, но ордера все равно нигде нет.  Во всех случаях робот сделку определяет верно, но до выставления ордеров не доходит. При этом также периодически все работает правильно и ордера выставляются.

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

Поделитесь опытом и идеями пожалуйста.

 
Илья Ребенок:

Добрый вечер.

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

В терминале на 2 инструментах запускаю 2 разных робота. Мэджики везде разные. Робот выставляет отложенные лимитки, в процедуре OnTradeTransaction отлавливаю транзакции совершения сделки и на основе нее выставляю отложенные стоп ордера.

Ниже код на транзакцию сделки

Код функции проверки принадлежности сделки к роботу

Код процедуры по выставлению отложенных стоп ордеров

Код функции поиска ордера в истории и не в истории

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

Периодически транзакции приходят в таком порядке TRADE_TRANSACTION_ORDER_DELETE, затем TRADE_TRANSACTION_DEAL_ADD, затем TRADE_TRANSACTION_HISTORY_ADD. Зачастую в этом случае после совершения сделки стоп ордера не выставляются. По моему предположению это связано с тем, что ордер уже удален, но в историю еще не попал. То есть мы не можем найти ордер из сделки ни в истории, ни в терминале. Хотя это сомнительно, но факт остается фактом - стоп ордера не выставляются, так как робот после поиска ордера во всех измерениях его не находит (isFindOrder=false). Порядок транзакций может быть и правильным, но ордера все равно нигде нет.

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

Поделитесь опытом и идеями пожалуйста.

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

В момент типа транзакции TRADE_TRANSACTION_DEAL_ADD надо выбрать позицию по trans.position и проверить её магик.

if(PositionSelectByTicket(trans.position) && PositionGetInteger(POSITION_MAGIC) == mag)

Можно проверить и символ по trans.symbol == _Symbol и по результатам этих проверок принимать решение.

 
Alexey Viktorov:

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

В момент типа транзакции TRADE_TRANSACTION_DEAL_ADD надо выбрать позицию по trans.position и проверить её магик.

Можно проверить и символ по trans.symbol == _Symbol и по результатам этих проверок принимать решение.

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

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

Поделитесь опытом и идеями пожалуйста.

Одна ситуация

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Ошибки, баги, вопросы

fxsaber, 2018.06.20 23:18

Решил проверить, как долго длятся такие ситуации фантомных ордеров, когда ордер есть в системе, но нет в Терминале.

// Советник отслеживает длительность ситуаций, когда ордер отсутствует среди текущих и исторических

#define TOSTRING(A)  #A + " = " + (string)(A) + "\n"
#define TOSTRING2(A) #A + " = " + EnumToString(A) + " (" + (string)(A) + ")\n"

bool OrderIsExist( const ulong &OrderTicket )
{
  return(OrderTicket ? OrderSelect(OrderTicket) || HistoryOrderSelect(OrderTicket) : true);
}

void OnTradeTransaction ( const MqlTradeTransaction &Trans, const MqlTradeRequest&, const MqlTradeResult& )
{
  static bool PrevIsExist = true;
  static ulong StartTime = 0;
  static ulong MaxInterval = 0;
  
  const ulong NowTime = GetMicrosecondCount();
  const bool IsExist = OrderIsExist(Trans.order);
    
  if (!IsExist)
  {
    Print(TOSTRING2(Trans.type) + TOSTRING(Trans.order) +
          TOSTRING(OrderSelect(Trans.order)) + TOSTRING(HistoryOrderSelect(Trans.order)));       
  
    if (PrevIsExist) 
      StartTime = NowTime;
  }
  else if (!PrevIsExist)
  {
    const ulong Interval = NowTime - StartTime;
    
    Print(TOSTRING(Interval) + TOSTRING2(Trans.type) + TOSTRING(Trans.order) +
          TOSTRING(OrderSelect(Trans.order)) + TOSTRING(HistoryOrderSelect(Trans.order)));       
    
    if (Interval > MaxInterval)
    {
      MaxInterval = Interval;
      
      Comment(TOSTRING(MaxInterval) + TOSTRING(Trans.order)); // mcs.
    }
  }
          
  PrevIsExist = IsExist;
}


Результат

2018.06.21 00:10:31.047 Trans.type = TRADE_TRANSACTION_ORDER_DELETE (2)
2018.06.21 00:10:31.047 Trans.order = 2210967406
2018.06.21 00:10:31.047 OrderSelect(Trans.order) = false
2018.06.21 00:10:31.047 HistoryOrderSelect(Trans.order) = false
2018.06.21 00:10:31.047 
2018.06.21 00:10:31.080 Interval = 32643
2018.06.21 00:10:31.080 Trans.type = TRADE_TRANSACTION_HISTORY_ADD (3)
2018.06.21 00:10:31.080 Trans.order = 2210967406
2018.06.21 00:10:31.080 OrderSelect(Trans.order) = false
2018.06.21 00:10:31.080 HistoryOrderSelect(Trans.order) = true


32 миллисекунды ордер есть, но его в Терминале нет! Только представьте себе, какие это может нести последствия, если в этом интервале выполнялась торговая логика...


Интересно, что фантомные ордера чаще всего присутствуют только при TRADE_TRANSACTION_ORDER_DELETE и при TRADE_TRANSACTION_DEAL_ADD (значительно реже) типах транзакций.


Очень нехороший нюанс платформы.


ЗЫ Сомнительное быстродействие торговых операций на пятерке, к сожалению.


Вторая

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Непонятная ситуация при срабатывании отложенных ордеров.

fxsaber, 2018.11.26 13:37

Еще бывает такая ситуация:

  1. Выставили открывающий позицию маркет-ордер и OrdersTotal увеличился на единицу.
  2. Он исполнился и OrdersTotal уменьшился на единицу, но при этом PositionsTotal не увеличился на единицу. Т.е. существует позиция, но Терминал о ней не знает.

Например, нет ни позиций, ни ордеров - PositionsTotal = 0, OrdersTotal = 0.

Выставляете маркет-ордер. При этом PositionsTotal = 0, OrdersTotal = 1.

Маркет-ордер исполнился - OrdersTotal = 0. Но PositionsTotal = 0!

 
Илья Ребенок:

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

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


Учитывая добавку в вашем сообщении, это всё не подходит. В таком случае надо повнимательней разбираться.

 
Илья Ребенок:

Пробовал разные подходы, ничего не помогает.

Напишите простое действие, которое нужно реализовать.

 
fxsaber:

Одна ситуация


Вторая

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

Alexey Viktorov:

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


Учитывая добавку в вашем сообщении, это всё не подходит. В таком случае надо повнимательней разбираться.

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

fxsaber:

Напишите простое действие, которое нужно реализовать.

Не совсем понял про написать простое действие) Поясните пожалуйста.

 
Илья Ребенок:


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

Уже удалили, но было это не так давно.

 
Илья Ребенок:

Не совсем понял про написать простое действие) Поясните пожалуйста.

Какая торговая задача стоит?

 
fxsaber:

Какая торговая задача стоит?

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

В роботе предусмотрена доливка, поэтому при докупке выставляем также стоп ордер и тейк профит, и заносим в комментарий тикет доливки

Идея про sleep в 1 секунду может спасти положение? Чтобы успели пройти все транзакции TRADE_TRANSACTION_ORDER_DELETE и TRADE_TRANSACTION_HISTORY_ADD

Общие принципы - Торговые операции - MetaTrader 5
Общие принципы - Торговые операции - MetaTrader 5
  • www.metatrader5.com
Перед тем как приступить к изучению торговых функций платформы, необходимо создать четкое представление об основных терминах: ордер, сделка и позиция. — это распоряжение брокерской компании купить или продать финансовый инструмент. Различают два основных типа ордеров: рыночный и отложенный. Помимо них существуют специальные ордера Тейк Профит...
 

Илья Ребенок:

В роботе предусмотрена доливка, поэтому при докупке выставляем также стоп ордер и тейк профит, и заносим в комментарий тикет доливки

Одновременно может быть >=2 тейков и стопов?

Причина обращения: