开发一个跨平台网格 EA(基础篇)
📘

开发一个跨平台网格 EA(基础篇)

第 1/3 篇

「在 MT5 上搭一个跨平台网格 EA 的骨架」

网格策略的核心是把仓位按价格间距铺开:价格每偏离一个步长就补一单,回摆时靠价差平仓。MT5 相比 MT4 的优势在于原生支持多品种、多周期同时跑,这对跨平台网格很关键。 原文作者 Roman Klymenko 在 2019 年 5 月 15 日发布该思路,截至统计时点获 9239 次浏览、27 条讨论,说明这类基础架构在实盘圈一直有稳定需求。 开 MT5 后先建一个 EA 框架,用 CTrade 类下单,用 PositionSelect 遍历同品种持仓来计算网格层级,比自己维护数组更稳。外汇与贵金属杠杆高,网格在单边行情里会快速放大敞口,回测时务必把 2015 年瑞郎黑天鹅这类极端段拉进来跑一遍。

为什么要把 EA 写成 MT4/MT5 通吃

很多老手都遇到过这类尴尬:现在用的经纪商给开 MT5 账户,MQL5 写起来顺手,但万一哪天换到只支持 MT4 的平台,之前攒的一堆 EA 就得推倒重写成 MQL4,时间成本极高。 外汇和贵金属杠杆交易本身高风险,平台政策变动、账户类型切换都可能发生,把策略锁死在单一终端并不划算。 更合理的做法是开发一套能在 MetaTrader 5 与 MetaTrader 4 同时跑的 EA,本文就尝试走这条路,并顺带验证基于订单网格的交易系统在两端的可用性。

◍ 关于条件编译的几句话

条件编译 将允许我们开发一个同时在 MetaTrader 4 和 MetaTrader 5 中工作的EA。应用的语法如下: 条件编译允许我们指定只有在MQL5 EA中完成编译时才应编译某个块。在MQL4和其他语言版本中编译时,只需丢弃此代码块,而是使用 #else 运算符后的代码块(如果已设置)。 这样,如果在 MQL4 和 MQL5 中实现了不同的功能,那么我们将以两种方式实现它,而条件编译允许选择特定语言所必需的选项。 在其他情况下,我们将使用在MQL4和MQL5中都有效的语法。

MQL5 / C++
&nbsp;&nbsp; <span class="preprocessor">class="macro">#ifdef </span><span class="macro">__MQL5__</span> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">// MQL5 代码</span>
&nbsp;&nbsp; <span class="preprocessor">class="macro">#else 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">class=class="str">"cmt">// MQL4 代码</span>
&nbsp;&nbsp; <span class="preprocessor">class="macro">#endif </span>

「网格挂单的双向铺法」

网格 EA 的核心动作,是在当前价上下两侧按固定步距各挂一批限价单:上方第一单距现价一个 step,第二单再叠一个 step,下方对称铺开,每侧单数可自行设定。 趋势市里,买限价挂现价上方、卖限价挂现价下方;震荡市反过来,卖单在上方、买单在下方。这一步方向判断直接决定网格是顺势加仓还是抄底摸顶。 止损可加可不加。无止损时,所有浮亏浮盈仓位留着,直到整网净值摸到预设总盈利线,才一次性平掉持仓与残留限价单、重铺新网。 有止损获利时,靠价格单向移动让盈利单覆盖亏损单;无止损时,靠正确方向不断新开单摊薄——即便先被反方向扫单,只要后续转向,同方向更多仓位会把前面坑填平。外汇与贵金属杠杆高,无止损网格在单边行情里可能迅速放大穿仓风险。

无止损网格的盈利假设与潜在陷阱

最简单的网格 EA 不挂止损,核心思路是:价格向一个方向走迟早能回到利润区,哪怕首单方向错了。假设开局价格回调触发两笔反向单,随后转向主趋势,后续同向挂单累加后,初始浮亏可能在一定时间后翻正。 这种逻辑依赖一个前提——价格不会长期在区间内反复扫单。若价格先触一单、回抽触另一单、再转向触更远单,如此往复扩张网格距离,浮亏会随层数放大。外汇与贵金属为高杠杆高风险品种,这种反复扫单在震荡市中并非小概率。 原文抛出一个问题:上述来回扫远单的走势在实盘是否真的可能?打开 MT5 用 EURUSD 的 M15 历史数据跑一段 2023 年下半年的震荡行情,就能看到网格被推到 6 层以外的案例并不罕见。

◍ 从空模板搭出可交互的 EA 骨架

先别急着写策略,把 EA 的空壳跑通更实在。MT5 向导生成的标准模板只差一行 #property strict,补上之后同一份代码在 MQL4 环境里也可能编译通过,跨平台改起来省事。 模板里真正要留神的是 OnChartEvent()。按钮点击、图表交互全靠它接事件,参数里的 id 区分事件类型,lparam / dparam / sparam 分别承载长整型、双精度与字符串信息。后面做『全部关闭』按钮,就是在这里捕获单击后遍历持仓和挂单。 下面这段骨架已经把初始化、去初始化、 tick 驱动和图表事件四个入口留好。OnInit 返回 INIT_SUCCEEDED 表示加载成功,OnTick 暂时空着等塞逻辑,OnChartEvent 的四个参数先注释清楚,免得回头接按钮时搞混类型。 外汇与贵金属杠杆高,EA 一旦误触平仓可能瞬间放大回撤,模板阶段就要想好人工干预的出口。

MQL5 / C++
class="macro">#class="kw">property copyright "Klymenko Roman(needtome@icloud.com)"
class="macro">#class="kw">property link      "[MQL5官方文档]
class="macro">#class="kw">property version   "class="num">1.00"
class="macro">#class="kw">property strict
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| EA 交易初始化函数                                                  |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
class=class="str">"cmt">//---
   
class=class="str">"cmt">//---
   class="kw">return(INIT_SUCCEEDED);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| EA 交易去初始化函数                                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnDeinit(const class="type">int reason)
  {
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| EA交易分时函数                                                    |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
  {
  }
class="type">void OnChartEvent(const class="type">int id,      class=class="str">"cmt">// 事件 ID
                  const class="type">long& lparam,  class=class="str">"cmt">// 长整型的事件参数
                  const class="type">class="kw">double& dparam, class=class="str">"cmt">// 双精度浮点型的事件参数
                  const class="type">class="kw">string& sparam) class=class="str">"cmt">// 字符串类型的事件参数
  {
  }

常见问题

先建一个空EA文件,用条件编译区分平台,把公共参数和双向挂单逻辑写成通用函数,再逐步接入口径一致的订单管理。
以当前价为中轴,按固定间距向上向下各挂一批挂单,用步长和层数控制密度,每层独立记录ticket避免重复补单。
可以,把EA代码或参数贴给小布,它能指出条件编译遗漏、无止损敞口过大等隐患,并给出改法建议。
假设价格均值回归持续收割价差,但单边行情会累积巨量浮亏,保证金耗尽即强平,外汇贵金属属高风险务必控仓。
条件编译让同一份源码按平台切换API,避免维护两份逻辑漂移,改一处即可两边同步,省事且不易出错。