重构经典策略(第十三部分):最小化均线交叉的滞后性(基础篇)
📘

重构经典策略(第十三部分):最小化均线交叉的滞后性(基础篇)

第 1/3 篇

「用同周期双均线掐掉交叉滞后」

传统均线交叉要靠长短周期差制造信号,但周期差本身就是滞后的根。我们之前对超过200个交易品种做过测试,机器更擅长预判均线未来值而非价格点位,顺着这个思路可以把滞后再压一层。 做法很直接:两条均线用相同周期,一条算在开盘价上,一条算在收盘价上。开盘价均线压在收盘价均线之上,说明该周期收盘价低于开盘价,价格倾向走弱;反过来收盘价均线在上,价格倾向走强。这样不需要长短周期错位也能出交叉。 这套框架不限于均线。RSI 同样可以分别挂在开盘、收盘、最高、最低价上独立计算;下跌趋势里跟踪开盘价的 RSI 往往会跑到跟踪收盘价的 RSI 上方,和双均线逻辑同构,可平移到别的指标做早信号。 外汇与贵金属波动大、杠杆高,这类同周期结构只降低信号延迟,不消除假交叉风险,上 MT5 用复盘比对一下普通交叉与本法的触发时点差异再决定参数。

◍ EURUSD四年回测的基准设定

先把传统双均线交叉当成基准策略,后面再拿重构后的思路跟它比优劣。今天所有讨论都用 EURUSD 做样本——它是全球成交最活跃的货币对,波动比大多数货币对都猛,恰恰不是简单交叉策略的舒服区。 我们锁定日线图,回测窗口为 2020-01-01 至 2024-12-24,约 4 年历史数据,在 MT5 月线图上能直接看到这段高亮区间。 原始策略就是两条跟踪收盘价的均线交叉:短周期线在长周期线上方,读作上升趋势可能延续;反之视为看跌。图里黄线快线、白线慢线,能看清基本逻辑。 但传统交叉有个硬伤——图里竖线左侧约两个月横盘,信号反复被打脸、大概率亏钱;直到右侧突破走出真趋势才扬眉吐气。它只在趋势市里好使,而后面要讲的策略正是冲着这种迟滞期来的。

先把均线交叉的骨架钉死

做一套可回测的均线交叉 EA,第一步不是调参数,而是把不该变的东西锁住。系统常量负责隔离逻辑改动带来的干扰:两次测试里止损倍数、交易量必须恒定,否则你分不清收益来自策略还是来自设置漂移。 全局变量盯三件事:指标句柄与缓冲、实时买卖价、K线 OHLC。事件驱动是 MT5 的底层机制——用户操作和新报价都会触发事件,每个事件配一个处理程序。OnInit 调 setup 加载指标,OnDeinit 调 release 释放资源,OnTick 调 update 刷最新价后再决定开仓或管仓。 入场规则极简:快线在慢线上方做多,反之下方做空。止损用 ATR 动态拉伸,入场价±ATR_MULTIPLE 倍 ATR 设止损止盈,并引入过去 90 天平均 ATR 衡量近期波动。三元运算符只在「新持仓比旧持仓更有利」时才更新止盈止损,逻辑紧凑且可独立调 TP/SL。 回测设置上,策略无 AI 无曲线拟合、无待调输入,Forward 设 No。用 Real ticks + Random delay 跑最严苛环境,EURUSD 从起测到 2022 年 7 月近 2 年都在盈亏平衡线挣扎,总亏损交易率约 61%,夏普比接近 0——原始形态不可直接托付资金,但稍调逻辑就可能显著改观。外汇与贵金属属高风险,回测不代表实盘概率。 下面这段是基准版常量与全局变量的骨架代码,开 MT5 新建 EA 把这部分贴进去就能跑通指标加载前的准备。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                                  Channel And MA.mq5 |
class=class="str">"cmt">//|                                                     Gamuchirai Zororo Ndawana |
class=class="str">"cmt">//|                                         [MQL5官方文档] |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Gamuchirai Zororo Ndawana"
class="macro">#class="kw">property link      "[MQL5官方文档]
class="macro">#class="kw">property version   "class="num">1.00"
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| System constants                                                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#define TF_1         PERIOD_D1 class=class="str">"cmt">//--- Our main time frame
class="macro">#define TF_2         PERIOD_H1 class=class="str">"cmt">//--- Our lower time frame
class="macro">#define ATR_PERIOD   class="num">14        class=class="str">"cmt">//--- The period for our ATR
class="macro">#define ATR_MULTIPLE class="num">3         class=class="str">"cmt">//--- How wide should our stops be?
class="macro">#define VOL          class="num">0.01      class=class="str">"cmt">//--- Trading volume
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Global variables                                                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int    trade;
class="type">int    ma_f_handler,ma_s_handler,atr_handler;
class="type">class="kw">double ma_f[],ma_s[],atr[];
class="type">class="kw">double bid,ask;
class="type">class="kw">double o,h,l,c;
class="type">class="kw">double original_sl;
class=class="str">"cmt">//+------------------------------------------------------------------+

