Pergunta sobre a função OnTradeTransaction

 

De acordo com a ajuda.

позволяет связать выполненное действие identificador de pedido (OrderSend ou OrderSendAsync call) com o resultado desta ação passado para a OnTradeTransaction


Isto é, permite verificar se a ordem foi executada corretamente na função OnTradeTransaction. Ou estou entendendo mal alguma coisa?

Mas há uma ressalva aqui:

A ordem de chegada dessas transações ao terminal não é garantida, portanto, não podemos construir nosso algoritmo comercial na espera de que algumas transações comerciais cheguem depois de outras. Além disso, as transações podem ser perdidas na entrega do servidor para o terminal.

Bem, a consistência não garantida é a metade do problema. Mas e quanto ao fato de que uma transação pode se perder e, portanto, não podemos usar a função OnTradeTransaction para verificações.

Então surge a pergunta: Para que então precisamos desta função de manipulador de eventos? É absolutamente inútil fixá-lo ao terminal? Ou estou entendendo algo errado novamente?

 
A funçãoOnTradeTransaction é necessária antes de tudo para a criação assíncrona de Expert Advisors comerciais. Se você não estiver envolvido em tais desenvolvimentos, muito provavelmente não precisará estudar esta função. Em resumo, aOnTradeTransaction deve ser utilizada juntamente com a verificação das mudanças do ambiente comercial. Não quero discutir este problema em detalhes.
 

Obrigado por isso também. Mas mesmo que haja possíveis perdas de transação ao criar especialistas em comércio assíncrono, não por mim, de que tipo de verificação podemos falar?

E, em geral, estou satisfeito com a resposta. Não tenho conhecimentos suficientes para discutir este assunto em detalhes.

Mais uma vez, obrigado.

 
AlexeyVik :

Obrigado por isso também. Mas mesmo que ao criar, não por mim, especialistas em negociação assíncrona, perdas de transações sejam possíveis, de que tipo de verificação podemos falar?

Em geral, a resposta me satisfaz. E eu não tenho conhecimento suficiente para discutir este tópico com mais detalhes.

E obrigado novamente.

Escrevi um artigo sobre este assunto.

Apenas diz como não "perder" o pedido feito pelo comando OrderSendAsync

Agora está sendo verificado, mas se não sair, aqui está um exemplo deste artigo (Forts de mercado a prazo):

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

Escrevi um artigo sobre este problema.

Ele diz exatamente como não "perder" um pedido feito pelo comando OrderSendAssync

Ele está sendo testado agora, mas se falhar, aqui está um exemplo deste artigo (FORTS mercado futuro):

Como se todos nós o recebêssemos e batêssemos palmas de alegria. Desculpe, mas é muito mais complicado do que isso em seu código.
 
C-4:
Como se todos nós o recebêssemos e batêssemos palmas de alegria. Desculpe, mas seu código está uma bagunça.

Alguém prometeu que seria fácil?

Desculpe, Vasili, espere até que o artigo saia....

P/S Se o artigo não for publicado, escreverei explicações, por exemplo, aqui.

 
Mikalas:

P/S Se o artigo não for publicado, publicarei aqui uma explicação, por exemplo.

Por que não deveria ser divulgado? O material é interessante.

Eu acho que você, Mikalas, fez um grande esforço em descobrir muitas coisas sobre ingressos e identificação de pedidos em seu diálogo com a MQ. Então espere por isso.

 
Mikalas:

Escrevi um artigo sobre este problema.

Ele diz exatamente como não "perder" um pedido feito pelo comando OrderSendAssync

Está sendo testado agora, mas se não sair, aqui está um exemplo para você daquele artigo (FORTS mercado futuro):

Se você não se importa que eu pergunte. Por que você se concentra em fazer um pedido usando a função OrderSendAssync()? Se fizermos um pedido usando a função OrderSend(), a transação não será perdida? Neste caso, há mais garantias?


Em minha inexperiência, quis inserir a tomada de decisão neste ou naquele caso na OnTradeTransactio(). Mas até agora não tem funcionado tão bem. E tendo lido sobre uma possível perda de transações, pedi-lhe esclarecimentos.

Em geral, para escrever para o mercado FORTS é preciso entender este mercado. Por enquanto não é para mim, talvez eu não precise dele. Decidi reescrever minha EA escrita em mql4 a fim de estudar mql5. Estou estudando isso agora.

 
AlexeyVik:

Se você não se importa, uma pergunta. Por que você se concentra em fazer um pedido com OrderSendAssync()? Se você fizer um pedido usando a função OrderSend(), a transação não será perdida? Neste caso, há mais garantias?


Em minha inexperiência, quis inserir a tomada de decisão neste ou naquele caso na OnTradeTransactio(). Mas até agora não tem funcionado tão bem. E tendo lido sobre uma possível perda de transações, pedi-lhe esclarecimentos.

Em geral, para escrever para o mercado FOREX, você precisa entender este mercado. Isto ainda não é para mim, e talvez eu não precise disto. Decidi reescrever minha EA escrita em mql4 para estudar mql5. Estou estudando isso agora.

1. OrderSendAsync é muito mais rápido (não espera por uma resposta do servidor).

A OrderSend é garantida para obter uma resposta do servidor.

2. O exemplo funcionará perfeitamente no FOREX

alterandoresultado.retcode == TRADE_RETCODE_PLACED pararesult.retcode == TRADE_RETCODE_DONE

 
Mikalas:

1. OrderSendAsync é muito mais rápido (não espera por uma resposta do servidor)

2. O exemplo funcionará perfeitamente também no FOREX

alterandoresultado.retcode == TRADE_RETCODE_PLACED pararesult.retcode == TRADE_RETCODE_DONE

Isto é, se a assincronia não for aplicada, então não há necessidade no manipulador da OnTradeTransaction, pois as corujas aguardarão uma resposta do servidor?

Mas até agora, não encontrei a melhor maneira de determinar se uma ordem Stop foi ativada. Por exemplo, eu defini 0,1 e SellStop 0,3 para o mercado e quando ativa 0,3, ficará 0,2 e em que momento devo segui-lo... Assim, acontece que temos que seguir duas ordens a cada tique. E eu queria aliviar as Corujas e controlar somente quando a transação acontecesse. Eu queria nem mesmo controlar, mas verificar o que aconteceu e decidir o que fazer. Mas acho que este não é o caso... Talvez seja melhor voltar aos velhos métodos testados e comprovados.

 
AlexeyVik:

Então, se não usarmos assíncrono, não há necessidade no manipulador da OnTradeTransaction porque as corujas vão esperar por uma resposta do servidor?

Mas até agora não encontrei a melhor maneira de detectar se uma ordem de parada foi ativada. Por exemplo, eu defini o mercado Comprar 0,1 e VenderStop 0,3, mas quando 0,3 é ativado, ele permanecerá 0,2 e em que momento devo segui-lo... Assim, acontece que temos que seguir duas ordens a cada tique. E eu queria aliviar as Corujas e controlar somente quando a transação acontecesse. Eu queria nem mesmo controlar, mas verificar o que aconteceu e decidir o que fazer. Mas acho que este não é o caso... Talvez seja melhor voltar aos métodos antigos, testados e testados.

Sim, você pode evitar o uso da OnTradeTransaction, mas neste caso, você terá que olhar através do histórico, o que reduzirá o desempenho geral da EA.

Todo desenvolvedor tem uma escolha!

Razão: