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

Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий
Ilya Rebenok
310
Ilya Rebenok  

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

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

В терминале на 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 секунду, может не хватает времени. В общем даже не знаю, куда еще копать.

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

Alexey Viktorov
25679
Alexey Viktorov  
Илья Ребенок:

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

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

В терминале на 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 и по результатам этих проверок принимать решение.

Ilya Rebenok
310
Ilya Rebenok  
Alexey Viktorov:

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

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

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

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

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

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

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

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

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

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!

Alexey Viktorov
25679
Alexey Viktorov  
Илья Ребенок:

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

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


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

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

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

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

Ilya Rebenok
310
Ilya Rebenok  
fxsaber:

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


Вторая

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

Alexey Viktorov:

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


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

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

fxsaber:

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

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

Alexey Viktorov
25679
Alexey Viktorov  
Илья Ребенок:


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

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

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

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

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

Ilya Rebenok
310
Ilya Rebenok  
fxsaber:

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

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

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

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

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

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

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

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

Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий