一个为莫斯科交易所期货开发的点差策略实例·综合运用
📉

一个为莫斯科交易所期货开发的点差策略实例·综合运用

(3/3)· 用 Si 与 RTS 的负相关把跨品种价差做成可回测的自动化信号,收尾篇补齐策略环境与风控提示

案例拆解新手友好 第 3/3 篇
很多人在做跨品种价差时直接拿裸价格相减,忽略了合约规范和毫秒级订单间隔,回测结果和实盘根本对不上。莫斯科交易所的 Si 和 RTS 虽显负相关,但不用回归构造序列就画价差,等于把噪声当信号。本文用 MT5 内置环境把这套流程跑通,少踩坑。

用点差占价百分比触发跨品种信号

点差策略的收尾一种玩法,是把点差绝对值换成「占主交易品种最新价的百分比」来判定。当 spread_percent = Spread_curr / last * 100 越过 spread_delta 阈值,就视为价差异常扩张,给出跨品种配对信号。 OnTick 里先等指标 BarsCalculated 与当前图表 Bars 对齐,避免跨品种数据不同步;取未完成柱的点差缓冲后,用 SymbolInfoTick 拿 symbol1 的 last 价算百分比。绝对值判断用 MathAbs,所以正负价差扩张都算触发。 触发后若无持仓,DoTrades 按策略方向同时进两个品种;已有持仓则 ReverseTrades 反转。另一层退出逻辑是固定 profit_percent:当账户浮盈占余额比 ≥ 2% 时,双向平仓落袋。 spread_delta 的优化区间设在 0.1%–1%。回测中「买一卖二」规则明显优于「卖一买二」,但这只是该样本周期内的倾向,外汇与贵金属自带高杠杆高风险,实盘前务必在 MT5 用历史数据重跑参数。

MQL5 / C++
class="type">void OnTick()
  {
   if(isNewBar())
       PrintFormat("新柱 %s 在 %s 开启", _Symbol, TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS));
 class=class="str">"cmt">//--- 等待指标数据的刷新,因为它工作于两个交易品种上
   if(BarsCalculated(ind_spreadLR)==Bars(_Symbol, _Period))
     {
      class=class="str">"cmt">//--- 取得当前柱(今天)的点差数值
      class="type">class="kw">double SpreadValues[];
      class="type">int copied=CopyBuffer(ind_spreadLR, class="num">0, class="num">0, class="num">1, SpreadValues);
      class="type">class="kw">double Spread_curr=SpreadValues[class="num">0]; class=class="str">"cmt">// 当前未完成的柱的点差
      if(copied!=-class="num">1)
        {
         class="type">MqlTick tick;
         SymbolInfoTick(symbol1, tick);
         class="type">class="kw">double last=tick.last;
         class="type">class="kw">double spread_percent=Spread_curr/last*class="num">100;
         class=class="str">"cmt">//--- 如果点差 % 达到了 spread_delta 的数值
         if(MathAbs(spread_percent)>=spread_delta)
           {
             PrintFormat("点差达到了 %.1f%% (%G) %s",
                        spread_percent, TimeToString(TimeCurrent(), TIME_SECONDS),
                        Spread_curr);
             class=class="str">"cmt">//--- 如果没有持仓,就在两个交易品种中进入市场
             if(PositionsTotal()==class="num">0)
               DoTrades(Spread_curr, strategy, symbol1, class="num">1, symbol2, class="num">1);
             class=class="str">"cmt">//--- 有持仓,就反转交易
             else
               ReverseTrades(Spread_curr, positionstype, symbol1, symbol2);
           }
         class=class="str">"cmt">//--- 点差在可接受的范围之内,检查浮赢 - 是时候平仓吗?
         else
           {
             class="type">class="kw">double profit=AccountInfoDouble(ACCOUNT_PROFIT);
             class="type">class="kw">double balance=AccountInfoDouble(ACCOUNT_BALANCE);
             if(profit/balance*class="num">100 >= profit_percent)
              {
               class=class="str">"cmt">//--- 达到了要求的浮盈,就获利平仓
               trade.PositionClose(symbol1);
               trade.PositionClose(symbol2);
               positionstype=class="num">0;
              }
           }
        }
     }
  }

「把 MT5 测试器当研究探针用」

