分离策略在趋势和盘整条件下的优化·综合运用
📘

分离策略在趋势和盘整条件下的优化·综合运用

第 3/3 篇

「下行波段的开仓参数与指标输入」

做空分支的入场逻辑依赖一组独立 input 变量,和做多分支完全隔离,避免同一 EA 里多空参数互相串味。Inp_MagicNum2 设为 2222,和上升趋势的幻数区分开,回测时能在 MT5 交易历史里直接筛出下行单。 止损 40 点、止盈 70 点,盈亏比约 1:1.75;外汇与贵金属杠杆高,实际浮亏可能远超本金,这组点数仅定义订单距离,不预示胜率。 CenterOfGravityOSMA 指标在空方分支用 PRICE_HIGH_ 作为计算价,Period_2=15、两段平滑各 3 周期且都用 MODE_SMA,和多方分支的 PRICE_LOW 形成镜像。Inp_Bars2=1 代表取最近 1 根 K 线,Price2 用 PRICE_WEIGHTED 加权收盘价测速。 把下面代码整段贴进 MQ5 文件头部,编译后到 EA 属性页能看见『===Downtrend parameters===』分组,调参不用碰源码。

MQL5 / C++
input class="type">int                Inp_Bars1=class="num">1;                                                            class=class="str">"cmt">//天数
input ENUM_APPLIED_PRICE  Price1=PRICE_LOW;                                                          class=class="str">"cmt">//使用的价格
input class="type">class="kw">double              Trend_lev1=class="num">1.6;                                                            class=class="str">"cmt">//趋势水平
class=class="str">"cmt">//--- 下降趋势参数
input class="type">class="kw">string              Inp_Str_label2="===Downtrend parameters==="; class=class="str">"cmt">//标签
input class="type">int                Inp_MagicNum2=class="num">2222;                                                         class=class="str">"cmt">//幻数
input class="type">int                Inp_StopLoss2=class="num">40;                                                           class=class="str">"cmt">//止损(点数)
input class="type">int                Inp_TakeProfit2=class="num">70;                                                         class=class="str">"cmt">//获利(点数)
class=class="str">"cmt">//--- CenterOfGravityOSMA 指标参数
input class="type">uint               Period_2=class="num">15;                                                               class=class="str">"cmt">//平均周期数
input class="type">uint               SmoothPeriod1_2=class="num">3;                                                         class=class="str">"cmt">//平滑周期数1
input ENUM_MA_METHOD     MA_Method_1_2=MODE_SMA;                                                    class=class="str">"cmt">//平均方法1
input class="type">uint               SmoothPeriod2_2=class="num">3;                                                         class=class="str">"cmt">//平滑周期数2
input ENUM_MA_METHOD     MA_Method_2_2=MODE_SMA;                                                    class=class="str">"cmt">//平均方法2
input Applied_price_     AppliedPrice2=PRICE_HIGH_;                                                 class=class="str">"cmt">//使用的价格
class=class="str">"cmt">//--- 平均速度指标的参数
input class="type">int                Inp_Bars2=class="num">1;                                                               class=class="str">"cmt">//天数
input ENUM_APPLIED_PRICE  Price2=PRICE_WEIGHTED;                                                    class=class="str">"cmt">//使用的价格

多空两侧的参数分置逻辑

这套 EA 把 Buy 和 Sell 的输入参数完全拆开,不是共用一套止损止盈。Buy 侧给了 40 点止损、60 点获利,MagicNum 固定为 3333;Sell 侧则是 30 点止损、30 点获利,MagicNum 用 4444。两边各自带标签字符串,MT5 参数面板上会显示「===Buy parameters===」和「===Sell parameters===」做视觉分隔。 指标周期也双向独立:Buy 用 WPR(11) 配 ADX(13),Sell 用 WPR(7) 配 ADX(15)。ADX 盘整阈值统一设为 25,低于这条线倾向判定为震荡、不触发趋势单。 Trend_lev2 作为顶层趋势过滤系数默认 1.0,实际作用是给二级趋势判断乘权重。外汇与贵金属杠杆高,参数直接实盘有滑点放大风险,建议先开 MT5 策略测试器用 2023 年 XAUUSD 的 M15 跑一遍,看两侧胜率差是否来自周期错配。

