記事「MQL5における高度な注文執行アルゴリズム:TWAP、VWAP、アイスバーグ注文」についてのディスカッション

 

新しい記事「MQL5における高度な注文執行アルゴリズム:TWAP、VWAP、アイスバーグ注文」はパブリッシュされました:

MQL5フレームワークで、機関投資家向けの高度な執行アルゴリズム(TWAP、VWAP、アイスバーグ注文)を小口トレーダー向けに提供します。統合された実行マネージャーとパフォーマンスアナライザーを用いて、注文の分割(スライシング)や分析をよりスムーズかつ正確に行える環境を提供します。

「でも自分は機関投資家のような大口を動かしているわけではない」と思うかもしれません。肝心なのは、そうする必要がないということです。0.5ロットや数ミニロットの取引でも、ボラティリティ次第で執行に影響が出ます。これらのツールは次のような利点を提供します。

  • スリッページを抑える:小さな注文でも乱高下する市場で価格のブレを抑制
  • 優位性を強化:分割発注により、単発の一括注文より有利な平均価格を実現
  • 冷静さを維持:自動化によりパニック的な売買の誘惑を排除
  • スムーズなスケーリング:口座規模が拡大しても執行精度は維持
  • 存在を隠す:特にアイスバーグ注文は、真の注文サイズを隠して他アルゴリズムからの追跡を回避

今日では、かつて数百万ドル規模の予算が必要だった執行テクノロジーが、個人の取引環境でも利用可能です。TWAP、VWAP、アイスバーグ戦略用の洗練されたMQL5コードをプラットフォームに組み込むことで、個人トレーダーでも機関投資家レベルの執行力を手に入れられます。


作者: N Soumik

 

素晴らしい記事だ!

このアルゴにはどのペアがおすすめですか?

どの時間枠がお勧めですか?M5、M30など。

どのセッションですか?

ありがとうございます。

 
あなたのアルゴをテストしています。
ファイル、ExecutionAlgorithm.mqh に、注文を出す際に request.type_filling = ORDER_FILLING_IOC; という行を追加し、注文を出す際の問題を修正しました。

H1 でテストしたところ、SL も TP も適用されず、すべての取引が損失で終了しました。

また、コンパイル中に警告が発生しました。
long'から'double'へのタイプ変換によるデータ損失の可能性 VWAP.mqh 271 41
long'から'double'への型変換によるデータ損失の可能性 VWAP.mqh 272 22
long' から 'double' への型変換によるデータ損失の可能性 VWAP.mqh 449 17
long' から 'double' への型変換によるデータ損失の可能性 PerformanceAnalyzer.mqh 222 17
long' から 'double' への型変換によるデータ損失の可能性 ExecutionManager.mqh 418 17


アルゴのテスト方法、
時間枠、その他推奨事項があれば教えてください。
 
警告を修正する
また、コンパイル中に警告が発生する
long'から'double'への型 変換による データ損失の可能性 VWAP .mqh 271 41
long'から'double'への型変換によるデータ損失の可能性 VWAP .mqh 272 22
long」から「double」への型変換によるデータ損失の可能性 VWAP .mqh 449 17
long」から「double」への型変換によるデータ損失の可能性 PerformanceAnalyzer .mqh 222 17
long' から 'double' への型変換によるデータ損失の可能性 ExecutionManager .mqh 418 17


コード行
m_volumeProfile[intervalIndex] += rates[i].tick_volu


に変更した。
m_volumeProfile[intervalIndex] += (double)rates[i].tick_volume;

それは警告を修正しました
今、私の他のクエリに関する指導が必要です。
時間枠
また、
バックテスト中のすべての取引が損失となる理由
あなたのこの偉大な仕事をテストする方法。
 
i_vergo データ損失の可能性 VWAP.mqh 271 41
long'から'double'への型変換によるデータ損失の可能性 VWAP.mqh 272 22
long' から 'double' への型変換によるデータ損失の可能性 VWAP.mqh 449 17
long' から 'double' への型変換によるデータ損失の可能性 PerformanceAnalyzer.mqh 222 17
long' から 'double' への型変換によるデータ損失の可能性 ExecutionManager.mqh 418 17


アルゴのテスト方法、
時間枠、その他推奨事項があれば教えてください。

警告は問題ではないが、すぐに修正できるだろう。しかし、作者がバックテストに使用した設定と入力をステップ・バイ・ステップで示すことができれば最高だ。

 

I_Virgoの結果は、おそらく彼が間違った時間枠と通貨ペアを使用したためです。 バックテストレポートを見る限り、約2000バーのうち、時間枠はM1かM5で、ペアは不明でした。

