Question sur la fonction OnTradeTransaction

 

Selon l'aide.

позволяет связать выполненное действие identifiant de la demande (appel des fonctions OrderSend ou OrderSendAsync) avec le résultat de cette action transmis à OnTradeTransaction


C'est-à-dire qu'il vous permet de vérifier si l'ordre a été correctement exécuté dans la fonction OnTradeTransaction. Ou est-ce que je comprends mal quelque chose ?

Mais il y a une mise en garde à faire :

L'ordre d'arrivée de ces transactions au terminal n'est pas garanti, nous ne pouvons donc pas construire notre algorithme de négociation en attendant que certaines transactions commerciales arrivent après d'autres. En outre, les transactions peuvent être perdues lors de leur acheminement du serveur au terminal.

Eh bien, ne pas garantir la cohérence est la moitié du problème. Mais qu'en est-il du fait qu'une transaction peut se perdre et que nous ne pouvons donc pas utiliser la fonction OnTradeTransaction pour les contrôles.

La question qui se pose est donc la suivante : à quoi sert cette fonction de gestion d'événements? L'attachement au terminal est-il absolument inutile ? Ou je comprends encore mal quelque chose ?

 
La fonctionOnTradeTransaction est tout d'abord nécessaire pour créer des Expert Advisors de trading asynchrone. Si vous n'êtes pas engagé dans de tels développements, vous n'avez probablement pas besoin d'étudier cette fonction. En bref,OnTradeTransaction doit être utilisé en même temps que la vérification des changements de l'environnement commercial. Je ne veux pas discuter de ce problème en détail.
 

Merci pour cela aussi. Mais même s'il existe des pertes de transaction possibles lors de la création d'experts en négociation asynchrone, pas par moi, de quel type de vérification pouvons-nous parler ?

Et en général, je suis satisfait de la réponse. Je n'ai pas assez de connaissances pour discuter de ce sujet en détail.

Merci encore.

 
AlexeyVik :

Merci pour ça aussi. Mais même si lors de la création, et non par moi, d'experts en trading asynchrone, des pertes de transaction sont possibles, de quel type de vérification peut-on parler ?

En général, la réponse me satisfait. Et je n'ai pas assez de connaissances pour discuter de ce sujet plus en détail.

Et merci encore.

J'ai écrit un article sur cette question.

Il indique simplement comment ne pas "perdre" la commande passée par la commande OrderSendAsync

Maintenant, il est en cours de vérification, mais s'il ne sort pas, voici un exemple tiré de cet article (FORTS du marché à terme):

 //+------------------------------------------------------------------+
//|                                                       Demo_1.mq5 |
//|                                          Copyright 2015, Mikalas |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Mikalas"
#property link        "https://www.mql5.com"
#property version    "1.00"

input uint TimerPeriod = 1000 ;     //Время ожидания проверки ордера (1 сек.)   