MQL5 / C++
input class="type">class="kw">double                Trend_lev2=class="num">1.0;                                        class=class="str">"cmt">//趋势水平
class=class="str">"cmt">//--- Buy parameters
input class="type">class="kw">string                Inp_Str_label3="===Buy parameters===";       class=class="str">"cmt">//标签
input class="type">int                   Inp_MagicNum3=class="num">3333;                            class=class="str">"cmt">//幻数
input class="type">int                   Inp_StopLoss3=class="num">40;                              class=class="str">"cmt">//止损(点数)
input class="type">int                   Inp_TakeProfit3=class="num">60;                            class=class="str">"cmt">//获利(点数)
class=class="str">"cmt">//--- WPR indicator parameters
input class="type">int                   Inp_WPRPeriod1=class="num">11;                             class=class="str">"cmt">//WPR 周期数
class=class="str">"cmt">//--- ADX indicator parameters
input class="type">int                   Inp_ADXPeriod1=class="num">13;                             class=class="str">"cmt">//ADX 周期数
input class="type">int                   Inp_FlatLevel1=class="num">25;                             class=class="str">"cmt">// ADX 盘整水平
class=class="str">"cmt">//--- Sell parameters
input class="type">class="kw">string                Inp_Str_label4="===Sell parameters===";       class=class="str">"cmt">//标签
input class="type">int                   Inp_MagicNum4=class="num">4444;                            class=class="str">"cmt">//幻数
input class="type">int                   Inp_StopLoss4=class="num">30;                              class=class="str">"cmt">//止损(点数)
input class="type">int                   Inp_TakeProfit4=class="num">30;                            class=class="str">"cmt">//获利(点数)
class=class="str">"cmt">//--- WPR indicator parameters
input class="type">int                   Inp_WPRPeriod2=class="num">7;                              class=class="str">"cmt">//WPR 周期数
class=class="str">"cmt">//--- ADX indicator parameters
input class="type">int                   Inp_ADXPeriod2=class="num">15;                             class=class="str">"cmt">//ADX 周期数

◍ 双模信号的 OnTick 分发与开仓逻辑

这段逻辑把趋势与盘整两套策略塞进同一个 OnTick,靠 Magic 编号隔离持仓。Inp_FlatLevel2 默认设 40,即 ADX 低于该值才认作盘整,外汇与贵金属品种在亚盘窄幅段常触发此条件,但高杠杆下假突破概率不低。 OnTick 先调 GetIndValue 取指标缓冲,失败直接 return,避免用脏数据下单。随后四个 if 各自独立:BuySignal_1/SellSignal_1 走趋势,BuySignal_2/SellSignal_2 走盘整,且都用 !Trade.IsOpenedByMagic 拦掉同策略重复开仓。 趋势买入要求 avr_speed1[0] 大于 Trend_lev1,且 cog1 上一根小于当前、两根都为负;趋势卖出镜像处理。盘整买入看 wpr1[0] 低于 -80 且 adx1[0] 小于 Inp_FlatLevel1,盘整卖出则是 wpr2[0] 大于等于 -20 且 adx2[0] 小于 40。 直接把下面代码贴进 MT5 EA 的 mq5 文件,改 Inp_FlatLevel2 从 40 调到 30,回测 EURUSD 五分钟可能明显减少盘整单量,但趋势踏空也会变多,自行权衡。

MQL5 / C++
input class="type">int                Inp_FlatLevel2=class="num">40;                class=class="str">"cmt">// ADX 盘整水平
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| EA交易分时函数                                                    |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
  {
class=class="str">"cmt">//--- 取得计算数据
   if(!GetIndValue())
      class="kw">return;
class=class="str">"cmt">//--- 如果有买入信号 (跟随趋势策略) 就开启订单
   if(BuySignal_1() && !Trade.IsOpenedByMagic(Inp_MagicNum1))
      Trade.BuyPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss1,Inp_TakeProfit1,Inp_MagicNum1,Inp_EaComment);
class=class="str">"cmt">//--- 如果有卖出信号(跟随趋势策略)就开启订单
   if(SellSignal_1() && !Trade.IsOpenedByMagic(Inp_MagicNum2))
      Trade.SellPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss2,Inp_TakeProfit2,Inp_MagicNum2,Inp_EaComment);
class=class="str">"cmt">//--- 如果有买入信号 (盘整策略)就开启订单
   if(BuySignal_2() && !Trade.IsOpenedByMagic(Inp_MagicNum3))
      Trade.BuyPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss3,Inp_TakeProfit3,Inp_MagicNum3,Inp_EaComment);
