依据价格相关性的统计数据过滤信号(基础篇)
📘

依据价格相关性的统计数据过滤信号(基础篇)

第 1/2 篇

「用相关性统计给信号做减法」

在 MT5 里跑趋势或反转策略,最怕信号扎堆却同向失效。一个实用做法是先统计候选品种间的价格相关性,把高度同向波动的标的视作冗余,只保留相关性低的一组来触发下单,相当于用统计关系给信号池做过滤。 原文作者 Михаил Тарачков 在 2014-03-07 发布的这一思路,截至统计时获得 2504 次查看与 16 条讨论,说明老交易员对「信号去重」有稳定需求。 具体落地时,可每日用 iPearson 或自定义相关系数函数计算近 20 根 H1 收盘的 pairwise 相关,超过 0.8 的配对只留一个进场,其余屏蔽。外汇与贵金属杠杆高、跳空频繁,这种过滤只降低拥挤度,不消除方向误判风险,相关结论均属概率倾向。

◍ 用模拟EA拆穿随机游走假设

很多人把市场想成掷硬币:扔100次大约50次正面,下一次正反概率仍是各半,前后互不影响。照这个逻辑,新K线出现时价格上扬和下降机会相等,历史柱根本不干扰当前柱,系统只要把数学期望调正就能躺赢——这想法太浪漫,也离谱。 我们直接在MT5里用MQL5向导建个EA模板,不真发单(点差和库存费会污染结果),只记录和模拟在1根、2根、3根柱收盘后买入的情形。测试区间取EUR/USD从2000年1月1日到2010年12月31日,跨度十一年。 跑完看收盘上涨占比:全样本里上涨比例明显偏离50%;若前一天收盘跌,次日上涨概率抬升;连跌两天、三天后,下一根反弹收阳的比例继续走高。价格有‘把损失赢回来’的倾向,前柱对当前柱影响相当显著。外汇和贵金属杠杆高,这种统计偏向只说明概率倾斜,不等于无风险套利。 下面这段是模拟用的核心代码,重点看OnDeinit里怎么算上涨百分比、OnTick里怎么抓时间结构:

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                                 explorer.mq5 |
class=class="str">"cmt">//|                    Copyright class="num">2011, MetaQuotes Software Corp. |
class=class="str">"cmt">//|                                        [MQL5官方文档] |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Copyright class="num">2011, MetaQuotes Software Corp."
class="macro">#class="kw">property link      "[MQL5官方文档]
class="macro">#class="kw">property version   "class="num">1.00"
class=class="str">"cmt">//---Variables---
class="type">class="kw">double profit_percent,open_cur,close_cur;
class="type">class="kw">double profit_trades=class="num">0,loss_trades=class="num">0,day_cur,hour_cur,min_cur,count;
class="type">class="kw">double open[],close[];
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert initialization function                                     |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
   class="kw">return(class="num">0);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert deinitialization function                                   |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnDeinit(const class="type">int reason)
  {
class=class="str">"cmt">/* Calculate percent of closures with increase from the total number */
   profit_percent=NormalizeDouble(profit_trades*class="num">100/(profit_trades+loss_trades),class="num">2);
   Print("Percent of closures with increase ",profit_percent,"%");   class=class="str">"cmt">// Enter data to the Journal
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert tick function                                               |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
  {
class=class="str">"cmt">//---find out the time---
   class="type">MqlDateTime time;                        class=class="str">"cmt">// Create a structure to store time
   TimeToStruct(TimeCurrent(),time);       class=class="str">"cmt">// Structuring the data
   day_cur=time.day_of_week;               class=class="str">"cmt">// Receive the value of the current day
   hour_cur=time.hour;                     class=class="str">"cmt">// Receive the current hour

用前一根阴线触发下一根涨跌统计

这段逻辑只盯一种情形:当上一根柱子收阴(close[1] < open[1])且尚未记录时,把当前根的开盘价 open_cur 存下来,count 置 1。注释里把连续三根阴线的条件划掉了,说明实盘只取单根信号,避免过度过滤。 等当前根走完(open_cur 不等于新的 open[0]),就把刚成型那根的收盘价 close[1] 赋给 close_cur,count 归零。此时若 close_cur >= open_cur,profit_trades 加 1,否则 loss_trades 加 1。 CopyOpen/CopyClose 都取 4 根并 ArraySetAsSeries 置为时间序列,索引 0 是最新根。你在 MT5 里把这段塞进 OnTick,跑 EURUSD 的 M1,肉眼能看到 profit_trades 和 loss_trades 随每根阴线后的第一根结果累加,外汇高杠杆下样本偏差会很大,仅作概率观察。

MQL5 / C++
  min_cur=time.min;                                                                     class=class="str">"cmt">// Receive the current minute
class=class="str">"cmt">//---Find out the prices---
  CopyOpen(NULL,class="num">0,class="num">0,class="num">4,open);ArraySetAsSeries(open,true);
  CopyClose(NULL,class="num">0,class="num">0,class="num">4,close);ArraySetAsSeries(close,true);
  if(close[class="num">1]<open[class="num">1]class=class="str">"cmt">/*&&close[class="num">2]<open[class="num">2]&&close[class="num">3]<open[class="num">3]*/ && count==class="num">0) class=class="str">"cmt">// If it closed with a loss
   {
     open_cur=open[class="num">0];                                                                  class=class="str">"cmt">// Remember open price of the current bar
     count=class="num">1;
   }
  if(open_cur!=open[class="num">0] && count==class="num">1)                                                     class=class="str">"cmt">// The current bar has closed
   {
     close_cur=close[class="num">1];                                                                class=class="str">"cmt">// Remember the close price of the formed bar
     count=class="num">0;
     if(close_cur>=open_cur)profit_trades+=class="num">1;                                           class=class="str">"cmt">// If the close price is higher than open,
     else loss_trades+=class="num">1;                                                               class=class="str">"cmt">// +class="num">1 to closures with profit, otherwise +class="num">1 to closures with loss
   }
}

「用交易日过滤把EA调稳」

把价格行为里的星期规律当成过滤器接进现有系统,往往比另起炉灶更划算。这里用 TDW 思路做验证:先假设一周内某些天更适合做多、某些天更适合做空,再用历史回测挑出最佳买卖日组合。 底层信号很简单——双 MA 交叉叠 MACD 直方图:快线自下而上穿慢线且 MACD 柱低于零轴做多,反之上穿且柱高于零轴做空,跟踪止损挂一个点,固定 0.1 手。原版 EA 把类封装在独立头文件里,用 MqlDateTime 抓服务器时间的星期索引(1=周一…5=周五)来比对设定的交易日期。 回测区间 EURUSD H1、2010 全年,未加过滤器时净值主要在前半段爬升;加上「周五买、周一卖」的日期过滤后,整段区间都更平稳。净盈利从约 3800 美元降到约 2800 美元(少 26%),但交易次数由 218 次砍到 62 次(近 3.5 倍),点差成本省下约 312 美元,盈利单比例升到 57%,单笔平均盈利提高到 113 美元。 外汇与贵金属属高风险品种,历史星期效应随时可能失效,上 MT5 跑一遍自己品种的 H1 回测再决定是否实盘跟随。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                                 moving.mqh |
class=class="str">"cmt">//|                     Copyright class="num">2011, MetaQuotes Software Corp. |
class=class="str">"cmt">//|                                 [MQL5官方文档] |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Copyright class="num">2011, MetaQuotes Software Corp."
class="macro">#class="kw">property link      "[MQL5官方文档]
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Класс my_expert                                                      |
class=class="str">"cmt">//+------------------------------------------------------------------+
class my_expert
  {                                                                       class=class="str">"cmt">// 定义一个EA类
  class=class="str">"cmt">// 私有成员
class="kw">private:
  class="type">int      ma_red_per,ma_yel_per;                                         class=class="str">"cmt">// 两条均线的周期参数
  class="type">int      ma_red_han,ma_yel_han,macd_han;                                class=class="str">"cmt">// 指标句柄
  class="type">class="kw">double   sl,ts;                                                         class=class="str">"cmt">// 止损与跟踪止损价位
  class="type">class="kw">double   lots;                                                          class=class="str">"cmt">// 固定手数
  class="type">class="kw">double   MA_RED[],MA_YEL[],MACD[];                                      class=class="str">"cmt">// 存放指标值的数组
  class="type">MqlTradeRequest  request;                                               class=class="str">"cmt">// 交易请求结构体
  class="type">MqlTradeResult   result;                                                class=class="str">"cmt">// 服务器返回结果结构体

常见问题

先算出品种间滚动相关系数,只在相关性低于阈值时放行信号,避免同方向扎堆;回测时保留阈值附近的样本做对照,防止一刀切。
写个只发随机单的模拟EA,对比实盘价格序列的连涨连跌分布;若实盘长串概率明显偏离随机基准,就说明存在可统计的规律。
小布可直接对指定品种跑历史K线统计,输出阴线后涨跌频率和置信区间,省去你自己写脚本逐根点数。
贵金属波动受消息驱动,单一阴阳线统计胜率可能随时段漂移;建议叠加交易日过滤,只在流动性稳定的时段采用该触发逻辑。
不止剔休市,还要避开数据周初和月末调仓日;按星期几分段统计胜率,只保留历史期望为正的那些交易日放行订单。