前面那 4 个点差策略的回测和优化结果,只是在有限时间段里跑出来的,带随机性,不能直接当开仓依据。写它们的目的只有一个:让你看清在 MetaTrader 5 里验证和调试策略有多顺手。 MT5 测试器给 EA 开发者塞了不少硬货:自动拉取 EA 用到的所有品种分时历史;可视化调试里把指标、成交流、历史成交和专家日志叠在一起看;可视化模式下指标自动加载;用真实历史重演真实环境测策略;按自定义目标函数做多线程参数优化;调动数千个测试代理加速;按自定义规则把优化结果画出来看;支持多资产毫秒级同步策略回测;还能在测试里直接打断点、单步跑、查变量。 实务上,测试器最该被当成找方向的探针,而不是印钞机。先用单参数优化快速拿到倾向性结论,再往里加规则或改旧规则跑全量 EA 优化。算得慢就去接 MQL5 云网络,那是平台专门设计的分布式算力,能明显压低等待时间。外汇和贵金属杠杆高、滑点跳空频繁,任何测试结论都只是概率倾向,上真仓前务必自己开 MT5 复跑一遍。

◍ 画得少,看得清

点差策略回测里用的 Delta[i]=Close[i]-Close[i-1] 而非绝对收盘价,本质是剥离价格水平、只抓相对变动;本文四个 EA 都按每品种 1 手固定量跑,RTS-12.16 期货点值挂钩美元兑卢布汇率的 0.2 倍,所以 2016-10-25 那张优化截图的结果高度依赖当时美俄汇率,换时段重跑大概率漂移。 代码是在最理想条件写的:不处理发单失败、断线、手续费与滑点,也没管某个品种整根柱无报价时指标死等同步的坑。期货流动性常在合约过期后抬升,这部分同样没覆盖。 附带的 CalcShowRegression_script 用 CGraphic 加 Alglib 画点差散点趋势线,TwoSymbolsSpread_Ind 画双品种点差柱,四个 EA 分别吃回归系数符号翻转、点差符号翻转(新柱/当柱稳 N tick/首刻触百分比)进场——直接丢进 MT5 可视化测试,比盯着静态图更能看清回归线怎么被重算。 外汇与贵金属自带高杠杆高风险,这类价差模型在实盘前务必自己跑一遍带点差和滑点的压力测试,别把实验室数字当依据。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 双样本 F 检验|
class=class="str">"cmt">//| 该测试检验了关于给定 | 的离散度的三个假设。
class=class="str">"cmt">//| 样本。|
class=class="str">"cmt">//| 输入参数:|
class=class="str">"cmt">//| X - 样本 class="num">1。索引从 class="num">0 到 N-class="num">1 的数组。
class=class="str">"cmt">//| N - 样本数量。|
class=class="str">"cmt">//| Y - 样本 class="num">2.索引从 class="num">0 到 M-class="num">1 的数组。
class=class="str">"cmt">//| M - 样本数量。|
class=class="str">"cmt">//| 输出参数:|
class=class="str">"cmt">//| BothTails - 双尾检验的 p 值。
class=class="str">"cmt">//|如果 BothTails 小于给定值
class=class="str">"cmt">///显著性水平,零假设为
class=class="str">"cmt">//| 已拒绝。|
class=class="str">"cmt">//| LeftTail - 左尾检验的 p 值。
class=class="str">"cmt">//|如果 LeftTail 小于给定值
class=class="str">"cmt">//| 在显著性水平上,零假设为
class=class="str">"cmt">//| 已拒绝。|
class=class="str">"cmt">//| RightTail - 右尾检验的 p 值。
class=class="str">"cmt">//|如果右尾小于给定值
class=class="str">"cmt">///显著性水平,零假设为
class=class="str">"cmt">//| 已拒绝。|
class=class="str">"cmt">//+------------------------------------------------------------------+
class="kw">static class="type">void CAlglib::FTest(const class="type">class="kw">double &x[],const class="type">int n,const class="type">class="kw">double &y[],
                    const class="type">int m,class="type">class="kw">double &bothTails,class="type">class="kw">double &leftTail,
                    class="type">class="kw">double &rightTail)
class="type">class="kw">double          m_x[];
...
CMatrixDouble xy(size,class="num">2);
xy[class="num">0].Set(class="num">0, m_x[class="num">0]);
把跨品种诊断交给小布
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到 Si 与 RTS 的实时回归残差和通道偏离,不必自己写脚本盯日志。

常见问题

Si 是美元/卢布合约,RTS 是以美元计价的俄股指数,卢布汇率波动会同时牵引两者但方向相抵,图表上常呈现一涨一跌的负相关形态。
为确保两边收盘价同步,避免用错位时间点的数据算价差,否则回归系数和点差柱都会失真,影响后续通道判断。
可以,窗口长度决定趋势线灵敏度,短窗口反应快但易被毛刺带偏,长窗口平滑却滞后,按品种波动频率微调即可。
目前小布内置的是跨品种相关性诊断与通道偏离提示,策略逻辑需自行在 MT5 部署,但看盘端的价差异常 alert 已覆盖同类需求。
期货带杠杆且俄交所品种流动性时段集中,点差触发可能在滑点扩大时失效,外汇贵金属亦属高风险,任何信号都只是概率倾向而非确定结果。