Frage zur Funktion OnTradeTransaction

 

Entsprechend der Hilfe.

позволяет связать выполненное действие request identifier (Aufruf der Funktionen OrderSend oder OrderSendAsync) mit dem Ergebnis dieser Aktion, das an OnTradeTransaction übergeben wird


D.h. Sie können damit überprüfen, ob der Auftrag in der Funktion OnTradeTransaction korrekt ausgeführt wurde. Oder habe ich etwas missverstanden?

Allerdings gibt es hier einen Vorbehalt:

Die Reihenfolge, in der diese Transaktionen am Terminal ankommen, ist nicht garantiert, so dass wir unseren Handelsalgorithmus nicht darauf aufbauen können, dass einige Handelstransaktionen nach anderen ankommen. Darüber hinaus können Transaktionen bei der Übertragung vom Server zum Terminal verloren gehen.

Nun, nicht garantierte Konsistenz ist das halbe Problem. Aber was ist mit der Tatsache, dass eine Transaktion verloren gehen kann und wir daher die Funktion OnTradeTransaction nicht für Prüfungen verwenden können.

Es stellt sich also die Frage: Wozu brauchen wir dann diese Ereignisbehandlungsfunktion? Ist es absolut nutzlos, das Terminal anzuschließen? Oder habe ich wieder etwas falsch verstanden?

 
DieOnTradeTransaction-Funktion ist vor allem für die Erstellung von asynchronen Trading Expert Advisors notwendig. Wenn Sie nicht an solchen Entwicklungen beteiligt sind, brauchen Sie diese Funktion wahrscheinlich nicht zu studieren. Kurz gesagt,OnTradeTransaction muss zusammen mit der Überprüfung von Änderungen in der Handelsumgebung verwendet werden.Ich möchte dieses Problem nicht im Detail erörtern.
 

Auch dafür danke ich Ihnen. Aber selbst wenn es bei der Erstellung von asynchronen Handelsexperten, die nicht von mir stammen, mögliche Transaktionsverluste gibt, über welche Art von Überprüfung können wir dann sprechen?

Und im Allgemeinen bin ich mit der Antwort zufrieden. Ich verfüge nicht über ausreichende Kenntnisse, um dieses Thema im Detail zu erörtern.

Nochmals vielen Dank.

 
AlexeyVik :

Danke auch dafür. Aber selbst wenn bei der Erstellung von asynchronen Handelsexperten, die nicht von mir stammen, Transaktionsverluste möglich sind, über welche Art von Verifizierung können wir sprechen?

Im Allgemeinen befriedigt mich die Antwort. Und ich habe nicht genug Wissen, um dieses Thema ausführlicher zu diskutieren.

Und nochmals vielen Dank.

Zu diesem Thema habe ich einen Artikel geschrieben.

Es sagt nur, wie man die Bestellung, die durch den OrderSendAsync- Befehl platziert wurde, nicht „verlieren“ soll

Jetzt wird es überprüft, aber wenn es nicht herauskommt, dann ist hier ein Beispiel aus diesem Artikel (Terminmarkt FORTS):

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

Ich habe einen Artikel über dieses Problem geschrieben.

Hier wird genau erklärt, wie man eine mit dem Befehl OrderSendAssync erteilte Bestellung nicht "verliert".

Es wird gerade getestet, aber falls es nicht herauskommt, hier ein Beispiel aus diesem Artikel (FORTS-Terminmarkt):

Als ob wir es alle verstehen und vor Freude in die Hände klatschen würden. Tut mir leid, aber in Ihrem Code ist es viel komplizierter.
 
C-4:
Als ob wir es alle verstehen und vor Freude in die Hände klatschen würden. Tut mir leid, aber Ihr Code ist eine Katastrophe.

Hat jemand versprochen, dass es einfach sein würde?

Tut mir leid, Vasili, warte, bis der Artikel veröffentlicht wird....

P/S Wenn der Artikel nicht veröffentlicht wird, werde ich hier Erklärungen zum Beispiel schreiben.

 
Mikalas:

P/S Wenn der Artikel nicht erscheint, werde ich hier eine Erklärung für ein Beispiel veröffentlichen.

Warum sollte es nicht herauskommen? Das Material ist interessant.

Ich denke, Sie, Mikalas, haben sich sehr bemüht, in Ihrem Dialog mit MQ viele Dinge über Tickets und Bestellnummern herauszufinden. Also warten Sie ab.

 
Mikalas:

Ich habe einen Artikel über dieses Problem geschrieben.

Hier wird genau erklärt, wie man eine mit dem Befehl OrderSendAssync erteilte Bestellung nicht "verliert".

Er wird gerade getestet, aber falls er nicht erscheint, hier ein Beispiel aus diesem Artikel (FORTS-Terminmarkt):

Wenn Sie mir die Frage gestatten. Warum konzentrieren Sie sich darauf, eine Bestellung mit der Funktion OrderSendAssync() aufzugeben? Wenn wir eine Bestellung mit der Funktion OrderSend() aufgeben, geht die Transaktion dann nicht verloren? In diesem Fall gibt es mehr Garantien?


In meiner Unerfahrenheit wollte ich die Entscheidungsfindung in diesem oder jenem Fall in OnTradeTransactio() einfügen. Aber bisher hat das nicht so gut funktioniert. Und nachdem ich von einem möglichen Transaktionsverlust gelesen habe, habe ich Sie um Klarstellung gebeten.

Um für den FORTS-Markt zu schreiben, muss man diesen Markt im Allgemeinen verstehen. Im Moment ist es nichts für mich, vielleicht brauche ich es nicht. Ich habe mich entschieden, meinen in mql4 geschriebenen EA umzuschreiben, um mql5 zu studieren. Ich studiere sie gerade.

 
AlexeyVik:

Wenn es Ihnen nichts ausmacht, eine Frage. Warum konzentrieren Sie sich auf das Aufgeben einer Bestellung mit OrderSendAssync()? Wenn Sie eine Bestellung mit der Funktion OrderSend() aufgeben, geht die Transaktion dann nicht verloren? In diesem Fall gibt es mehr Garantien?


In meiner Unerfahrenheit wollte ich die Entscheidungsfindung in diesem oder jenem Fall in OnTradeTransactio() einfügen. Aber bisher hat das nicht so gut funktioniert. Und nachdem ich von einem möglichen Verlust von Transaktionen gelesen habe, habe ich Sie um Klarstellung gebeten.

Um für den FOREX-Markt zu schreiben, müssen Sie diesen Markt verstehen. Das ist noch nichts für mich, und vielleicht brauche ich es auch gar nicht. Ich beschloss, meine EA in mql4 geschrieben neu zu schreiben, um mql5 zu studieren. Ich studiere sie gerade.

1. orderSendAsync ist viel schneller (es wird nicht auf eine Antwort vom Server gewartet).

OrderSend wird garantiert eine Antwort vom Server erhalten.

2. Das Beispiel funktioniert perfekt auf FOREX

durch Änderung vonresult.retcode == TRADE_RETCODE_PLACED inresult.retcode == TRADE_RETCODE_DONE

 
Mikalas:

1. orderSendAsync ist viel schneller (es wird nicht auf eine Antwort vom Server gewartet)

2. Das Beispiel funktioniert auch perfekt auf FOREX

durch Änderung vonresult.retcode == TRADE_RETCODE_PLACED inresult.retcode == TRADE_RETCODE_DONE

D.h. wenn Asynchronität nicht angewandt wird, dann gibt es keinen Bedarf im OnTradeTransaction-Handler, da die Eulen auf eine Antwort vom Server warten werden?

Bislang habe ich jedoch noch nicht herausgefunden, wie ich am besten feststellen kann, ob eine Stop-Order aktiviert wurde. Zum Beispiel habe ich Markt Buy 0,1 und SellStop 0,3, aber wenn 0,3 aktiviert ist, wird es bleiben 0,2 und an welchem Punkt sollte ich es folgen... Es stellt sich also heraus, dass wir bei jedem Tick zwei Befehle befolgen müssen. Und ich wollte die Eulen entlasten und nur kontrollieren, wenn die Transaktion stattfindet. Ich wollte nicht einmal kontrollieren, sondern prüfen, was passiert ist, und entscheiden, was zu tun ist. Aber ich denke, das ist nicht der Fall... Vielleicht ist es besser, zu den alten und bewährten Methoden zurückzukehren...

 
AlexeyVik:

Also, wenn wir nicht verwenden Asynchronie, gibt es keine Notwendigkeit in OnTradeTransaction Handler, weil die Eulen werden für eine Antwort vom Server warten?

Aber bisher habe ich noch nicht die beste Methode gefunden, um zu erkennen, ob eine Stop-Order aktiviert wurde. Zum Beispiel habe ich Markt Buy 0,1 und SellStop 0,3, aber wenn 0,3 aktiviert ist, wird es bleiben 0,2 und an welchem Punkt sollte ich es folgen... Es stellt sich also heraus, dass wir bei jedem Tick zwei Befehle befolgen müssen. Und ich wollte die Eulen entlasten und nur kontrollieren, wenn die Transaktion stattfindet. Ich wollte nicht einmal kontrollieren, sondern prüfen, was passiert ist, und entscheiden, was zu tun ist. Aber ich denke, das ist nicht der Fall... Vielleicht ist es besser, zu den alten und bewährten Methoden zurückzukehren...

Ja, Sie können die Verwendung von OnTradeTransaction vermeiden, aber in diesem Fall müssen Sie die Historie durchsehen, was die Gesamtleistung des EA verringert.

Jeder Entwickler hat eine Wahl!