OnTradeTransaction - страница 8

 
Igor Zakharov:

на "нормальных" роботах, случай который я описал, вообще не замечал; но в одном меня попросили сделать систему безопасности: условие было, что позиции всегда локированы (либо реальными позициями, либо отложенным ордером), т.е. количество лотов на покупку равно количеству лотов на продажу. Вот этот случай и познакомил меня с нюансами подсчета ордеров/позиций/сделок в пятёрке.

разница, как я объяснил это самому себе, :) в том, что четвёрка получая ответ от брокера сначала синхронизирует свои "таблицы" с открытыми ордерами и историей, а потом сообщает пользователю об ответе брокера. пятёрка сразу транслирует нам этот ответ, и параллельно правит свои "таблицы" (а все mql программы читают данные из этих "таблиц"). Именно этот момент мы ловим на миллисекундном таймере. Но тогда, почему в тестере мы на это не напарываемся?

А вообще, я смирился...

Нет, дела обстоят хуже.

Ордер в момент превращения из отложенного (или маркет) в исторический (исполненный или отмененный) на какое-то время пропадает из терминала вообще. Его нет ни среди отложенных (или "стартовавших" маркетов), ни среди исторических.

То есть дело не в исполнении, а в синхронизации этих двух таблиц. Ответ от сервера пришел ("ордер исполнен, породил сделку такую-то"), из одной таблицы он удаляется, а в другую не вносится.

 
Andrey Khatimlianskii:

Нет, дела обстоят хуже.

Ордер в момент превращения из отложенного (или маркет) в исторический (исполненный или отмененный) на какое-то время пропадает из терминала вообще. Его нет ни среди отложенных (или "стартовавших" маркетов), ни среди исторических.

То есть дело не в исполнении, а в синхронизации этих двух таблиц. Ответ от сервера пришел ("ордер исполнен, породил сделку такую-то"), из одной таблицы он удаляется, а в другую не вносится.

Вот это интересно проверить. Igor Makanu заинтриговал меня задачкой   https://www.mql5.com/ru/forum/6343/page1097#comment_12518742

Сделал в первом приближении на коленке. Потом сделаю сбор статистики о работе OnOrder и OnOrderTransaction и состоянии торгового окружения терминалаи если не лень можно поставить на демо-тесты, чтобы посмотреть что как на разных счетах / брокерах.

тогда можно будет анализировать. Допущения пока сделаны: 1. не проверяется частичное исполнение и не проверяются особенности исполнения на счете, отправил маркет-ордер запомнил открытую позицию, жду появления в журнале сделки по закрытию этой позиции и открываю снова в обратное направление. 2. В идеале отлавливать в OnOrderTransaction конкретную транзакцию, но пока сделал так - в обоих событиях проверяю всё одинаково.

Естественно код неоптимальный. Уже вижу где будут потери ордеров-позиций, если всё так плохо как описано постом выше.

