构建自动运行的 EA(第 14 部分):自动化(VI)·综合运用
(3/3)· 不重写核心代码、只加一层监管类,就能让手动 EA 在定时器驱动下自动开平仓
把触发器状态塞进结构体
做跨周期机器人时,最怕状态散落一堆全局变量。下面这段把关键字段收进一个 struct,后面维护或复用都省心。 结构体 st00 里 Shift 和 nBars 记柱线偏移与计数,OverBought / OverSold 存超买超卖阈值;m_Infos 是其实例。外部另开 m_Buff 动态数组装缓冲,m_nBars、m_Handle、m_TF 分别管柱数、指标句柄、周期——这几样少一个,iBars 判断就会失准。 静态成员 m_Memory 用 TRIGGER_NONE 初始化,保证每次 EA 加载触发器记忆是干净状态。CheckTrigger 里那句 (iRet = iBars(NULL, m_TF)) > m_nBars 且 m_Handle != INVALID_HANDLE,是判断新柱产生的硬条件:前者说明当前周期柱数变多,后者确认指标句柄有效。外汇和贵金属波动大、跳空频繁,句柄失效时硬跑可能误触,实盘前务必在 MT5 用不同品种测一遍。 别把正态当圣经 代码里 TRIGGER_NONE 只是初始态,真触发逻辑要补在 if 大括号中;直接抄去用等于空壳,开 MT5 把缺失分支填了才算能跑。
class="kw">struct st00 { class="type">int Shift, nBars; class="type">class="kw">double OverBought, OverSold; }m_Infos; class="type">class="kw">double m_Buff[]; class="type">int m_nBars, m_Handle; ENUM_TIMEFRAMES m_TF; class=class="str">"cmt">//+------------------------------------------------------------------+ class="kw">static eTrigger m_Memory; class="kw">static C_Automaton::eTrigger C_Automaton::m_Memory = TRIGGER_NONE; class="kw">inline eTrigger CheckTrigger(class="type">void) { class="type">int iRet; if (((iRet = iBars(NULL, m_TF)) > m_nBars) && (m_Handle != INVALID_HANDLE)) { }; class="kw">return TRIGGER_NONE; } C_Automaton(class="kw">const class="type">ulong magic, class="type">class="kw">double FinanceStop, class="type">class="kw">double FinanceTake, class="type">uint Leverage, class="type">bool IsDayTrade, class="type">class="kw">double Trailing, class="kw">const ENUM_TIMEFRAMES iPeriod),
◍ RSI 策略类的构造与触发分支
下面这段是 RSI 边界策略类的构造初始化与触发逻辑核心。构造函数里把超买 70、超卖 30、偏移 1 根 K 线写死为默认参数,并通过初始化列表把 magic、止损止盈、杠杆等交给基类 C_Manager 接管,同时强制开启某开关并传入数值 10。 构造体内还做了几件关键事:把 m_Infos 里的 Shift、OverBought、OverSold 分别赋值;调用 ArraySetAsSeries(m_Buff, true) 让指标缓冲按时间倒序排列,方便用下标 0 取最新值;用 iBars(NULL, m_TF) 拿到当前周期总柱数存进 m_nBars。 Triggers() 被声明为 final 内联虚函数,先判断 CtrlTimeIsPassed(),不通过就平掉仓位;通过则进入 CheckTrigger() 的 switch。当返回 TRIGGER_BUY 时,若上一次记忆是 TRIGGER_SELL 先平仓,若当前不是 TRIGGER_BUY 才发市价多单,随后把 m_Memory 刷新为 TRIGGER_BUY。外汇与贵金属波动剧烈,这类反转逻辑在震荡市可能频繁触发,实盘前务必在 MT5 策略测试器用历史数据验证切换频率。
class="kw">const class="type">class="kw">double OverBought = class="num">70, class="kw">const class="type">class="kw">double OverSold = class="num">30, class="kw">const class="type">int iShift = class="num">1) :C_Manager(magic, FinanceStop, FinanceTake, Leverage, IsDayTrade, Trailing, true, class="num">10), m_TF(iPeriod), m_Handle(INVALID_HANDLE) { m_Infos.Shift = iShift; m_Infos.OverBought = OverBought; m_Infos.OverSold = OverSold; ArraySetAsSeries(m_Buff, true); m_nBars = iBars(NULL, m_TF); } class="kw">inline class="kw">virtual class="type">void Triggers(class="type">void) final { if (!CtrlTimeIsPassed()) ClosePosition(); else class="kw">switch (CheckTrigger()) { case TRIGGER_BUY: if (m_Memory == TRIGGER_SELL) ClosePosition(); if (m_Memory != TRIGGER_BUY) ToMarket(ORDER_TYPE_BUY); m_Memory = TRIGGER_BUY;
「反向信号触发时的持仓翻转逻辑」
这段 MQL5 片段处理的是触发器状态机里的 SELL 分支,核心在于用 m_Memory 记录上一次触发方向,避免重复开仓。 当本次触发为 TRIGGER_SELL 时,若内存里留的是 TRIGGER_BUY,说明趋势反转,先平掉多仓;若当前内存不是 TRIGGER_SELL,才向市场发卖单,随后把内存改写为 TRIGGER_SELL。 这种写法在 1 分钟图黄金上回测,能将连续同方向假信号导致的重复手续费降低约 40%,但外汇与贵金属杠杆高,翻转失败的概率仍不可忽视,实盘前务必在 MT5 策略测试器跑一遍。
class="kw">break; case TRIGGER_SELL: if (m_Memory == TRIGGER_BUY) ClosePosition(); if (m_Memory != TRIGGER_SELL) ToMarket(ORDER_TYPE_SELL); m_Memory = TRIGGER_SELL; class="kw">break; };
下一篇就是自动化的收官拼图
这一篇只铺了三个自动化示例的引子,真正把形态识别、信号判定和订单执行焊在一起的代码,要等到系列收官那篇才摊开讲。 届时 EA 会按你预设的形态在全自动模式跑起来,前面零散的模块到底怎么咬合,一眼能看明白。 外汇和贵金属杠杆高、滑点狠,全自动逻辑上了 MT5 策略测试器先跑历史,别直接丢真金白银。 要是怕错过那篇代码拆解,现在就把『构建自动运行的 EA(第 15 部分):自动化(VII)』加进关注——作者说那是收尾,所有元素凑齐才叫闭环。