基于季节性因素的MetaTrader 5外汇价差交易质量评估·进阶篇
📘

基于季节性因素的MetaTrader 5外汇价差交易质量评估·进阶篇

第 2/2 篇

「用多年样本看跨品种价差季节性」

把两个品种报价相减就能得到价差:价差 = 第一品种报价 - 第二品种报价,再乘权重系数可修正 tick 价值差异。比如欧美系数取 1、镑美取 0.8,就是因为镑美每跳价值更高,直接 1:1 会扭曲真实价差结构。 白银兑美元加载指标后看 15 年 1 月数据,橄榄色历史均值、黄色本年曲线和橙色箭头全部指向价差收窄,说明该贵金属组合在中段月份有统计上可重复的收敛倾向。金银配比可设白银 1、黄金 2,也可在 tick 价值接近时直接 1:1。 欧美-镑美 12 月、镑美-纽元 4 月的历史均值曲线与本年曲线同向,后者两条线均自下而上呈扩大态势;但镑美-白银 6 月本年走势未验证历史均值方向,说明季节性不是每月都兑现。WTI-布伦特 7 月黄线配合橙色下行箭头,历史规律倾向 WTI 跌幅大于布伦特,可考虑做空该价差,指标须加载在 WTI 图表且配比 1:1。 评估季节性靠样本质量:观测期至少 10 年,15–20 年更稳;各年数值应平稳如 100、150、90、166、200、150、130、125,避免出现离群极值。若连续多年同月方向一致率≥70% 且区间相近,该模型可靠性才高,可用于当年交易。外汇与贵金属杠杆高、价差跳变频繁,任何季节性结论都只是概率倾向,需先在 MT5 加载 SpreadMultiYearComparison 用 CME 历史数据回看再动手。

价差跨年多周期对比的副图玩法

这个副图指标把品种间价差按年份拆开看,外部参数就六个:Symbol1 是主品种(比如 XAUUSD),Symbol2 留空就只算单一品种自身,MonthToShow 取 1–12,YearsToShow 支持回看 1–15 年,FillGaps 打开时用最近有效值补缺失。 核心逻辑落在日线周期,以点数为单位对 Symbol1 做统计。CalculateAllStatistics() 负责算月初到月末的价差变化并照顾小数位精度,DisplayFullStatistics() 抛逐年盈亏表并标趋势(强趋势或横盘),GetRecommendation() 看盈利月份占比给方向报告。 代码里 input 段直接暴露了默认值:MonthToShow=6、YearsToShow=15、FillGaps=true,意味着加载后默认就在看 6 月、回溯 15 年的价差结构。 季节性表格里有一条值得验证:6 月白银倾向下跌,6 月 GBPUSD 减 XAGUSD 价差也倾向下行;7 月 WTI–布伦特价差倾向走弱。外汇贵金属杠杆高,季节性只是概率倾向,不等于必然,止损和 COT 持仓报告得一并看。 下面这段取价函数是理解指标的基础,注意 iBarShift 拿日线偏移、iOpen 取开盘价再乘权重系数。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                  SpreadMultiYearComparison.mq5                  
class=class="str">"cmt">//|                     Copyright class="num">2025, Roman Shiredchenko
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Copyright class="num">2025"
class="macro">#class="kw">property version   "class="num">7.1"
class="macro">#class="kw">property strict
class="macro">#class="kw">property indicator_separate_window
class="macro">#class="kw">property indicator_buffers class="num">18
class="macro">#class="kw">property indicator_plots   class="num">17
class=class="str">"cmt">//--- Input parameters
class="kw">input class="type">class="kw">string   Symbol1      = "EURUSD";  class=class="str">"cmt">// First symbol(required)
class="kw">input class="type">class="kw">string   Symbol2      = "";        class=class="str">"cmt">// Second symbol(empty for single symbol analysis)
class="kw">input class="type">class="kw">double   k_Symbol1    = class="num">1.0;       class=class="str">"cmt">// Weight coefficient for Symbol1
class="kw">input class="type">class="kw">double   k_Symbol2    = class="num">1.0;       class=class="str">"cmt">// Weight coefficient for Symbol2
class="kw">input class="type">int      MonthToShow  = class="num">6;         class=class="str">"cmt">// Month to analyze(class="num">1-class="num">12)
class="kw">input class="type">int      YearsToShow  = class="num">15;        class=class="str">"cmt">// Number of years to analyze(class="num">1-class="num">15)
class="kw">input class="type">bool     FillGaps     = true;      class=class="str">"cmt">// Fill gaps in data
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Get spread/price value                                           |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">class="kw">double GetSpreadValue(class="type">class="kw">datetime dt)
{
   class=class="str">"cmt">//--- Get data for first symbol
   class="type">int shift1 = iBarShift(Symbol1, PERIOD_D1, dt, false);
&nbsp;&nbsp; if(shift1 < class="num">0) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Print("No data for ", Symbol1, " at ", TimeToString(dt));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class="kw">return EMPTY_VALUE;
&nbsp;&nbsp; }
&nbsp;&nbsp; class="type">class="kw">double price1 = k_Symbol1 * iOpen(Symbol1, PERIOD_D1, shift1);
&nbsp;&nbsp;
&nbsp;&nbsp; class=class="str">"cmt">//--- Return first symbol price if second symbol not specified
&nbsp;&nbsp; if(Symbol2 == "") {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class="kw">return price1;
&nbsp;&nbsp; }
&nbsp;&nbsp;
&nbsp;&nbsp; class=class="str">"cmt">//--- Get data for second symbol
&nbsp;&nbsp; class="type">int shift2 = iBarShift(Symbol2, PERIOD_D1, dt, false);
&nbsp;&nbsp; if(shift2 < class="num">0) {

◍ 跨品种日线开盘价差的计算收口

上面这段是跨品种价差函数的收尾逻辑,先判断副品种在指定时间是否有日线开盘数据,没有就直接打印提示并返回 EMPTY_VALUE,避免后续算出脏值。 具体看,Print 输出 "No data for " 加 Symbol2 和 TimeToString(dt),让 MT5 终端日志能定位是哪一对品种、哪一个时间点缺数据;return EMPTY_VALUE 则保证调用方拿到的是无效值而非 0,防止把“无数据”误当“价差为零”。 最后在有数据的情况下,price2 用 k_Symbol2 乘 iOpen(Symbol2, PERIOD_D1, shift2) 拿到副品种经系数调整后的日线开盘价,函数返回 price1 - price2 作为两品种开盘价差(spread)。 实盘里把这段塞进 EA 的 OnTick 前先跑一遍,若日志频繁出现 No data,多半是副品种不在市场报价窗口或周期未加载,外汇与贵金属跨品种套利本身高风险,缺数据时点应直接跳过交易而非硬算。

MQL5 / C++
  Print("No data for ", Symbol2, " at ", TimeToString(dt));
  class="kw">return EMPTY_VALUE;
  }
  class="type">class="kw">double price2 = k_Symbol2 * iOpen(Symbol2, PERIOD_D1, shift2);
  
  class=class="str">"cmt">//--- Return price difference(spread)
  class="kw">return price1 - price2;
}

