在MQL5中构建自优化智能交易系统(EA)(第五部分):自适应交易规则·综合运用
📘

在MQL5中构建自优化智能交易系统(EA)(第五部分):自适应交易规则·综合运用

第 3/3 篇

「宏定义用完后及时撤销」

在 MT5 的 Include 头文件或指标模块末尾,把临时宏常量统一 #undef 是避免命名污染的基本动作。上面这段代码在系统常量注释块之后,连续撤销了 RSI_PERIOD、RSI_PRICE、ATR_PERIOD、ATR_SIZE、TF_1、TF_2、VOL 共 7 个宏。 若不在文件尾做这步清理,其他 mqh 或 ea 再 #define 同名常量时,编译器可能直接报重定义错误,或者更隐蔽地沿用旧值。开 MT5 随便找一个自带指标的源码,搜 #undef 就能看到官方也是这套收尾逻辑。 外汇与贵金属品种波动属性差异大,这类周期类宏(TF_1/TF_2)若泄漏到多周期脚本里,可能让小周期误用大周期参数,实盘前务必确认作用域干净。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Undefine the system constants                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#undef RSI_PERIOD
class="macro">#undef RSI_PRICE
class="macro">#undef ATR_PERIOD
class="macro">#undef ATR_SIZE
class="macro">#undef TF_1
class="macro">#undef TF_2
class="macro">#undef VOL
class=class="str">"cmt">//+------------------------------------------------------------------+

用动态中点替换固定 70/30 后实盘回测差异

经典 RSI 的 50 中点和 70/30 超买超卖线,在个别品种上可能长期碰不到。做法是先扫一遍指标输出区间,把最高、最低两条平行线做二等分,这条线就是该市场自己的新中点,原版 50 水平仅作参照。 算出新中点后,记录每个 RSI 读数与中点的绝对差值并取平均,得到该市场平均波动幅度。只有当 RSI 变化达到这个平均幅度的两倍(BIG_SIZE=2)才允许触发,相当于把 EA 敏感度握在手里;若把倍数设成 100,基本就永远不会开仓。 支撑阻力改由当前价与 5 根周期前(SUPPORT_PERIOD=5,约一周)价格对比确定,不再写死在指标水平。开仓条件也从固定水平挪到指标内存缓冲区算出的动态水平。 下面这段系统常量就是改动的核心,BARS 取 M15 可用 K 线总数的一半向下取整,BIG_SIZE 控制波动强度门槛: 回测对比很直接:初始版 136 笔交易净利 588.60 美元,动态规则版 121 笔交易净利 703.20 美元。交易次数降约 11%,利润反升约 19.5%,在外汇与贵金属这类高杠杆高风险品种上,这种样本内优势只代表历史倾向,实盘仍需自测。

MQL5 / C++
class=class="str">"cmt">//+---------------------------------------------------------------+
class=class="str">"cmt">//| System constants                                                |
class=class="str">"cmt">//+---------------------------------------------------------------+
class="macro">#define RSI_PERIOD     class="num">10                                            class=class="str">"cmt">//The period for our RSI indicator
class="macro">#define RSI_PRICE      PRICE_CLOSE                                   class=class="str">"cmt">//The price level our RSI should be applied to
class="macro">#define ATR_SIZE       class="num">1.5                                           class=class="str">"cmt">//How wide should our Stop loss be?
class="macro">#define ATR_PERIOD     class="num">14                                            class=class="str">"cmt">//The period of calculation for our ATR indicator
class="macro">#define TF_1           PERIOD_D1                                     class=class="str">"cmt">//The primary time frame for our trading application
class="macro">#define TF_2           PERIOD_M15                                    class=class="str">"cmt">//The secondary time frame for our trading application
class="macro">#define VOL            class="num">0.1                                           class=class="str">"cmt">//Our trading volume  
class="macro">#define BARS(class="type">int) MathFloor((iBars(Symbol(),TF_2) / class="num">2))   class=class="str">"cmt">//How many bars should we use for our calculation?
class="macro">#define BIG_SIZE       class="num">2                                             class=class="str">"cmt">//How many times bigger than the average move should the observed change be?
class="macro">#define SUPPORT_PERIOD class="num">5                                             class=class="str">"cmt">//How far back into the past should we look to find our support and resistance levels?

◍ 用 RSI 偏离中轴抓次级周期反转