class=class="str">"cmt">//--- 如果有卖出信号 (盘整策略) 就开启订单
   if(SellSignal_2() && !Trade.IsOpenedByMagic(Inp_MagicNum4))
      Trade.SellPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss4,Inp_TakeProfit4,Inp_MagicNum4,Inp_EaComment);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 买入条件 (跟随趋势策略)                                           |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool BuySignal_1()
  {
   class="kw">return(avr_speed1[class="num">0]>Trend_lev1 && cog1[class="num">1]<cog1[class="num">0] &&(cog1[class="num">1]<class="num">0 && cog1[class="num">0]<class="num">0))?true:false;
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 卖出条件 (跟随趋势策略)                                           |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool SellSignal_1()
  {
   class="kw">return(avr_speed2[class="num">0]>Trend_lev2 && cog2[class="num">1]>cog2[class="num">0] &&(cog2[class="num">1]>class="num">0 && cog2[class="num">0]>class="num">0))?true:false;
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 买入条件 (基于盘整策略)                                           |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool BuySignal_2()
  {
   class="kw">return(wpr1[class="num">0]<-class="num">80 && adx1[class="num">0]<Inp_FlatLevel1)?true:false;
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 卖出条件 (基于盘整策略)                                           |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool SellSignal_2()
  {
   class="kw">return(wpr2[class="num">0]>=-class="num">20 && adx2[class="num">0]<Inp_FlatLevel2)?true:false;
  }
class=class="str">"cmt">//+------------------------------------------------------------------+

「用 CopyBuffer 一次性卡死八个指标句柄」

多指标共振策略最怕某个附属指标没取到数,EA 却照常发单。下面这段把八个句柄的当前值一次性拉进数组,只要其中任意一个 CopyBuffer 返回值小于等于 0,函数就直接吐 false,主逻辑立刻跳过本次信号判断。 注意 CopyBuffer 的第三个参数是 0、第四个是 2,意思是取最新两根柱(索引 0 和 1)写入目标数组。若句柄未就绪或缓冲区不足,返回值会是 -1 或小于请求量的数,这里用 <=0 统一拦截,比逐个写 if 更省行数。 外汇与贵金属杠杆高,这类取数失败若不被拦住,可能让 EA 在指标空洞期用残缺数据下单,回测看不出、实盘直接吃滑点。开 MT5 把这段塞进你的多指标 EA,先裸跑观察日志里 false 触发频率,再决定要不要对单个句柄做延时重试。

MQL5 / C++
class="type">bool GetIndValue()
  {
   class="kw">return(CopyBuffer(InpInd_Handle1,class="num">0,class="num">0,class="num">2,cog1)<=class="num">0      ||
          CopyBuffer(InpInd_Handle2,class="num">0,class="num">0,class="num">2,cog2)<=class="num">0      ||
          CopyBuffer(InpInd_Handle3,class="num">0,class="num">0,class="num">2,avr_speed1)<=class="num">0 ||
          CopyBuffer(InpInd_Handle4,class="num">0,class="num">0,class="num">2,avr_speed2)<=class="num">0 ||
          CopyBuffer(InpInd_Handle5,class="num">0,class="num">0,class="num">2,wpr1)<=class="num">0      ||
          CopyBuffer(InpInd_Handle6,class="num">0,class="num">0,class="num">2,wpr2)<=class="num">0      ||
          CopyBuffer(InpInd_Handle7,class="num">0,class="num">0,class="num">2,adx1)<=class="num">0      ||
          CopyBuffer(InpInd_Handle8,class="num">0,class="num">0,class="num">2,adx2)<=class="num">0
          )?false:true;
  }

分离优化在逆风区间的韧性

把趋势跟踪模型训好的参数,直接丢到盘整区段回测,结果仍跑出正向权益曲线——这点比它在顺势行情里的表现更值得盯。样本取自随机挑的交易系统,未做二次拟合,仅靠分离训练切分市场状态。 两个独立训练的子策略在长周期里零修正、零重优化各自存活,等于互为对方的压力测试。外汇与贵金属波动放大时这类分离结构可能降低过拟合概率,但杠杆品种高风险依旧,参数失效不报警。 最不利历史区间的终检也过了,说明分离优化不是只挑好日子干活。开 MT5 用随机 EA 跑一遍趋势/盘整分离训练,比盲信单一全样本优化更靠谱。

◍ 文件落地与实盘边界

随文压缩包 Separate_optimization.zip 体积 101.79 KB,内含 6 个文件:3 个 EA(TrendStrategy、FlatStrategy、UniverseStrategy)、1 个交易库 Trade.mqh、2 个指标(average_speed、centerofgravityosma)。部署时把 mql5 文件夹直接丢进终端根目录,MT5 才能正确索引 include 路径,否则编译会报访问 include 文件夹的错误。 评论区有用户反馈:用 1 分钟 OHLC 做回测的 EA,实盘大概率惨败,这类策略更适合当教学样本而非直接上资金。外汇与贵金属杠杆高、滑点跳空频繁,拿文中 EA 跑实盘前务必先在策略测试器用 tick 级数据重验。 Sharl Larionov 提到 MT5 看不到 mq5 文件,多半是根目录放错层;Mark Alan Watson 找不到下载入口,说明附件依赖原发布页环境。真要验证,自己解包、放对路径、编译 ex5,比等现成文件更稳。

常见问题

原文未给固定数值;建议按波段振幅的1.2倍设止损,手数随账户净值0.5%风险上限浮动,实盘前先在历史品种上回测验证。
多空周期差保持原文的对称分置逻辑即可,过滤阈值建议相差不超过30%,避免样本内漂亮、样本外崩盘。
可以。小布能按品种页加载分离策略诊断,直接列出多空参数冲突与OnTick分发异常,省去手动核对八个句柄的麻烦。
原文提到逆风区间靠分置参数保韧性;实盘可加滑点容差并禁用临界5%带宽内的新开仓,等确认K线收完再放行。
重点查CopyBuffer句柄失效处理和点差突变保护;文件输出路径权限也要确认,否则复盘日志写不进去会静默出错。