请 [注册] 或 [登录]  | 返回主站

量化交易吧 /  源码分享 帖子:3365773 新帖:5

用于在以仓位为中心的 MetaTrader 5 环境中跟踪订单的虚拟订单管理程序

外汇老老法师发表于:4 月 17 日 17:10回复(1)

1. 简介

可以论证,在从 MetaTrader 4 到 MetaTrader 5 的转变中最大的变化是作为仓位的建仓交易的管理。在任何时候,每个交易品种都只能有一个未平仓位,并且此仓位的大小在经纪人每次处理订单时都增大或减小。这符合在美国施行的 NFA 2-43(b) 先入先出原则,并且也符合在期货、商品和 CFD 等很多其他实体中的交易模型。

两个针对相同交易品种的 EA 在相对方向发布订单就是一个明显的区别例子。对于在不同时间段工作的两个 EA,例如投机交易程序和趋势关注程序,这是一种普遍的情形。在 MetaTrader 4 中,建仓交易列表会使用零边际显示买入和卖出建仓订单。在 MetaTrader 5 中,仓位根本不会处于未平仓的状态。

看一看 EA 代码本身,以下常用的 MQL4 OpenOrders() 等函数,或者类似的变体,在迁移到 MQL5 后将不会按预期工作。

int OpenOrders()  // 为EA交易计算持仓总数的 MetaTrader 4 代码
{
  int nOpenOrders=0;
  for (int i=OrdersTotal()-1; i>=0; i--)
  {
    OrderSelect(i,SELECT_BY_POS,MODE_TRADES);
    if (OrderMagicNumber()==magic)
      if (OrderType()==OP_BUY || OrderType()==OP_SELL)
        if (OrderSymbol()==Symbol())
          nOpenOrders++;
  }
  return(nOpenOrders);
}

因此,MetaTrader 5 以仓位为中心的环境向使用在 MetaTrader 4 中所用订单处理方法的程序员带来了不熟悉的挑战。当多个订单能够合并到一个仓位,例如多个 EA 在一个交易品种上交易,或来自一个 EA 的多个订单处理一个交易品种时,在 MetaTrader 4 中简单的订单管理函数在 MetaTrader 5 中变得更加复杂。


2.在 MetaTrader 5 中处理仓位的方式

视交易策略的复杂性而定,有若干方式来管理 MetaTrader 5 中这种以仓位为中心的环境。

首先,注意 MetaTrader 5 处理挂单的方式与 MetaTrader 4 类型,因此为挂单编写的 MQL5 代码能够相对简单地从 MQL4 代码移植。

2.1 直接 EA;每个帐户每个交易品种一个 EA

最简单的方法是将一个帐户上的交易限制为每个交易品种一个直接 EA。这种情况下的“直接 EA”指一次只发布一个单一订单的 EA,这是一种普通方法,但不包括金字塔和网格交易等策略。或许可以使用包含在 include\trade\trade.mqh 中的 CTrade 库包装,用与 MQL4 类似的方法以 MQL5 编写直接 EA。

2.2 复杂 EA;每个帐户每个交易品种一个 EA

对于复杂 EA,例如具有金字塔或网格交易等策略的 EA,对于一个交易品种能够要求多个建仓订单,添加到 EA 的某些相对简单的订单跟踪代码可能就是管理策略所需的一切。这只有在 EA 不会与交易相同品种的另一 EA 共用仓位时才有可能。

2.3 每个帐户每个交易品种有多个任意类型的 EA

这提出了最复杂的交易和代码编写要求,并且也是开发 Virtual Order Manager (虚拟订单管理程序,VOM)库的原因。该库旨在大大简化能够与其他 EA 完全通信的稳定 EA 代码的开发。

本文的余下部分将详细说明虚拟订单管理程序库。


3. 虚拟订单管理程序的设计目标、优点和缺点

VOM 具有四个主要的设计目标:

  1. 社交性:使用 VOM 交易函数正确编写的 EA 的行为将被与其他 EA 的活动分隔开来
  2. 稳定性:极好地处理异常事件,例如错误、客户端-服务器通信中断和不完整的订单填写。
  3. 易用性:提供具有完整说明并且使用简单的交易功能
  4. 能够在策略测试程序中使用

通过以下方式实现这些目标:

  • 使用虚拟建仓订单、挂单、止损和获利。在本语境中的“虚拟”指它们的状态在客户端上独立于服务器上的仓位维持。这些订单在客户端上呈水平线,类似于仓位
  • 一个基于服务器的保护性止损与虚拟止损有一定的差异,防止在 PC 或互联网连接发生故障时出现灾难性问题

