Pregunta sobre la función OnTradeTransaction

 

Según la ayuda.

позволяет связать выполненное действие identificador de la solicitud (llamada a las funciones OrderSend o OrderSendAsync) con el resultado de esta acción pasada a OnTradeTransaction


Es decir, permite comprobar si la orden se ha ejecutado correctamente en la función OnTradeTransaction. ¿O he entendido algo mal?

Pero aquí hay una advertencia:

El orden de llegada de estas transacciones al terminal no está garantizado, por lo que no podemos construir nuestro algoritmo de negociación esperando que algunas transacciones comerciales lleguen después de otras. Además, las transacciones pueden perderse en la entrega del servidor al terminal.

Bueno, la coherencia no garantizada es la mitad del problema. Pero qué pasa con el hecho de que una transacción puede perderse y por lo tanto no podemos utilizar la función OnTradeTransaction para las comprobaciones.

Así que surge la pregunta: ¿Para qué necesitamos entonces esta función manejadora de eventos? ¿Es un complemento absolutamente inútil para el terminal? ¿O estoy entendiendo algo mal otra vez?

 
La funciónOnTradeTransaction es necesaria, en primer lugar, para crear Asesores Expertos en negociación asíncrona. Si no se dedica a estos desarrollos, lo más probable es que no necesite estudiar esta función. En resumen,OnTradeTransaction debe utilizarse junto con la comprobación de los cambios del entorno comercial. No quiero discutir este problema en detalle.
 

Gracias por eso también. Pero incluso si hay posibles pérdidas de transacciones al crear expertos en comercio asíncrono, no por mí, ¿de qué tipo de verificación podemos hablar?

Y en general estoy satisfecho con la respuesta. No tengo suficientes conocimientos para discutir este tema en detalle.

Gracias de nuevo.

 
AlexeyVik :

Gracias por eso también. Pero incluso si al crear, no por mí, expertos en comercio asincrónico, las pérdidas de transacciones son posibles, ¿de qué tipo de verificación podemos hablar?

En general, la respuesta me satisface. Y no tengo suficiente conocimiento para discutir este tema con más detalle.

Y gracias de nuevo

Escribí un artículo sobre este tema.

Simplemente dice cómo no "perder" el pedido realizado por el comando OrderSendAsync

Ahora se está revisando, pero si no sale, aquí hay un ejemplo de este artículo (Forts de mercado a plazo):

 //+------------------------------------------------------------------+
//|                                                       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:

He escrito un artículo sobre este problema.

Indica exactamente cómo no "perder" un pedido realizado por el comando OrderSendAssync

Se está probando ahora, pero si no sale, aquí tienes un ejemplo de este artículo (mercado de futuros FORTS):

Como si todos lo entendiéramos y aplaudiéramos de alegría. Lo siento, pero es mucho más complicado que eso en su código.
 
C-4:
Como si todos lo entendiéramos y aplaudiéramos de alegría. Lo siento, pero tu código es un desastre.

¿Alguien prometió que sería fácil?

Lo siento, Vasili, espera a que salga el artículo....

P/S Si el artículo no sale, escribiré las explicaciones por ejemplo aquí.

 
Mikalas:

P/S Si no sale el artículo, publicaré aquí una explicación por ejemplo.

¿Por qué no debería salir? El material es interesante.

Creo que tú, Mikalas, te has esforzado en averiguar muchas cosas sobre las entradas y el identificador de pedidos en tu diálogo con MQ. Así que espéralo.

 
Mikalas:

He escrito un artículo sobre este problema.

Indica exactamente cómo no "perder" un pedido realizado por el comando OrderSendAssync

Se está probando ahora, pero si no sale, aquí tienes un ejemplo de ese artículo (mercado de futuros FORTS):

Si no le importa que le pregunte. ¿Por qué se centra en la realización de un pedido mediante la función OrderSendAssync()? Si realizamos un pedido mediante la función OrderSend(), ¿no se perderá la transacción? En este caso, hay más garantías...


En mi inexperiencia, quería insertar la toma de decisiones en tal o cual caso en OnTradeTransactio(). Pero hasta ahora no ha funcionado muy bien. Y habiendo leído sobre una posible pérdida de la transacción, les pedí aclaraciones.

En general, para escribir para el mercado de FORTS hay que entender este mercado. Por ahora no es para mí, tal vez no lo necesite. Decidí reescribir mi EA escrito en mql4 para estudiar mql5. Lo estoy estudiando ahora.

 
AlexeyVik:

Si no le importa, una pregunta. ¿Por qué se centra en realizar un pedido con OrderSendAssync()? Si se realiza un pedido mediante la función OrderSend(), ¿no se perderá la transacción? En este caso, hay más garantías...


En mi inexperiencia, quería insertar la toma de decisiones en tal o cual caso en OnTradeTransactio(). Pero hasta ahora no ha funcionado muy bien. Y habiendo leído sobre una posible pérdida de transacciones, les pedí aclaraciones.

En general, para escribir para el mercado FOREX, es necesario entender este mercado. Esto no es para mí todavía, y tal vez no lo necesite. Decidí reescribir mi EA escrito en mql4 para estudiar mql5. Lo estoy estudiando ahora.

1. OrderSendAsync es mucho más rápido (no espera la respuesta del servidor).

Se garantiza que OrderSend obtendrá una respuesta del servidor.

2. El ejemplo funcionará perfectamente en FOREX

cambiando result.retcode== TRADE_RETCODE_PLACED porresult.retcode == TRADE_RETCODE_DONE

 
Mikalas:

1. OrderSendAsync es mucho más rápido (no espera la respuesta del servidor)

2. El ejemplo funcionará perfectamente en FOREX también

cambiando result.retcode== TRADE_RETCODE_PLACED porresult.retcode == TRADE_RETCODE_DONE

Es decir, si no se aplica la asincronía, entonces no hay necesidad en el manejador OnTradeTransaction ya que los búhos esperarán una respuesta del servidor?

Pero hasta ahora, no he encontrado la mejor manera de determinar si se ha activado una orden de Stop. Por ejemplo, he puesto en el mercado Buy 0.1 y SellStop 0.3 y cuando se activa 0.3, se queda 0.2 y en qué momento debo seguirlo... Así que resulta que tenemos que seguir dos órdenes en cada tic. Y quería relevar a los Búhos y controlar sólo cuando se produjera la transacción. No quería ni siquiera controlar, sino comprobar qué pasaba y decidir qué hacer. Pero supongo que este no es el caso... Tal vez sea mejor volver a los viejos métodos probados...

 
AlexeyVik:

Entonces, si no usamos la asincronía, no hay necesidad en el manejador OnTradeTransaction porque los búhos esperarán una respuesta del servidor?

Pero hasta ahora no he encontrado la mejor manera de detectar si se ha activado una orden de stop. Por ejemplo, he puesto en el mercado Buy 0.1 y SellStop 0.3, pero cuando se activa el 0.3, se queda en 0.2 y en qué momento debo seguirlo... Así que resulta que tenemos que seguir dos órdenes en cada tic. Y quería relevar a los Búhos y vigilar sólo cuando se produjera la transacción. No quería ni siquiera controlar, sino comprobar qué pasaba y decidir qué hacer. Pero supongo que este no es el caso... Tal vez sea mejor volver a los viejos y probados métodos...

Sí, puede evitar el uso de OnTradeTransaction, pero en este caso, tendrá que buscar en el historial, lo que reducirá el rendimiento general del EA.

Cada desarrollador puede elegir.

Razón de la queja: