OnTradeTransaction関数について質問です。

 

ヘルプによると

позволяет связать выполненное действие リクエスト識別子(OrderSend または OrderSendAsync 関数呼び出し)、このアクションの 結果は OnTradeTransaction に渡される。


すなわち、OnTradeTransaction関数で注文が正しく実行されたかどうかを確認することができます。それとも、私が何か勘違いしているのでしょうか?

しかし、ここで注意点があります。

これらの取引の端末への到着順序は保証されていないので、ある取引取引が他の取引の後に到着するのを待つという取引アルゴリズムを構築 することはできない。また、サーバーから端末への受け渡しの際に、トランザクションが失われる可能性が ある。

まあ、一貫性が保証されていないのは、悩みの種が半減してしまいますが。しかし、トランザクションが失われる可能性があり、そのためチェックのためにOnTradeTransaction関数を使用できないというのはどうでしょうか。

では、このイベントハンドラ関 数は何のために必要なのでしょうか?端末へのアタッチメントが絶対的に無駄なのか?それとも、また何か誤解しているのでしょうか?

 
OnTradeTransaction 関数は、まず、非同期取引のExpert Advisorを作成 するために必要です。もし、あなたがそのような開発に携わっていないのであれば、この機能を勉強する必要はほとんどないでしょう。つまりOnTradeTransaction は、取引環境の変更を確認しながら使用する必要が あります。この問題を詳しく論じるつもりはない。
 

こちらもありがとうございました。しかし、私ではなく、非同期取引の専門家を 作るときに、取引損失が発生する可能性があるとしても、どのような検証を すればよいのかという話になります。

そして、総じて満足のいく回答が得られました。私はこのテーマについて詳しく論じるだけの知識を持っていません。

いつもありがとうございます。

 
AlexeyVik :

それもありがとう。しかし、私ではなく、非同期取引の専門家を作成する場合、取引損失が発生する可能性があるとしても、どのような検証について話すことができますか?

一般的に、答えは私を満足させます。そして、私にはこのトピックをより詳細に議論するのに十分な知識がありません。

そして、もう一度ありがとう。

この問題に関する記事を書きました。

OrderSendAsyncコマンドによって出された注文を「失わない」方法を指示するだけです

現在チェック中ですが、出てこない場合は、この記事の例を次に示します(フォワードマーケット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:

この問題については、記事を書いています。

OrderSendAssyncコマンドで発注した注文を「失わない」ための方法を正確に伝えています。

現在テスト中ですが、もし失敗したら、この記事(FORTS先物市場)の例です。

まるで、全員がそれを理解して手を叩いて喜ぶかのように。申し訳ありませんが、あなたのコードではとんでもなく複雑になっています。
 
C-4:
まるで、全員がそれを理解して手を叩いて喜ぶかのように。申し訳ありませんが、あなたのコードは混乱しています。

誰かが簡単にできると約束したのでしょうか?

ごめんね、バシリ、記事が出るまで待っててね...。

P/S もし記事が出なかったら、ここに例の解説を書きますね。

 
Mikalas:

P/S もし記事が出なかったら、ここに例の解説を載せますね。

なぜ、出てきてはいけないのか?素材が面白いんです。

ミカラスさんは、MQさんとの対話の中で、チケットやオーダーIDについていろいろと把握されて、ご苦労されていると思います。だから待っててね。

 
Mikalas:

この問題については、記事を書いています。

OrderSendAssyncコマンドで発注した注文を「失わない」ための方法を正確に伝えています。

今、テスト中ですが、もし出てこなかったら、その記事(FORTS先物市場)から例をご紹介します。

差し支えなければ、お聞かせください。なぜ、OrderSendAssync()関数による発注に こだわるのか?OrderSend()関数を使って注文を出すと、その取引は失われないのでしょうか?この場合、保証はもっとあるのですか?


未熟な私は、OnTradeTransactio()に、この場合、この場合の判断を挿入したかったのです。しかし、これまではあまりうまくいかなかった。そして、取引上の損失が発生する可能性があることを読み、その説明を求めました。

一般に、FORTSのマーケットで文章を書くには、このマーケットを理解する必要があります。今のところ自分には必要ないのかもしれません。mql5を勉強するために、mql4で書いたEAを書き直すことにしました。今、勉強しているところです。

 
AlexeyVik:

差し支えなければ、質問です。なぜOrderSendAssync()で発注 することにこだわるのか?OrderSend()関数を使って注文した場合、その取引は失われないのでしょうか?この場合、保証はもっとあるのですか?


未熟な私は、OnTradeTransactio()に、この場合、この場合の判断を挿入したかったのです。しかし、これまではあまりうまくいかなかった。そして、取引ができなくなる可能性があることを読み、説明を求めました。

一般的に、FOREXマーケット向けに文章を書くには、このマーケットを理解する必要があります。これはまだ自分には必要ないのかもしれません。mql4で書いたEAをmql5の勉強のために書き直すことにしました。今、勉強しているところです。

1.OrderSendAsyncはより高速です(サーバーからの応答を待ちません)。

OrderSendは、サーバーからの応答が保証されています。

2.この例は、FOREXで完全に動作します。

result.retcode == TRADE_RETCODE_PLACED をresult.retcode == TRADE_RETCODE_DONE に変更することで対応可能です。

 
Mikalas:

1.OrderSendAsyncはより高速です(サーバーからの応答を待ちません)。

2.この例は、FOREXでも完璧に機能します。

result.retcode == TRADE_RETCODE_PLACED をresult.retcode == TRADE_RETCODE_DONE に変更することで対応可能です。

つまり、非同期が適用されない場合、フクロウはサーバーからの応答を待つので、OnTradeTransaction ハンドラは必要ないのですか?

しかし、今のところ、Stop注文が発動されたかどうかを判断する最良の方法は見つかっていません。例えば、マーケットBuy0.1とSellStop0.3を設定し、0.3が発動したら0.2のままで、どの時点でフォローすればいいのか......。つまり、1ティックごとに2つの命令に従わなければならないことがわかったのです。そして、フクロウを解放し、取引が発生した時だけコントロールしたいと思いました。コントロールもせず、何が起こったかを確認して、どうするかを決めたかったのです。でも、これではいけないのでしょうね...。昔の試行錯誤の方法に戻った方がいいのかもしれない...。

 
AlexeyVik:

つまり、非同期を使用しない場合、フクロウはサーバーからの応答を待つので、OnTradeTransaction ハンドラは必要ないのでしょうか?

しかし、今のところ、逆指値注文が作動したかどうかを検出する最良の方法は見つかっていません。例えば、マーケットBuy0.1とSellStop0.3を設定し、0.3が発動したら0.2のままで、どの時点で追随すればいいのか...。つまり、1ティックごとに2つの命令に従わなければならないことがわかったのです。そして、フクロウを解放し、取引が発生した時だけコントロールしたいと思いました。コントロールもせず、何が起こったかを確認して、どうするかを決めたかったのです。でも、これではいけないのでしょうね...。昔のように試行錯誤を重ねた方がいいのかもしれない......。

はい、OnTradeTransactionを使用 しないこともできますが、この場合、履歴に目を通す必要があり、EA全体のパフォーマンスを低下させることになります。

すべてのデベロッパーに選択肢がある!