VOM 方法允许 MQL5 EA 程序员:

  • 用一种“以订单为中心”的方式编写 EA 代码,类似于 the MetaTrader 4 方法
  • 实施 Metatrader 社区中的很多人所称的“对冲交易”,更为精确地说,即在单个交易品种的两个方向同时交易 
  • 相对容易地编写其他先进交易策略的代码,例如网格交易、金字塔交易和资金管理方法
  • 发布比最低止损水平更紧的挂单

还应注意,VOM 方法的副作用是其虚拟止损、获利和挂单在本质上具有“秘密”行为,即在经纪人服务器上看不到它们。为了防止经纪人能够猎杀止损,隐藏止损水平从而避免被某些人看到是必需的。

VOM 也有缺点。由于在 PC 或互联网连接出现长时间故障时有可能依赖更远的保护性服务器,资产净值的风险增大。  同样,命中虚拟挂单、止损或获利时的最大允许滑点数在新闻事件等造成的大波动期间也会比基于服务器的最大允许滑点数大很多。如果 VOM EA 是从到经纪人服务器的响应时间很短的可靠虚拟台式机进行交易的,则可以很大程度地减少这些缺点的影响。


4. 实践中的 VOM – 一个简单的 EA

在继续之前,是说明如何编写 VOM EA 的时间了。我们将从在发行包中提供的 EA 模板开始编写一个简单移动平均线交叉 EA。我们将使用“分形移动平均线”,有可能减少市场横向盘整期间的无意义交易,而这正是移动平均线交叉策略的一个非常不好的问题。应该强调,此 EA 作为一个简单的例子提供,并不建议用于实时交易 – 篮子可盈利,但是交易次数少意味着结果在统计学上并没有意义。

该 EA 存储在 experts\Virtual Order Manager\VOM EAs 中。

//+------------------------------------------------------------------+
//|                                           FraMA Cross EA VOM.mq5 |
//+------------------------------------------------------------------+
#property copyright "Paul Hampton-Smith"
#property link      "http://paulsfxrandomwalk.blogspot.com"
#property version   "1.00"

// 这是仅需的包含文件,它指向上一级文件夹
#include "..\VirtualOrderManager.mqh"

input double   Lots=0.1;
input int      Fast_MA_Period=2;
input int      Slow_MA_Period=58;
/* 
因为经纪商价格为3位或者5位小数,止损和获利值应该乘以10.  
看起来似乎所有支持MetaTrader 5的经纪商都是提供3/5位小数价格的, 
但是如果不是这样,还有一项重要工作即是增加 
小数位数的侦测. */
input int      Stop_Loss=5000;
input int      Take_Profit=0;
/*
我们也可以改变记录的级别.  LOG_VERBOSE 是最详细的 
记录级别.  当EA交易被完全调试好以后,它可以改为 
LOG_MAJOR.  记录文件位于 files\EAlogs 文件夹下并且会 
自动删除30天以前的记录文件.  */
input ENUM_LOG_LEVEL Log_Level=LOG_VERBOSE;

// 以下全局变量将保存移动平均(MA)的句柄和数值 
double g_FastFrAMA[];
double g_SlowFrAMA[];
int g_hFastFrAMA;
int g_hSlowFrAMA;
//+------------------------------------------------------------------+
//| EA初始化函数                                                       |
//+------------------------------------------------------------------+
int OnInit()
  {
   LogFile.LogLevel(Log_Level);

// 使用 CVirtualOrderManager 的所有EA交易都需要包含下面这一行  
   VOM.Initialise();
   Comment(VOM.m_OpenOrders.SummaryList());

   g_hFastFrAMA = iFrAMA(_Symbol,_Period,Fast_MA_Period,0,PRICE_CLOSE);
   g_hSlowFrAMA = iFrAMA(_Symbol,_Period,Slow_MA_Period,0,PRICE_CLOSE);
   ArraySetAsSeries(g_FastFrAMA,true);
   ArraySetAsSeries(g_SlowFrAMA,true);

   return(0);
  }
//+------------------------------------------------------------------+
//| EA订单函数                                                        |
//+------------------------------------------------------------------+
void OnTick()
  {
// 使用 CVirtualOrderManager 的所有EA交易都需要包含下面这一行  
   VOM.OnTick();
   Comment(VOM.m_OpenOrders.SummaryList());

// 现在我们取得 FrAMA 数值的最近两个拷贝, 
// 它们位于 g_FastFrAMA 和  g_SlowFrAMA 数组中.  
   if(CopyBuffer(g_hFastFrAMA,0,Shift,2,g_FastFrAMA)!=2) || 
      CopyBuffer(g_hSlowFrAMA,0,Shift,2,g_SlowFrAMA)!=2)
     {
      Print("载入的历史数据不足");
      return;
     }