MQがバックテストレポートに時間枠と通貨ペアを追加し、さらにペアの結果をより詳細に分けてくれれば、著者のバックテスト結果を より忠実に再現でき、FXペアへの適用性も判断できるのにと思います。また、EAが実行中にチャートにテキストを投稿できれば非常に助かります。


私もこの記事はすばらしいと思いますし、彼のテクニックを他のEAに応用することを期待して、徹底的に研究するつもりです。


ケープコッダ

 
//+------------------------------------------------------------------+
//| すべての実行アルゴリズムの基本クラス|
//+------------------------------------------------------------------+
class CExecutionAlgorithm
{
protected:
   string            m_symbol;           // 取引シンボル
   double            m_totalVolume;      // 実行する総量
   double            m_executedVolume;   // ボリュームはすでに実行済み
   double            m_remainingVolume;  // 実行可能な残量
   datetime          m_startTime;        // 実行開始時刻
   datetime          m_endTime;          // 実行終了時刻
   int               m_slippage;         // 許容されるスリップポイント
   bool              m_isActive;         // アルゴリズムは現在アクティブか
   
   // 統計
   double            m_avgExecutionPrice; // 平均執行価格
   int               m_totalOrders;       // 注文総数
   int               m_filledOrders;      // 埋まった注文の数
   
public:
   // コンストラクタ
   CExecutionAlgorithm(string symbol, double volume, datetime startTime, datetime endTime, int slippage);
   
   // デストラクタ
   virtual ~CExecutionAlgorithm();
   
   // 派生クラスが実装する仮想メソッド
   virtual bool      Initialize();
   virtual bool      Execute() = 0;
   virtual bool      Update() = 0;
   virtual bool      Terminate() = 0;
   
   // 共通メソッド
   bool              IsActive() { return m_isActive; }
   double            GetExecutedVolume() { return m_executedVolume; }
   double            GetRemainingVolume() { return m_remainingVolume; }
   double            GetAverageExecutionPrice() { return m_avgExecutionPrice; }
   
   // ヘルパーメソッド
   bool              PlaceOrder(ENUM_ORDER_TYPE orderType, double volume, double price = 0.0);
   bool              ModifyOrder(ulong ticket, double price, double sl, double tp);
   bool              CancelOrder(ulong ticket);
   void              UpdateAverageExecutionPrice(double price, double volume);
   
   // 適切な充填モードを取得するヘルパーメソッド
   ENUM_ORDER_TYPE_FILLING GetFillingMode();
};

//+------------------------------------------------------------------+
//| コンストラクタ|
//+------------------------------------------------------------------+
CExecutionAlgorithm::CExecutionAlgorithm(string symbol, double volume, 
                                       datetime startTime, datetime endTime, 
                                       int slippage)
{
   m_symbol = symbol;
   m_totalVolume = volume;
   m_executedVolume = 0.0;
   m_remainingVolume = volume;
   m_startTime = startTime;
   m_endTime = endTime;
   m_slippage = slippage;
   m_isActive = false;
   
   m_avgExecutionPrice = 0.0;
   m_totalOrders = 0;
   m_filledOrders = 0;
}

//+------------------------------------------------------------------+
//| デストラクタ|
//+------------------------------------------------------------------+
CExecutionAlgorithm::~CExecutionAlgorithm()
{
   // 必要に応じてリソースをクリーンアップする
}

//+------------------------------------------------------------------+
//| アルゴリズムの初期化|
//+------------------------------------------------------------------+
bool CExecutionAlgorithm::Initialize()
{
   // 入力を検証する
   if(m_symbol == "" || m_totalVolume <= 0.0)
   {
      Print("Invalid inputs for execution algorithm");
      return false;
   }
   
   // シンボルが存在するかチェックする
   if(!SymbolSelect(m_symbol, true))
   {
      Print("Symbol not found: ", m_symbol);
      return false;
   }
   
   // 統計をリセットする
   m_executedVolume = 0.0;
   m_remainingVolume = m_totalVolume;
   m_avgExecutionPrice = 0.0;
   m_totalOrders = 0;
   m_filledOrders = 0;
   
   return true;
}

//+------------------------------------------------------------------+
//| シンボルの適切な充填モードを取得する。
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE_FILLING CExecutionAlgorithm::GetFillingMode()
{
   // シンボルの充填モードを取得する
   int filling_modes = (int)SymbolInfoInteger(m_symbol, SYMBOL_FILLING_MODE);
   
   // 利用可能な充填モードを優先順にチェックする
   if((filling_modes & SYMBOL_FILLING_FOK) == SYMBOL_FILLING_FOK)
      return ORDER_FILLING_FOK;
   else if((filling_modes & SYMBOL_FILLING_IOC) == SYMBOL_FILLING_IOC)
      return ORDER_FILLING_IOC;
   else
      return ORDER_FILLING_RETURN;
}