//+------------------------------------------------------------------+
//|                                                 Test_Makalu2.mq5 |
//|                                           Copyright 2019, Allex@ |
//|                                                 alex-all@mail.ru |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Allex@"
#property link      "alex-all@mail.ru"
#property version   "1.00"
#include <Expert\Expert.mqh>
//--- input parameters
input int      TP=200;
input int      SL=200;
input double   Lot=0.01;
input string   File;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CExpertTest : public CExpert
  {
public:
   int               type;
   ulong             order;
   ulong             deal;
   ulong             position;
   bool              send;
   bool              placed;
   bool              opened;
   bool              history;
   datetime          last_history;

                     CExpertTest() {order=0;};
                    ~CExpertTest() {};
   bool              Buy(double volume,double price,double sl,double tp,const string comment="") {return m_trade.Buy(volume, price, sl, tp,  comment);};
   bool              Sell(double volume,double price,double sl,double tp,const string comment="") {return m_trade.Sell(volume, price, sl, tp,  comment);};
   bool              CheckOrder(ulong order)
     {
      ulong state;
      if(OrderSelect(order))
        {
         if(OrderGetInteger(ORDER_STATE)==ORDER_STATE_FILLED)
            position=OrderGetInteger(ORDER_POSITION_ID);
        }
      else
         if(HistoryOrderSelect(order))
           {
            if(HistoryOrderGetInteger(order,ORDER_STATE,state)&& state==ORDER_STATE_FILLED)
               position=HistoryOrderGetInteger(order,ORDER_POSITION_ID);
           }
         else
           {
            return false;
           }
      return true;

     }
   virtual bool      Processing(void)
     {
      double price;
      if(order==0)
        {
         last_history=TimeCurrent();
         price=m_symbol.Ask();
         if(Buy(Lot,price,m_symbol.NormalizePrice(price-SL*m_symbol.Point()),m_symbol.NormalizePrice(price+TP*m_symbol.Point())))
            if(m_trade.ResultRetcode()==TRADE_RETCODE_DONE)
              {
               //ulong deal2;
               deal=m_trade.ResultDeal();
               order=m_trade.ResultOrder();
               if(order!=0 && CheckOrder(order))
                  return true;
              }
        }
      return false;
     }
   void              OnTrade()
     {
      if(order==0 || !CheckOrder(order))
         return;
      HistorySelect(last_history,TimeCurrent());
      for(int i=HistoryDealsTotal()-1; i>=0; i--)
        {
         ulong ticket=HistoryDealGetTicket(i);
         ulong ordticket=HistoryDealGetInteger(ticket,DEAL_ORDER);
         ulong pos=HistoryDealGetInteger(ticket,DEAL_POSITION_ID);
         if(pos==position || ordticket==order || ticket==deal)
           {
            int entry=HistoryDealGetInteger(ticket,DEAL_ENTRY);
            ulong type=HistoryDealGetInteger(ticket,DEAL_TYPE);
            if(pos==position && entry==DEAL_ENTRY_OUT)
              {
               Refresh();
               double price;
               double sl;
               double tp;
               bool result=false;
               datetime dt=TimeCurrent();
               if(type==DEAL_TYPE_SELL)
                 {
                  price=m_symbol.Bid();
                  sl=m_symbol.NormalizePrice(price+SL*m_symbol.Point());
                  tp=m_symbol.NormalizePrice(price-TP*m_symbol.Point());
                  result=Sell(Lot,price,sl,tp);
                 }
               if(type==DEAL_TYPE_BUY)
                 {
                  price=m_symbol.Ask();
                  sl=m_symbol.NormalizePrice(price-SL*m_symbol.Point());
                  tp=m_symbol.NormalizePrice(price+TP*m_symbol.Point());
                  result=Buy(Lot,price,sl,tp);
                 }
               if(result && m_trade.ResultRetcode()==TRADE_RETCODE_DONE)
                 {
                  deal=m_trade.ResultDeal();
                  order=m_trade.ResultOrder();
                  if(order!=0 && CheckOrder(order))
                     last_history=dt;
                 }
              }
           }
        }
     }
  };
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
CExpertTest Expert;
//---
int OnInit()
  {
   if(!Expert.Init(Symbol(),Period(),Point()))
      return INIT_FAILED;
   Expert.OnTradeProcess(true);
   return(INIT_SUCCEEDED);
  }
//---
void OnTick()
  {
   Expert.OnTick();
  }
//+------------------------------------------------------------------+
void OnTrade()
  {
   Expert.OnTrade();
  }
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
                        const MqlTradeRequest& request,
                        const MqlTradeResult& result)
  {
   Expert.OnTrade();
  }
Вопросы от начинающих MQL5 MT5 MetaTrader 5
Вопросы от начинающих MQL5 MT5 MetaTrader 5
  • 2019.07.21
  • www.mql5.com
Подскажите пожалуйста, такой показатель тестера в жизни реален? И хороший это или плохой результат за год с депо 3000...
 
Aleksey Mavrin:

