MQL5 向导未平仓位追踪模块:从基类结构吃透自定义追踪逻辑(基础篇)
(1/3)· 多数交易者直接套用标准追踪类,却说不清 CExpertTrailing 到底向 EA 暴露了哪些接口
本文是 MQL5 向导追踪模块系列的第一部分,聚焦未平仓位追踪模块的编写原则与基类结构。后续两篇将分别进入实战封装与向导集成,本篇先把骨架和接口讲透,避免后面写自定义类时反复返工。
◍ 用向导搭一个未平仓位追踪模块
MT5 的 MQL5 向导能直接生成 EA 骨架,省去从零写事件循环的麻烦。2013 年底上线的这套向导模板,至今在官方示例库里被下载 referenced 三千四百次以上,说明手动追踪仓位的需求一直很实在。 想在 EA 里盯住未平仓位做追踪,核心是把 PositionGetTicket 遍历出来的持仓单,逐个挂上 trailing stop 逻辑。外汇和贵金属杠杆高,追踪止损设太紧容易被噪音扫掉,设太宽又吃不到趋势,参数得自己按品种波动率调。 向导生成后,重点看 OnTick 里有没有调用 CTrade 或自定义追踪函数;没有就补一段遍历持仓并修改 SL 的代码,下节会拆具体写法。
「EA 自动生成的四个基类骨架」
想在 MT5 里不写一行框架代码就验证策略,MQL5 向导的策略生成器是最快的入口。它把一套可扩展的基类开放出来,你只要补自己的信号、资金、追踪类,就能拼出能跑的 EA。 向导产出的机器人核心就是 CExpert(或其子类),它本身是个引擎,内部持有三个关键子类的实例:CExpertSignal 负责给入场信号和保护单水平,CExpertMoney 算开仓手数,CExpertTrailing 专门盯未平仓位并提示要不要挪保护单。注意,这三类都只给“建议”,最终下单和修改决定仍由 CExpert 拍板。 除了上述三者,CExpert 还挂着 CExpertTrade(执行)、CIndicators(指标管理)、CSymbolInfo、CAccountInfo、CPositionInfo、COrderInfo 这一串成员。读官方文档时说的“EA 交易”通常就是指 CExpert 实例本身。 外汇和贵金属杠杆高、滑点跳空频繁,用向导拼出的 EA 先在策略测试器用历史数据跑一遍,别直接上实盘。
追踪止损模块的基类骨架
在 MT5 的 EA 架构里,CExpertTrailing 是所有追踪未平仓位逻辑的父类。它只暴露一组 public 的虚方法,子类通过重写这些接口来对接具体策略,外界不直接碰内部状态。 初始化阶段有三个虚函数要留意:Init 负责把 EA 的运行参数同步进模块实例;ValidationSettings 做参数合法性校验,避免乱设步长导致订单被拒;InitIndicators 则创建并初始化后续算信号要用的指标和时间序列。 真正产生动作的是两个信号函数。CheckTrailingStopLong 针对多单返回修改信号并算出新止损价,CheckTrailingStopShort 对空单做同样的事。实盘里若想改追踪逻辑,直接继承这个类重写这两个方法即可,不用动底层下单代码。外汇与贵金属杠杆高,追踪止损只减浮亏不保盈利,回测通过也不代表实盘概率占优。
◍ 跟踪止损基类的方法骨架
在 MT5 标准库里,CExpertTrailing 作为跟踪止损逻辑的基类,把生命周期拆成了几个虚方法。实例挂进 EA 后,Init() 会被自动触发,且不需要你去重写——它只做最基础的绑定。 参数就绪后 EA 会调 ValidationSettings()。基类本身没有可设参数,所以永远返回 true;但只要你派生出带参数的子类,就必须覆写这个函数,非法配置要返回 false,否则 EA 会继续跑一套无效设置。 指标类的准备放在 InitIndicators()。基类不碰任何指标或时间序列,因此原样返回 true。实际策略若依赖均线或 ATR,要在这里 new 出标准库指标,并把指针塞进 EA 的 CIndicators 集合,任一步失败就返回 false。 真正产生调仓信号的是 CheckTrailingStopLong / CheckTrailingStopShort。基类两者都直接返回 false,意味着不覆盖就永远不跟损。覆写时要把新止损(及可能的止盈)写进引用参数 sl、tp,条件不满足则回 false。外汇与贵金属杠杆高,跟损逻辑失效可能放大回撤,上机前建议在策略测试器用真实点差验证。
class="kw">virtual class="type">bool Init(CSymbolInfo* symbol, ENUM_TIMEFRAMES period, class="type">class="kw">double adjusted_point); class="kw">virtual class="type">bool ValidationSettings(); class="kw">virtual class="type">bool InitIndicators(CIndicators* indicators); class="kw">virtual class="type">bool CheckTrailingStopLong(CPositionInfo* position,class="type">class="kw">double& sl,class="type">class="kw">double& tp) class="kw">virtual class="type">bool CheckTrailingStopShort(CPositionInfo* position,class="type">class="kw">double& sl,class="type">class="kw">double& tp)
「把无损追踪模块挂进MT5向导」
想让EA在价格朝有利方向跑出一段距离后把止损推到保本,最干净的做法是写一个派生自CExpertTrailing的类,覆盖CheckTrailingStopLong和CheckTrailingStopShort两个虚函数。算法本身不复杂:当仓位盈利点数超过设定阈值、且止损还没被推过,就发出移损信号。 文件要放在Include\Expert\Trailing\MyTrailing\SampleTrailing.mqh,这样向导启动时才能扫到。类的受保护成员存两个参数——触发移损所需的盈利点数,以及锁定盈利的点数;Profit设0则整段逻辑不生效。
| 光放对位置不够,MQL5向导靠注释块里的类描述符认人。开头必须是//+------------------------------------------------------------------+,随后用// | Title=... | 写显示名,// | Type=signal | 标类型,// | Name=... | 给全局变量短名,// | Class=类名 | 必须和代码里的class一字不差,参数行按// | Parameter=方法名,类型,默认值 | 列,最后以//+------------------------------------------------------------------+收尾。 |
|---|
改完记得重启MetaEditor,向导只在启动那次扫Include目录。之后在策略生成器里就能选你的模块,输入参数直接暴露给EA。用策略测试器跑几组参数,可能比拍脑袋设的默认值更贴合你做的品种——外汇和贵金属杠杆高,回测过关也只是概率优势,实盘仍可能因滑点吃掉保本位。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| SampleTrailing.mqh | class=class="str">"cmt">//| Copyright class="num">2010, MetaQuotes Software Corp. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Copyright class="num">2010, MetaQuotes Software Corp." class="macro">#class="kw">property link "[MQL5官方文档] class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| defines | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">// class="macro">#define MacrosHello "Hello, world!" class=class="str">"cmt">// class="macro">#define MacrosYear class="num">2010 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| DLL imports | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">// class="macro">#class="kw">import "user32.dll" class=class="str">"cmt">// class="type">int SendMessageA(class="type">int hWnd,class="type">int Msg,class="type">int wParam,class="type">int lParam); class=class="str">"cmt">// class="macro">#class="kw">import "my_expert.dll" class=class="str">"cmt">// class="type">int ExpertRecalculate(class="type">int wParam,class="type">int lParam); class=class="str">"cmt">// class="macro">#class="kw">import class=class="str">"cmt">//+------------------------------------------------------------------+