「把指标句柄挂进生命周期」

EA 跑起来最先碰到的不是行情,而是句柄。把 iATR 与两条 iMA 的创建塞进 setup(),在 OnInit 里调用,MT5 会在加载时就把指标资源绑好,不至于每 tick 重复申请。 setup() 里固定了 10 周期与 60 周期两条 EMA(PRICE_CLOSE),快线慢线跨度 6 倍,在 EURUSD 的 M5 上这种组合对假突破的过滤概率倾向优于单均线。外汇与贵金属杠杆高,句柄泄漏会拖慢终端,必须重视释放。 OnDeinit 调用 release(),用 IndicatorRelease() 逐个交还 atr_handler、ma_f_handler、ma_s_handler。漏掉这一步,策略切换时 MT5 可能堆积几十个隐形指标,肉眼难查。 OnTick 目前只调 update(),真正的信号逻辑留在后续补。你开 MT5 新建 EA,把下面代码贴进文件,编译后挂图表,能在 Experts 日志看到初始化通过即说明句柄链通了。

MQL5 / C++
class="macro">#include <Trade\Trade.mqh>
CTrade Trade;
class="type">int OnInit()
  {
class=class="str">"cmt">//--- Setup
   setup();
class=class="str">"cmt">//---
   class="kw">return(INIT_SUCCEEDED);
  }
class="type">void OnDeinit(const class="type">int reason)
  {
class=class="str">"cmt">//--- Release our indicators
   release();
  }
class="type">void OnTick()
  {
class=class="str">"cmt">//--- Update system variables
   update();
  }
class="type">void setup(class="type">void)
  {
   atr_handler   = iATR(Symbol(),TF_1,ATR_PERIOD);
   ma_f_handler = iMA(Symbol(),TF_1,class="num">10,class="num">0,MODE_EMA,PRICE_CLOSE);
   ma_s_handler = iMA(Symbol(),TF_1,class="num">60,class="num">0,MODE_EMA,PRICE_CLOSE);
  }
class="type">void release(class="type">void)
  {
   IndicatorRelease(atr_handler);
   IndicatorRelease(ma_f_handler);
   IndicatorRelease(ma_s_handler);
  }
class="type">void update(class="type">void)
  {

常见问题

用同周期快慢两条均线,价格触及快线即预判交叉,不等实体穿叉确认,能把信号提前一根K线左右。
固定 timeframe 与均线周期、点差按经纪商实盘值、滑点设1~2点,样本覆盖涨跌震荡各段即可。
小布可实时标注快线触碰慢线瞬间并提示疑似交叉,省去你手动刷图等确认。
先钉死周期、双均线长度、交叉方向判定与手数规则,再写指标调用,结构不易崩。
挂生命周期只初始化一次,避免重复申请资源拖慢执行,退出时释放即可。