ulong       order_ticket;
uint        request_id;
//
ulong       magic_number = 1010000 ;   //по 10000 на каждый символ
ulong       magic_storage;
ulong       mem_magic;
datetime    mem_time;
uint        mem_tick;
ulong       deal_volume;             //Счётчик заливки ордера
//
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit ()
{
  deal_volume = 0 ;             
   //--- Установка таймера
   if ( ! EventSetMillisecondTimer ( 500 ) )     //0.5 cек.
  {
     MessageBox ( "Таймер не установлен!" , "Ошибка" , MB_OK | MB_ICONHAND );
     return ( INIT_FAILED );
  } 
   return ( INIT_SUCCEEDED );
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit ( const int reason )
{
//--- удаление таймера
   EventKillTimer ();
}
//+------------------------------------------------------------------+
//| Expert Get retcode function                                      |
//+------------------------------------------------------------------+
string GetRetCode( const uint code )
{
   string retcode;
//---  
   switch ( code )
  {
     case 10004 : retcode = "Реквота" ;
         break ;
     case 10006 : retcode = "Запрос отвергнут" ;
         break ;
     case 10007 : retcode = "Запрос отменен трейдером" ;
         break ;
     case 10008 : retcode = "Ордер размещен" ;
         break ;
     case 10009 : retcode = "Заявка выполнена" ;
         break ;
     case 10010 : retcode = "Заявка выполнена частично" ;
         break ;
     case 10011 : retcode = "Ошибка обработки запроса" ;
         break ;
     case 10012 : retcode = "Запрос отменен по истечению времени" ;
         break ;
     case 10013 : retcode = "Неправильный запрос" ;
         break ;
     case 10014 : retcode = "Неправильный объем в запросе" ;
         break ;
     case 10015 : retcode = "Неправильная цена в запросе" ;
         break ;
     case 10016 : retcode = "Неправильные стопы в запросе" ;
         break ;
     case 10017 : retcode = "Торговля запрещена" ;
         break ;
     case 10018 : retcode = "Рынок закрыт" ;
         break ;
     case 10019 : retcode = "Нет достаточных денежных средств для выполнения запроса" ;
         break ;
     case 10020 : retcode = "Цены изменились" ;
         break ;
     case 10021 : retcode = "Отсутствуют котировки для обработки запроса" ;
         break ;
     case 10022 : retcode = "Неверная дата истечения ордера в запросе" ;
         break ;
     case 10023 : retcode = "Состояние ордера изменилось" ;
         break ;
     case 10024 : retcode = "Слишком частые запросы" ;
         break ;
     case 10025 : retcode = "В запросе нет изменений" ;
         break ;
     case 10026 : retcode = "Автотрейдинг запрещен сервером" ;
         break ;
     case 10027 : retcode = "Автотрейдинг запрещен клиентским терминалом" ;
         break ;
     case 10028 : retcode = "Запрос заблокирован для обработки" ;
         break ;
     case 10029 : retcode = "Ордер или позиция заморожены" ;
         break ;
     case 10030 : retcode = "Указан неподдерживаемый тип исполнения ордера по остатку" ;
         break ;
     case 10031 : retcode = "Нет соединения с торговым сервером" ;
         break ;
     case 10032 : retcode = "Операция разрешена только для реальных счетов" ;
         break ;
     case 10033 : retcode = "Достигнут лимит на количество отложенных ордеров" ;
         break ;
     case 10034 : retcode = "Достигнут лимит на объем ордеров и позиций для данного символа" ;
         break ;
     case 10035 : retcode = "Неверный или запрещённый тип ордера" ;
         break ;
     case 10036 : retcode = "Позиция с указанным POSITION_IDENTIFIER уже закрыта" ;
         break ;
     default : retcode = "Нет кода возврата." ;  
         break ; 
  }
   return ( retcode );
}
//+------------------------------------------------------------------+
//| Expert place order function                                      |
//+------------------------------------------------------------------+
bool PlaceOrder( const string a_symbol, const double price, const double volume, const bool buy_sell )
{
   MqlTradeRequest request = { 0 };
   MqlTradeResult   result  = { 0 };
//---  
  order_ticket = 0 ;
  request_id = 0 ;
  mem_time = TimeTradeServer ();   //Время установки ордера (для для сокращения поиска в истории)
  mem_tick = GetTickCount ();       //Начало отсчёта времени (для проверки, если не сработала функция OnTradeTransaction)   
  mem_magic = magic_storage + 1 ;   //Уникальный номер (magic) ордера
  
   if ( mem_magic >= ( magic_number + 9999 ) ) mem_magic = magic_number;   //Переполнение, начинаем сначала
     
//--- Fill structure
  request.action = TRADE_ACTION_PENDING ;
  request.magic  = mem_magic;
  request.symbol = a_symbol;
  request.volume = volume;
  request.price  = price;
    
   if ( buy_sell )
  {
    request.type       = ORDER_TYPE_BUY_LIMIT ;
  }
   else
  {
    request.type       = ORDER_TYPE_SELL_LIMIT ;
  } 
  request.comment      = "Отложенный ордер..." ;      
  request.type_filling = ORDER_FILLING_RETURN ;
  request.type_time    = ORDER_TIME_DAY ;
   
//--- Send order
   if ( OrderSendAsync ( request, result ) )
  {
     if ( result.retcode == TRADE_RETCODE_PLACED ) 
    {
      request_id = result.request_id;
      magic_storage = mem_magic;
       return ( true );
    }
     else
    {
      mem_magic = 0 ;
      mem_time = 0 ;
      mem_tick = 0 ;
       Print ( "Ордер не отправлен! " , a_symbol, " Код возврата = " , GetRetCode( result.retcode ) );
       return ( false );
    }
  }
   else
  {
    mem_magic = 0 ;
    mem_time = 0 ;
    mem_tick = 0 ;
     Print ( "Ордер не отправлен! " , a_symbol, " Код возврата = " , GetRetCode( result.retcode ) );
     return ( false );
  }
}
//+------------------------------------------------------------------+
//| Expert place order function                                      |
//+------------------------------------------------------------------+
void OnTick ()
{
   MqlTick a_tick;
  
   if ( SymbolInfoTick ( _Symbol , a_tick ) )
  {
    PlaceOrder( _Symbol , a_tick.ask, 1 , false );   //Устанавливаем ордер
  }     
}

//+------------------------------------------------------------------+
//| TradeTransaction function                                        |
//+------------------------------------------------------------------+
void OnTradeTransaction ( const MqlTradeTransaction & trans,
                         const MqlTradeRequest & request,
                         const MqlTradeResult & result)
{
   switch ( trans.type )
  {
     case TRADE_TRANSACTION_REQUEST :     if ( trans.order_state == ORDER_STATE_STARTED )
                                        {
                                           if ( ( request_id != 0 ) && ( result.request_id == request_id ) )
                                          {
                                             if ( result.retcode == TRADE_RETCODE_PLACED )
                                            {
                                              order_ticket = result.order;         //Получаем билет ордера
                                              mem_tick     = GetTickCount ();       //Начало отсчёта времени (для проверки, если не сработает функция OnTradeTransaction) 
                                            }
                                             else
                                            {
                                              mem_tick = 0 ;
                                               Print ( "OnTradeTransaction: Не получен билет ордера. Запрос = " , request_id );
                                            }
                                            request_id = 0 ;
                                            mem_magic  = 0 ;
                                            mem_time   = 0 ;
                                          }  
                                        }
                                         break ;
                                    
     case TRADE_TRANSACTION_DEAL_ADD :     if ( trans.order_state == ORDER_STATE_STARTED )
                                        {
                                           if ( ( order_ticket != 0 ) && ( trans.order == order_ticket ) )
                                          { 
                                             if ( ! OrderSelect ( order_ticket ) ) order_ticket = 0 ;     //Обнуляем билет, так как ордер залился полностью.
                                             Print ( "OnTradeTransaction: Сделка совершена, билет = " , trans.order ); 
                                          } 
                                        }
                                         break ;
                                     
     case TRADE_TRANSACTION_HISTORY_ADD : if ( (order_ticket != 0 ) && ( trans.order == order_ticket ) )
                                        {
                                          order_ticket = 0 ;
                                          
                                           switch ( trans.order_state )
                                          {
                                             case ORDER_STATE_REJECTED : Print ( "OnTradeTransaction: Ордер отклонён." );
                                                                       break ;
                                                                       
                                             case ORDER_STATE_CANCELED : Print ( "OnTradeTransaction: Ордер удалён." ); 
                                                                       break ;
                                                                     
                                             case ORDER_STATE_EXPIRED :   Print ( "OnTradeTransaction: Срок действия ордера окончен." );
                                                                       break ;
                                          }   
                                        }
                                         break ;     
                                        
     case TRADE_TRANSACTION_ORDER_UPDATE : if ( trans.order_state == ORDER_STATE_REQUEST_MODIFY )
                                         {
                                           if ( ( order_ticket != 0 ) && ( trans.order == order_ticket ) )
                                           {
                                             Print ( "OnTradeTransaction: Ордер в состоянии модифицикации." );
                                              mem_tick = GetTickCount ();  
                                           }
                                         }
                                         break ;                                                                                          
  }     
}
//+------------------------------------------------------------------+
// Expert find histiry order function                                |
//+------------------------------------------------------------------+
ulong FindHistoryOrder( const ulong a_magic, const datetime a_time, const datetime b_time )
{
   if ( HistorySelect ( a_time, b_time ) )
  {
     for ( int i = HistoryOrdersTotal () - 1 ; i >= 0 ; i-- )
    {
       ulong cur_ticket = HistoryOrderGetTicket ( i );
      
       if ( ulong ( HistoryOrderGetInteger ( cur_ticket, ORDER_MAGIC ) ) == a_magic ) return ( cur_ticket );
    }
  }  
   return ( 0 ) ;
}
//+------------------------------------------------------------------+
// Expert find order function                                        |
//+------------------------------------------------------------------+
ulong FindOrder( const ulong a_magic )
{
   for ( int i = OrdersTotal () - 1 ; i >= 0 ; i-- )
  {
     ulong cur_ticket = OrderGetTicket ( i );
    
     if ( ulong ( OrderGetInteger ( ORDER_MAGIC ) ) == a_magic ) return ( cur_ticket );
  }
   return ( 0 );
}
//+------------------------------------------------------------------+
//| Expert Get order tiket function                                  |
//+------------------------------------------------------------------+
ulong GetOrderTicket( const ulong m_magic, const datetime m_time, const datetime cur_time )
{
   ulong a_ticket = FindOrder( m_magic );                         //Ищем действующий ордер
  
   if ( a_ticket > 0 )
  {
     return ( a_ticket );
  }
   else
  {
    a_ticket = FindHistoryOrder( m_magic, m_time, cur_time );   //Ищем ордер в истории
    
     if ( a_ticket > 0 )
    {
       return ( a_ticket );
    }
  }  
   return ( 0 ); 
}
//+------------------------------------------------------------------+
//| Expert Check time function                                      |
//+------------------------------------------------------------------+
bool CheckTime( const uint start_value, const uint per_value )
{
   uint end_value = GetTickCount ();
  
   if ( end_value < start_value )
  {
     if ( ( start_value - end_value ) >= per_value ) return ( true );
  } 
   else
  {
     if ( ( end_value - start_value ) >= per_value ) return ( true );
  }
   return ( false );
}
//+------------------------------------------------------------------+
// Expert Get History Deals function                                 |
//+------------------------------------------------------------------+
uint GetHistoryDeals( const ulong ticket )
{
   int deals_total = HistoryDealsTotal ();
   uint ticket_deals = 0 ;
          
   for ( int i = 0 ; i < deals_total; i++ )
  {
     ulong deal_ticket = HistoryDealGetTicket ( i );
     ulong ord_ticket = ulong ( HistoryDealGetInteger ( deal_ticket, DEAL_ORDER ) );
        
     if ( ( ord_ticket > 0 ) && ( ord_ticket == ticket ) ) ticket_deals++;
  }
           
   if ( ticket_deals > 0 ) return ( ticket_deals );
  
   return ( 0 );
}
//+------------------------------------------------------------------+
//| Expert Check order function                                      |
//+------------------------------------------------------------------+
void CheckOrder()
{
   if ( ( mem_tick > 0 ) && CheckTime( mem_tick, TimerPeriod ) )           //Проверка времени ожидания действия над ордером (установка, модификация или удадение) 
  {
     if ( mem_magic > 0 )                                                   //Нет билета, получаем билет
    {
      order_ticket = GetOrderTicket( mem_magic, mem_time, TimeTradeServer () );
      
       if ( order_ticket > 0 )
      {
        mem_tick  = GetTickCount ();                                       //Начало отсчёта времени, если в будующем вновь не сработает функция OnTradeTransaction 
      }
       else
      {
        mem_tick  = 0 ;
         Print ( "Timeout: Билет ордера не найден!" );  
      }
      mem_magic = 0 ;
      mem_time  = 0 ;
    }
     else                                                                  
    {
       if ( order_ticket > 0 )                                             //Есть билет, смотрим что произошло с ордером
      {
         if ( OrderSelect ( order_ticket ) )                                 //Ордер рабочий 
        {
           double init_volume = OrderGetDouble ( ORDER_VOLUME_INITIAL );
           double cur_volume = OrderGetDouble ( ORDER_VOLUME_CURRENT );
          
           if ( init_volume != cur_volume )
          {
             ulong d_volume = ( ulong ( init_volume - cur_volume ) - deal_volume );
            deal_volume = deal_volume + d_volume;
            
             if ( d_volume > 0 )
            { 
               Print ( "Timeout: Сделка совершена, билет = " , order_ticket, " Объём = " , d_volume );
            }  
          }
          mem_tick = GetTickCount ();
        }
         else                                                                //Ордер исполнился, удален или экпирировался   
        {
           if ( HistoryOrderSelect ( order_ticket ) )
          {
             datetime ord_time = datetime ( HistoryOrderGetInteger ( order_ticket, ORDER_TIME_SETUP ) );
            
             if ( HistorySelect ( ord_time, TimeTradeServer () ) )
            {
               uint deals = GetHistoryDeals( order_ticket );
              
               if ( deals > 0 )
              {
                 Print ( "Timeout: Сделка совершена, билет = " , order_ticket );
              }
            }
          }
           else
          {
             Print ( "Timeout: Ордер " , order_ticket, " не найден в истории!" );
          } 
          deal_volume  = 0 ;
          order_ticket = 0 ;
          mem_tick     = 0 ;
        }
      }
       else
      {
        deal_volume = 0 ;
        mem_tick    = 0 ;
         Print ( "Timeout: Нет билета ордера!" );
      }
    }
  }
}
//+------------------------------------------------------------------+
//| Expert timer function                                            |
//+------------------------------------------------------------------+
void OnTimer ()
{
  CheckOrder();
}
//+------------------------------------------------------------------+
 
Mikalas:

J'ai écrit un article sur ce problème.

Il indique exactement comment ne pas "perdre" une commande passée par la commande OrderSendAssync

Il est actuellement testé, mais s'il ne sort pas, voici un exemple tiré de cet article (marché à terme FORTS) :

Comme si on comprenait tous et qu'on tapait des mains de joie. Désolé, mais c'est beaucoup plus compliqué que ça dans votre code.
 
C-4:
Comme si on comprenait tous et qu'on tapait des mains de joie. Désolé, mais votre code est un désordre.

Quelqu'un a promis que ce serait facile ?

Désolé, Vasili, attends que l'article sorte. ....

P/S Si l'article ne sort pas, je vais écrire des explications par exemple ici.

 
Mikalas:

P/S Si l'article ne sort pas, je posterai une explication par exemple ici.

Pourquoi ça ne sortirait pas ? Le matériel est intéressant.

Je pense que vous, Mikalas, avez fait beaucoup d'efforts pour comprendre beaucoup de choses sur les billets et l'identification des commandes dans votre dialogue avec MQ. Alors, attendez.

 
Mikalas:

J'ai écrit un article sur ce problème.

Il indique exactement comment ne pas "perdre" une commande passée par la commande OrderSendAssync

Il est en cours de test actuellement, mais s'il ne sort pas, voici pour vous un exemple tiré de cet article (marché à terme FORTS) :

Si vous me permettez de demander. Pourquoi se concentrer sur la passation d'une commande à l'aide de la fonction OrderSendAssync() ? Si nous passons un ordre en utilisant la fonction OrderSend(), la transaction ne sera-t-elle pas perdue ? Dans ce cas, il y a plus de garanties ?


Dans mon inexpérience, j'ai voulu insérer la prise de décision dans tel ou tel cas dans OnTradeTransactio(). Mais jusqu'à présent, cela n'a pas très bien fonctionné. Et ayant lu des informations sur une éventuelle perte de transactions, je vous ai demandé des éclaircissements.

En général, pour écrire pour le marché FORTS, il faut comprendre ce marché. Pour l'instant, ce n'est pas pour moi, peut-être que je n'en ai pas besoin. J'ai décidé de réécrire mon EA écrit en mql4 afin d'étudier le mql5. Je suis en train de l'étudier.

 
AlexeyVik:

Si ça ne vous dérange pas, une question. Pourquoi se concentrer sur la passation d'une commande avec OrderSendAssync() ? Si vous passez un ordre en utilisant la fonction OrderSend(), la transaction ne sera-t-elle pas perdue ? Dans ce cas, il y a plus de garanties ?


Dans mon inexpérience, j'ai voulu insérer la prise de décision dans tel ou tel cas dans OnTradeTransactio(). Mais jusqu'à présent, cela n'a pas très bien fonctionné. Et ayant lu des informations sur une éventuelle perte de transactions, je vous ai demandé des éclaircissements.

En général, pour écrire pour le marché FOREX, vous devez comprendre ce marché. Ce n'est pas encore pour moi, et peut-être que je n'en ai pas besoin. J'ai décidé de réécrire mon EA écrit en mql4 pour étudier le mql5. Je suis en train de l'étudier.

1. OrderSendAsync est beaucoup plus rapide (il n'attend pas de réponse du serveur).

OrderSend a la garantie d'obtenir une réponse du serveur.

2. L'exemple fonctionnera parfaitement sur le FOREX

en changeantresult.retcode == TRADE_RETCODE_PLACED enresult.retcode == TRADE_RETCODE_DONE

 
Mikalas:

1. OrderSendAsync est beaucoup plus rapide (il n'attend pas de réponse du serveur).

2. L'exemple fonctionnera parfaitement sur le FOREX également.

en changeantresult.retcode == TRADE_RETCODE_PLACED enresult.retcode == TRADE_RETCODE_DONE

En d'autres termes, si l'asynchronie n'est pas appliquée, le gestionnaire OnTradeTransaction n'est pas nécessaire puisque les hiboux attendront une réponse du serveur ?

Mais jusqu'à présent, je n'ai pas trouvé la meilleure façon de déterminer si un ordre Stop a été activé. Par exemple, j'ai défini le marché Buy 0.1 et SellStop 0.3 et quand il s'active 0.3, il reste 0.2 et à quel moment dois-je le suivre... Il s'avère donc que nous devons suivre deux ordres à chaque tic. Et je voulais soulager les Hiboux et ne contrôler que lorsque la transaction a lieu. Je ne voulais même pas contrôler, mais vérifier ce qui s'était passé et décider de ce qu'il fallait faire. Mais je suppose que ce n'est pas le cas... Peut-être est-il préférable de revenir aux anciennes méthodes éprouvées...

 
AlexeyVik:

Donc, si nous n'utilisons pas l'asynchronie, il n'y a pas besoin du handler OnTradeTransaction car les hiboux attendront une réponse du serveur ?

Mais jusqu'à présent, je n'ai pas trouvé la meilleure façon de détecter si un ordre stop a été activé. Par exemple, j'ai défini le marché Buy 0.1 et SellStop 0.3 et quand il s'active 0.3, il reste 0.2 et à quel moment dois-je le suivre... Il s'avère donc que nous devons suivre deux ordres à chaque tic. Et je voulais soulager les Hiboux et ne contrôler que lorsque la transaction a lieu. Je ne voulais même pas contrôler, mais vérifier ce qui s'était passé et décider de ce qu'il fallait faire. Mais je suppose que ce n'est pas le cas... Peut-être vaut-il mieux revenir aux anciennes méthodes, celles qui ont fait leurs preuves...

Oui, vous pouvez éviter d'utiliser OnTradeTransaction, mais dans ce cas, vous devrez consulter l'historique, ce qui réduira les performances globales de l'EA.

Chaque développeur a le choix !