// 现在我们侦测快速 FrAMA 和 慢速 FrAMA 的交叉,
// 关闭任何反向订单,新开一个买入订单
   if(g_FastFrAMA[0]>g_SlowFrAMA[0] && g_FastFrAMA[1]<=g_SlowFrAMA[1])
     {
      VOM.CloseAllOrders(_Symbol,VIRTUAL_ORDER_TYPE_SELL);
      if(VOM.OpenedOrdersInSameBar()<1 && VOM.OpenOrders()==0)
        {
         VOM.Buy(_Symbol,Lots,Stop_Loss,Take_Profit);
        }
     }

// 相反则卖出
   if(g_FastFrAMA[0]<g_SlowFrAMA[0] && g_FastFrAMA[1]>=g_SlowFrAMA[1])
     {
      VOM.CloseAllOrders(_Symbol,VIRTUAL_ORDER_TYPE_BUY);
      if(VOM.OpenedOrdersInSameBar()<1 && VOM.OpenOrders()==0)
        {
         VOM.Sell(_Symbol,Lots,Stop_Loss,Take_Profit);
        }
     }
  }
//+------------------------------------------------------------------+

现在可以使用发行的策略测试程序对其进行回测,请参阅下面的图 1:

图 1. FrAMA 交叉 EA 回测

图 1. FrAMA 交叉 EA 回测

图 2 显示了记录部分:

图 2. 策略测试记录

图 2. 策略测试记录

 

5. VOM 结构

下面的图 3 显示了如何配置多个 VOM EA:

图 3. 多个 VOM EA

图 3. 多个 VOM EA

再看一看 VOM 内部,下面的图 4 显示了主要的组件:

图 4. VOM 内部结构

图 4. VOM 内部结构

 以下解释图 4 的元素:

  • 配置 - VOM 使用 CConfig,在一个全局对象 Config 中将所有主要的配置项目存储在一个地方。为了使存取简单,成员变量是公共的,并且不提供 get/set 函数。
  • 全局变量 - 这些是在 MQL5 中通过 GlobalVariableGet() 等函数存取的变量。VOM 使用全局变量来进行以下操作: 
    • 使用 CGlobalVariable 记录和增大最新的虚拟订单单证编号
    • 维持所有虚拟止损的列表,从而能够维持灾难防护服务器止损
  • 建仓交易和历史记录文件 - 这些是由 CVirtualOrderArrays 存储的永久性磁盘文件,用于确保在重启时能够重建订单状态。可以在 Files\\VOM 中为每个使用 VOM 的 EA 创建和存储一对这样的文件。CVirtualOrder 在 VOM.m_OpenOrders 数组中诞生,并在被关闭或删除时转移到 VOM.m_OrderHistory 数组。
  • 活动和调试日志 - 大多数任意复杂的代码都需要能够记录活动,此功能封装在 CLog 类中。这样能够在四个不同的详细和重要级别记录活动,包含自动清除旧的日志文件以确保磁盘空间的管理。

与 VOM 库进行互动的 EA 如下面的图 5 所示:

图 5. 与 VOM 库进行互动的 EA

图 5. 与 VOM 库进行互动的 EA


6. 有关灾难防护止损的更多说明

虚拟止损在 MetaTrader 4 EA 中非常普遍。如果止损仅在客户端维持,则经纪人看不见交易的退出水平,这是认为某些经纪人会进行猎杀止损活动时经常实施的一个策略。靠他们自己,虚拟止损大大增加了交易风险,因为经纪人-客户连接必须始终存在才能让止损发生。 

VOM 通过将基于服务器的止损维持在离最紧虚拟止损一段可配置的距离来控制此风险。这被称为灾难防护止损 (DPSL),因为它通常仅在经纪人-客户连接中断一段时间后才发生,互联网连接中断或 PC 出现故障就是这样的情形。随着虚拟订单的建仓、平仓以及转换到服务器上的仓位,将 DPSL 维持在正确的级别可能有一点复杂,如以下序列所示。

虚拟订单
操作
建仓
价格
虚拟止损 服务器
上的仓位
服务器
上的止损
备注
0.1 手 买入 #1 2.00000 1.99000 0.1 手 买入 1.98500 DPSL 低于虚拟止损 #1 50 点
0.1 手 买入 #2 2.00000 1.99500 0.2 手 买入 1.99000 虚拟订单 #2 具有一个较紧的止损,因此 DPSL
收紧,低于虚拟止损 #2 50 点
平仓 #2     0.1 手 买入 1.98500 恢复到较松的 DPSL
0.1 手 卖出 #3 2.00000 2.00500 虚拟订单 #1 和 #3 在服务器上
相互取消
平仓 #1     0.1 手 卖出 2.01000 虚拟订单 #3 处于未平状态 - DPSL 现在
高于虚拟止损 #3 50 点