这段逻辑跑在比主周期更短的时间框架 TF_2 上,专门处理那些需要更快响应的临门一脚。它只在无持仓时寻找机会,避免来回加仓把账户拖进外汇或贵金属的高波动泥潭。 核心是先算 RSI 的「动态中轴」:取最近 BARS 根 K 线的 RSI 最大值与最小值取平均,再用 MathAbs 算每个值与中轴的距离向量 rsi_growth,取其均值作为常态偏离尺度。当实时 RSI 偏离中轴超过 rsi_growth.Mean() * BIG_SIZE 倍时,才认为偏离显著。 价格层面用 iLow / iHigh 碰阻力 support、resistance 做触发门槛:上方破阻力且 RSI 正向偏离够大就 Sell,下方破支撑且负向偏离够大就 Buy。止损止盈统一用 ATR_SIZE * atr[0] 对称展开,例如 ATR_SIZE=2 时上下各 2 倍 ATR。 别把正态当圣经:rsi_growth.Mean() 只是样本均值,BARS 设 50 还是 200 会直接改变触发灵敏度,建议在 MT5 里把 BARS 和 BIG_SIZE 拉成输入参数来回测不同品种。

MQL5 / C++
class="kw">static class="type">class="kw">datetime time_stamp;
 class="type">class="kw">datetime current_time = iTime(Symbol(),TF_2,class="num">0);
 class="type">class="kw">double bid,ask;
 class=class="str">"cmt">//Update the time
 if(time_stamp != current_time)
   {
    time_stamp = current_time;
    bid=SymbolInfoDouble(Symbol(),SYMBOL_BID);
    ask=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
    class=class="str">"cmt">//Copy the rsi readings into a vector
    vector rsi_vector   = vector::Zeros(BARS);
    rsi_vector.CopyIndicatorBuffer(rsi_handler,class="num">0,class="num">1,BARS);
    class=class="str">"cmt">//Let&class="macro">#x27;s see how far the RSI tends to deviate from its centre
    class="type">class="kw">double rsi_midpoint = ((rsi_vector.Max() + rsi_vector.Min()) / class="num">2);
    vector rsi_growth   = MathAbs(rsi_vector - rsi_midpoint);
    class=class="str">"cmt">//Check if we have broken either extreme
    if(PositionsTotal() == class="num">0)
      {
       class=class="str">"cmt">//We are looking for opportunities to sell
       if(iLow(Symbol(),TF_2,class="num">0) > resistance)
         {
          if((rsi[class="num">0] - rsi_midpoint) > (rsi_growth.Mean() * BIG_SIZE))
             Trade.Sell(VOL,Symbol(),bid,(ask + (ATR_SIZE * atr[class="num">0])),(ask - (ATR_SIZE * atr[class="num">0])));
         }
       class=class="str">"cmt">//We are looking for opportunities to buy
       if(iHigh(Symbol(),TF_2,class="num">0) < support)
         {
          if((rsi[class="num">0] - rsi_midpoint) < (-(rsi_growth.Mean() * BIG_SIZE)))
             Trade.Buy(VOL,Symbol(),ask,(bid - (ATR_SIZE * atr[class="num">0])),(bid + (ATR_SIZE * atr[class="num">0])));
         }
      }
   }

「画得少,看得清」

把经典 RSI 的 30/70 换成从当前品种指标分布里挑出的最优边界,等于让阈值跟着市场呼吸,而不是拿教科书硬套。多品种同时盯盘时,这种自适应规则能直接比出各市场真实波动强度,避免被固定水平骗进假信号。 附件里基准版 Self_Adapting_Trading_Rules.mq5 仅 6.2 KB,V2 优化版 7.41 KB,差距不到 1.3 KB 却把静态规则换成了随数据调整的逻辑。外汇与贵金属杠杆高、滑点跳空频繁,直接上实盘前务必在 MT5 策略测试器跑两轮再决定参数。 打开 V2 源码,先改 Input 里的品种列表,让小布替你把那套阈值重算一遍,比肉眼翻几十张图来得准。

常见问题

宏在编译期全局替换,不撤销会污染后面代码导致莫名报错或逻辑串味;用完后立即 #undef 是最省事的做法。
回测显示信号触发点随波动平移,震荡市假信号减少约两成,但趋势市入场会偏慢,需自己跑一遍验证。
小布可自动标注RSI偏离中轴的周期并提示潜在次级反转,你打开对应品种页就能直接看,不用自己写指标。
看RSI在次级周期离开50中轴超过阈值(如10)再回靠时介入,外汇贵金属波动大属高风险,先用模拟盘试。
只留关键线:动态中点、RSI偏离带,其余隐藏;画得少反而更容易认出结构,决策更快。