//+------------------------------------------------------------------+
//| 注文する|
//+------------------------------------------------------------------+
bool CExecutionAlgorithm::PlaceOrder(ENUM_ORDER_TYPE orderType, double volume, double price = 0.0)
{
   // 入力を検証する
   if(volume <= 0.0)
   {
      Print("Invalid order volume");
      return false;
   }
   
   // リクエストを準備する
   MqlTradeRequest request;
   MqlTradeResult result;
   ZeroMemory(request);
   
   request.symbol = m_symbol;
   request.volume = volume;
   request.type = orderType;
   request.deviation = m_slippage;
   request.magic = 123456; // 識別のためのマジックナンバー
   
   // 注文の種類に応じて、適切なアクションと価格を設定する。
   if(orderType == ORDER_TYPE_BUY || orderType == ORDER_TYPE_SELL)
   {
      // 市場注文
      request.action = TRADE_ACTION_DEAL;
      request.type_filling = GetFillingMode();
      
      if(orderType == ORDER_TYPE_BUY)
         request.price = SymbolInfoDouble(m_symbol, SYMBOL_ASK);
      else
         request.price = SymbolInfoDouble(m_symbol, SYMBOL_BID);
   }
   else
   {
      // 未決注文
      request.action = TRADE_ACTION_PENDING;
      if(price <= 0.0)
      {
         Print("Price must be specified for pending orders");
         return false;
      }
      request.price = price;
   }
   
   // 注文を送信する
   if(!OrderSend(request, result))
   {
      Print("OrderSend error: ", GetLastError());
      return false;
   }
   
   // 結果をチェックする
   if(result.retcode != TRADE_RETCODE_DONE)
   {
      Print("OrderSend failed with code: ", result.retcode, " - ", result.comment);
      return false;
   }
   
   // 統計を更新する
   m_totalOrders++;
   
   // 成行注文の場合、即座に執行統計を更新する
   if(orderType == ORDER_TYPE_BUY || orderType == ORDER_TYPE_SELL)
   {
      m_filledOrders++;
      UpdateAverageExecutionPrice(request.price, volume);
      m_executedVolume += volume;
      m_remainingVolume -= volume;
   }
   
   Print("Order placed successfully. Ticket: ", result.order, " Volume: ", volume, " Price: ", request.price);
   
   return true;
}

//+------------------------------------------------------------------+
//| 既存の注文を変更する|
//+------------------------------------------------------------------+
bool CExecutionAlgorithm::ModifyOrder(ulong ticket, double price, double sl, double tp)
{
   // リクエストを準備する
   MqlTradeRequest request;
   MqlTradeResult result;
   ZeroMemory(request);
   
   request.action = TRADE_ACTION_MODIFY;
   request.order = ticket;
   request.price = price;
   request.sl = sl;
   request.tp = tp;
   
   // 修正リクエストを送信する
   if(!OrderSend(request, result))
   {
      Print("OrderModify error: ", GetLastError());
      return false;
   }
   
   // 結果をチェックする
   if(result.retcode != TRADE_RETCODE_DONE)
   {
      Print("OrderModify failed with code: ", result.retcode, " - ", result.comment);
      return false;
   }
   
   Print("Order modified successfully. Ticket: ", ticket);
   
   return true;
}

//+------------------------------------------------------------------+
//| 既存の注文をキャンセルする|
//+------------------------------------------------------------------+
bool CExecutionAlgorithm::CancelOrder(ulong ticket)
{
   // リクエストを準備する
   MqlTradeRequest request;
   MqlTradeResult result;
   ZeroMemory(request);
   
   request.action = TRADE_ACTION_REMOVE;
   request.order = ticket;
   
   // キャンセルリクエストを送信する
   if(!OrderSend(request, result))
   {
      Print("OrderCancel error: ", GetLastError());
      return false;
   }
   
   // 結果をチェックする
   if(result.retcode != TRADE_RETCODE_DONE)
   {
      Print("OrderCancel failed with code: ", result.retcode, " - ", result.comment);
      return false;
   }
   
   Print("Order cancelled successfully. Ticket: ", ticket);
   
   return true;
}

//+------------------------------------------------------------------+
//| 平均約定価格の更新|
//+------------------------------------------------------------------+
void CExecutionAlgorithm::UpdateAverageExecutionPrice(double price, double volume)
{
   // 新しい平均執行価格を計算する
   if(m_executedVolume > 0.0)
   {
      // 新旧価格の加重平均
      m_avgExecutionPrice = (m_avgExecutionPrice * m_executedVolume + price * volume) / 
                           (m_executedVolume + volume);
   }
   else
   {
      // 最初の実行
      m_avgExecutionPrice = price;
   }
}
//+------------------------------------------------------------------+