7. 测试虚拟订单管理程序

此规模的项目需要一定的时间才能彻底测试完毕,因此我写了 EA VirtualOrderManaerTester.mq5,允许用图上的命令按钮轻松创建、修改、删除和关闭虚拟订单。  

下面的图 6 在 M5 窗口中显示了一个买入 0.1 手的虚拟订单,在 H4 窗口中显示了买入另外 0.1 手建仓的虚拟订单,都是针对 EURUSD 的(见注释行),而服务器状态正确显示一个买入了 0.2 手的仓位。因为整体仓位是买入持仓,可以看到灾难防护止损低于较紧的 20 点止损。

图 6. 两个方向一致的 EA

图 6. 两个方向一致的 EA

图 7 现在显示两个具有相反虚拟订单的测试 EA,在经纪人处并没有建仓:

图 7. 两个具有相反虚拟订单的 EA,在经纪人处并没有建仓

图 7. 两个具有相反虚拟订单的 EA,在经纪人处并没有建仓


8. 所有 VOM 建仓订单的非常简单的显示

每个 VOM EA 只能看到其自己的订单,因此我写了一个非常简单的 EA 来收集来自所有 VOM 的建仓订单。显示非常简单,并且在时间允许时会编写一个更好的版本,或许用命令按钮依据需要对每个订单进行修改、删除或关闭操作。该 EA 作为 VOM_OrderDisplay.mq5 包含在发行包中。


9. 总结

在撰写本文时,VOM 代码处于 Beta 版本,正如 MetaTrader 5 本身一样,并且作为 MQL5 编程的令人感兴趣的一部分,时间将告诉我们 VOM 概念是变为流行还是终结。

让我们回顾一下第 3 节中的设计目标,看一看我们已经到了哪里

  1. 社交性:使用 VOM 交易函数正确编写的 EA 的行为将被与其他 EA 的活动分隔开来
    • 结果 - 是的,VOM 方法实现了此目标
  2. 稳定性:极好地处理异常事件,例如错误、客户端-服务器通信中断和不完整的订单填写。
    • 结果 - 有证据证明一定程度的稳定性,但是随着实际交易情形的发生以及对其进行的分析,应该还有改进之处 
  3. 易用性:提供具有完整说明并且使用简单的交易功能
    • 结果 - 如在文件发行包中所见,包含了一个 .chm 帮助文件
  4. 能够在策略测试程序中使用
    • 结果 - 在最近发布的策略测试程序中进行的初步测试表明 VOM 确实能通过回测,尽管 VOM 方法相当程度地延缓了测试。可能需要对生产能力进行某些改进工作。

将来还可能需要若干改变

  • 与任何复杂的软件开发一样,代码中可能仍然有错误之处
  • 对于每个 MetaTrader 5 Beta 发行版本,可能需要 VOM 改变保持兼容性
  • VomGetLastError() 和 VomErrorDescription() 函数
  • 能够从一个文件读取配置
  • 跟踪各类类型的止损


10. 压缩发行包中的文件

VOM 发行包含有若干 .mqh 文件,这些文件应安装在 Experts\Virtual Order Manager 文件夹中,

  • ChartObjectsTradeLines.mqh - CEntryPriceLine、CStopLossLine、CTakeProfitLine
  • StringUtilities.mqh - 全局枚举描述符,例如 ErrorDescription()
  • Log.mqh - CLog
  • GlobalVirtualStopList.mqh - CGlobalVirtualStopList
  • SimpleChartObject.mqh - CButton、CLabel 和 CEdit
  • VirtualOrder.mqh - CVirtualOrder
  • GlobalVariable.mqh - CGlobalVariable
  • VirtualOrderArray.mqh - CVirtualOrderArray
  • VirtualOrderManager.mqh - CVirtualOrderManager
  • VirtualOrderManagerConfig.mqh - CConfig
  • VirtualOrderManagerEnums.mqh - 为 VOM 定义的各种枚举
  • VOM_manual.mqh - 手册的这一页
  • VOM_doc.chm***

在 Experts\Virtual Order Manager\VOM EAs 中也包含五个 EA mq5 文件:

  • VOM_template_EA.mq5 - 克隆此文件以创建您自己的 EA,并且也将它们存储在 Experts\Virtual Order Manage\VOM EAs 中
  • VirtualOrderManagerTester.mq5
  • Support_Resistance_EA_VOM.mq5
  • FrAMA_Cross_EA_VOM.mq5
  • VOM_OrderDisplay.mq5 

***注意,VOM_doc.chm 文件可能需要解锁:

全部回复

0/140

量化课程

    移动端课程