文章 "MQL5 中的高级订单执行算法:TWAP、VWAP 和冰山订单"

 

新文章 MQL5 中的高级订单执行算法:TWAP、VWAP 和冰山订单已发布:

MQL5 框架通过统一的执行管理器和性能分析器,将机构级执行算法(TWAP、VWAP、冰山订单)带给散户交易者,从而实现更流畅、更精确的订单切片和分析。

“当然,”你可能会耸耸肩,“但我经手的又不是机构资金。”关键是:你完全不必这么做。无论你投入半手还是少量迷你手,波动性仍然会影响你的执行。这些工具可以帮助您:

  • 驯服滑点:即使是数额不大的订单,在震荡的市场中也可能出现波动。
  • 磨砺你的锋芒:分层执行往往会让你获得比一次性赌博更有利的平均价格。
  • 保持禅意:自动化的工作流消除了恐慌性买入或恐慌性卖出的诱惑。
  • 无缝扩展:随着账户的增长,无论订单金额有多大,您的执行都能保持高效。
  • 低调行事:特别是冰山订单,可以隐藏您的真实订单规模,让窥探的算法难以猜测。

如今的民主化环境意味着,曾经需要数百万美元预算的执行技术现在可以在你的个人交易站上运行。通过将完善的 MQL5 代码(用于 TWAP、VWAP 和 Iceberg 策略)添加到您的平台中,您将拥有机构级的强大火力 —— 而无需离开散户领域。


作者:N Soumik

 

好文章!

您推荐哪些货币对适用于该算法?

哪些时间框架?M5、M30 等。

哪个时段?

谢谢,并致以诚挚的问候

 
在 ExecutionAlgorithm.mqh 文件中,在下单时添加了 request.type_filling = ORDER_FILLING_IOC;一行,以解决下单问题。 在 H1 上进行了测试,它从未应用 SL 或 TP,所有交易都以亏损收盘。 在编译时还会产生警告




从 "多头 "到 "双头 "的类型转换可能 导致数据丢失 VWAP.mqh 271 41
从 "长 "到 "双 "的类型转换可能导致数据丢失 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
从 "长 "到 "双 "的类型转换可能导致数据丢失 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
从 "长 "到 "双 "的类型转换可能导致数据丢失 VWAP.mqh 272 22
从 "long "到 "double "的类型转换可能导致数据丢失 VWAP.mqh 449 17
从 "long "到 "double "的类型转换可能导致数据丢失 PerformanceAnalyzer.mqh 222 17
从 "long "到 "double "的类型转换可能导致数据丢失 ExecutionManager.mqh 418 17


建议如何测试算法、
时间框架以及任何其他建议。

警告不是问题所在,但可以很快解决。不过,如果作者能逐步说明他在回溯测试中使用了哪些设置和输入,那就再好不过了。

 

我同意 Dominic 的观点,因为警告只是警告。 I_Virgo 的结果可能是因为他使用了错误的时间框架和货币对。 从回溯测试报告来看,在近 2000 个条形图中,时间框架一定是 M1 或 M5,货币对不明。

如果 MQ 能在回溯测试报告中添加时间框架和货币对,并将货币对结果更详细地分开,那就更好了,这样我们就能更接近地复制作者的回溯测试结果,并确定其对外汇货币对的适用性。 此外,如果 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;
   }
}
//+------------------------------------------------------------------+