Вот это интересно проверить. Igor Makanu заинтриговал меня задачкой   https://www.mql5.com/ru/forum/6343/page1097#comment_12518742

там в обсуждении было решение https://www.mql5.com/ru/forum/6343/page1098#comment_12519819  , часть обсуждения, правда, потерли (((
 
Решение есть в ветке MT4Orders. Но нужно же каждые грабли пощупать самостоятельно ;)
 
Aleksey Mavrin:

Сделал в первом приближении на коленке.

На этом демо лучше смотреть. ForexTimeFXTM-Demo01

 
Igor Zakharov:

на "нормальных" роботах, случай который я описал, вообще не замечал

Любую торговую библиотеку на вшивость можно и нужно проверить через стресс-тесты на различных демо-счетах. Она должна проходить все без сучка и задоринки.

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

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

 
Igor Makanu:
там в обсуждении было решение https://www.mql5.com/ru/forum/6343/page1098#comment_12519819  , часть обсуждения, правда, потерли (((
Andrey Khatimlianskii:
Решение есть в ветке MT4Orders. Но нужно же каждые грабли пощупать самостоятельно ;)

Это да, грабли всегда интересны, а потом посмотреть как профи сделали. Решение fxsaber гениальное своей лаконичностью, но в том решении вижу засаду в одном - в мануалах сказано, что тикет позиции ОБЫЧНО тикет открывшего ордера, но НЕ ВСЕГДА.

В моём решения я из этого исходил.

fxsaber
fxsaber
  • www.mql5.com
Опубликовал пост "Out-Of-Sample" - где расположить, справа или слева? Когда-то в паблике столкнулся с мнением, что OOS должен располагаться только справа. Т.е. расположение его слева от интервала Оптимизации - ошибка. Я с этим был категорически не согласен, т.к. не видел разницы. Теперь вижу. Ошибался, был не прав... Опубликовал пост...
 
fxsaber:

Любую торговую библиотеку на вшивость можно и нужно проверить через стресс-тесты на различных демо-счетах. Она должна проходить все без сучка и задоринки.

в описанном мной роботе дело было не в брокере, а в таймере. я для тестов использовал 200ms, а когда отдал, человек поставил 5ms. при пяти почти каждый раз срабатывало на любом счёте.

не знаю важно ли, но там были использованы винапишные timeBeginPeriod(1), т.е. ниже стандартных 20ms всё происходило

 
Aleksey Mavrin:

тикет позиции ОБЫЧНО тикет открывшего ордера, но НЕ ВСЕГДА.

Плохо помню, но, вроде, всегда.

 
fxsaber:

Плохо помню, но, вроде, всегда.

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

вот только не понял - при частичном закрытии позиции - тикет не меняется чтоли на тикет последнего повлиявшего на позицию ордера?

Использование сделок тогда избыточно, пересмотрю свои коды, спасибо. Не зря на форум залез)

К вопросу о "потерянном ордере", которого нет ни в списке текущих ни в списке исторических: Мне кажется это никакой не баг, просто надо внимательно посмотреть на особенности работы

связки Терминал-Сервер МТ-Рынок (В случае инстант исполнения рынок отпадает). Я думаю так, смотрите - терминал отправляет рыночный ордер, в случае синхронной функции  - ждёт и получает ответ от сервера,

если не ошибка, то ответом может быть только TRADE_RETCODE_DONE (в случае инстант еще реквоты, но пока про рыночный тип исполнения), который по сути означает что сервер отправил ордер дальше в рынок и сам

ждёт ответа. Состояние ордера в этот момент ORDER_STATE_STARTED если не ошибаюсь, и известен его тикет. Если ордер исполнился, то сервер присылает в терминал OnTradeTransaction и статус ордера меняется ORDER_STATE_FILLED и становится известна сделка

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

Вот это время пока ордера исполняются в ECN-сети или ещё где, их и нет ни в одном из двух списков. Т.е. в случае рыночного ордера он вообще только в истории появляется (не уверен насчёт случая реквот при инстант исполнении), 

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

Верно рассуждаю?

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