「用跨年价差对比挖日线季节性窗口」

在 MT5 里做日线季节性,先别急着翻日历。打开一个品种图表,加载 SpreadMultiYearComparison 指标,填入你要对比的两个品种代码,再把历史年份拉到 10–15 年区间,指标才会给出跨年同期的价差堆叠视图。 选品种对讲究关联,不是随便两个标的凑一对。货币对、商品、指数甚至股票都行,但核心动作是同时一多一空开仓——价差交易赚的是两者相对位移,不是单边方向。某一方走反时,另一腿可能部分或完全抵掉亏损,这种结构常被称为对冲。 找规律看两条:一是翻出过去 10–15 年同月价差,抓那些每年同一月份持续扩张或收缩的窗口;二是看曲线够不够「平滑」,中间没大跳空、所需年份都有报价的,可靠性才高。统计越干净,重复概率越值得盯。 日线周期下单,可叠别的指标确认入出场,但止损必须按波动率摆,仓位别压太重。还要注意基本面突袭——经济数据、天气、主力投机、税务或监管变动都可能打断旧规律。 跑之前核对四件事:品种在所有年份都有报价(15 年优、10 年底线);图表切日线;两个代码都在市场报价窗;加载指标后右键刷新拉全数据。外汇贵金属杠杆高、季节窗也可能失效,历史重复只提示关注,不预示必然。

用多年价差季节性拆季节窗口

在 MT5 里把 SpreadMultiYearComparison 挂到 Symbol1 的图表上,比如 XAUUSD,就能同时看到橄榄色的历史同期价差均值曲线和黄色的本年曲线。把 Symbol2 设成 XAGUSD 可算金银价差,MonthToShow 填 12 即只看 12 月,YearsToShow 设 15 代表回看 15 年同期。 统计口径分三档:盈利年份占比 ≥75% 判为强势趋势;60%–75% 是中等趋势,得再叠加过滤;低于 60% 就是横盘,价差在区间里晃,原文建议配包络线指标做边界参考。外汇与贵金属价差受流动性和央行日程影响,高风险,以上仅为概率倾向。 实战上,强势档(>75%)可顺曲线方向进场,止损放历年平均亏损幅度,止盈取平均盈利两倍,触盈后按权益变化开移动止损。横盘档低于 60% 不赌方向,借包络线上轨空、下轨多,属于高抛低吸的季节性观察,不代表稳赚。

◍ 记住这一条就够了

SpreadMultiYearComparison 这套多年度价差比法,核心是把季节性统计当成‘统计罗盘’而非占卜。它靠双品种对冲把波动率压到单品种以下,D1 周期上只留正向概率超 70% 的季节性信号,确实能砍掉不少噪音。 但别以为机会少就没法玩——原文作者 7 月靠 NAS100 价差拿了约 900 点,8 月 AUDNZD 季节性也走顺了,缺的入场密度可用‘同月多组价差+多品种分散’补回来。 外汇与贵金属价差对冲仍属高风险,白银抵不掉黄金单边崩盘的情形历史上出现过;真要上手,先下那 39.97 KB 的 mq5 在 MT5 跑一遍再说。

常见问题

用同周期、同节假日后对齐的多年样本做收口处理,剔除流动性真空日的跳空,只在重叠交易时段取开盘差值。
把每年同月价差归一化后叠在同一副图,用色阶区分年份,重点看12月至次年2月是否稳定走阔。
可以,小布能拉取多年同周期价差并标出重合度高的季节窗口,你直接看它给出的重叠区间就行。
差别明显,3年可能只是偶然共振,10年重叠窗口才更接近真实季节规律,建议至少取5年以上。
统计上12月下半月到1月前两周走阔概率偏高,但属高风险品种,需结合当年宏观验证再动手。