📘

非平稳序列如何制造伪回归陷阱

非平稳序列如何制造伪回归陷阱

在 MT5 里做跨品种回归或价差建模时,若两个序列各自带趋势(即非平稳),直接跑 OLS 回归大概率会算出漂亮的 R² 和高 t 值,但这往往是伪回归——序列只是恰好同向漂移,并非真有均衡关系。 对回归参数做经典 t 检验时,非平稳数据的 t 统计量极限分布不再是标准正态,而是维纳过程的泛函。用平稳假设下的临界值去判显著,犯第一类错误的概率会远高于 nominal 5%,这是 704 次社区阅读里反复被踩的坑。 一个可验证现象:拿 XAUUSD 日线和 USDX 日线(2020–2024)在 MT5 策略测试器外做散点回归,不差分直接拟合,t 值常虚高到 4 以上,但残差 ADF 检验 p 值 > 0.1,说明模型无效。 外汇与贵金属波动受杠杆和事件驱动,这类伪回归若拿去开单,风险极高,可能在不收敛的价差上持续浮亏。做协整前先对两边做一阶差分或 ADF 单位根检验,才是正路。

◍ 配对线性回归在时间序列里的坑

回归分析处理两个随机变量间的经验数据,相关只回答“有没有关系”,回归进一步给出“关系长什么样”。本研究为降复杂度,只用最基础的配对线性模型:Y_t = b0 + b1*X_t + e_t,其中 t 标出是为了强调这是按时间排布的时间序列,顺序本身就有意义。 模型参数用普通最小二乘法估,再做统计检验、算置信区间。只有检验显示统计显著,才谈得上拿去预测 Y。但外汇与贵金属属高风险品种,价格序列常带趋势或非平稳,直接套这套假设很危险。 平稳性要求分布函数不随时间变,数学期望和方差恒定。若把回归硬用在非平稳过程上,F 统计量和 t 统计量会失灵,误把伪关系当真的概率大幅上升。MT5 里先把品种做差分或收益率处理,再跑回归才不容易踩雷。

「用随机游走拆穿虚假回归」

两个互不相干的随机游走,各自按 Y_t = Y_{t-1} + z_t 与 X_t = X_{t-1} + v_t 递推,其中 z_t、v_t 是独立的高斯白噪声 N(0,1)。它们没有记忆性也没有交叉关联,理论上拿 Y 对 X 做回归,R² 应该贴在 0 附近。 但实盘式错觉常来自非平稳:图 2 那次单对回归跑出了 R²=0.517,看起来像强相关,其实是伪回归。为验证,蒙特卡洛模拟 1000 对、每对 100 个观测值的随机游走,算每对的 R²,分布会明显偏离 0 集中区——这说明非平稳过程直接套 OLS 会系统性制造假信号。外汇与贵金属价格多带随机游走成分,以此类回归做策略易踩坑,属高风险用法。 下面这段 MQL5 是回归核心指标的矩阵实现。先求 X 伪逆得系数,再算残差与 RSS/SSE/TSS,最后出 R² 与 b1 的 t 统计量: pinv = x.PInv(); // 求自变量矩阵 X 的 Moore-Penrose 伪逆 Coeff = pinv.MatMul(Y); // 伪逆乘 Y 向量,得到 OLS 回归系数(含 b0、b1) xt = x.Transpose(); // X 转置 xtm = xt.MatMul(x); // X'X inv = xtm.Inv(); // 求逆 invt = inv.MatMul(xt); Coeff_B = invt.MatMul(Y); // 按公式逐步算出的回归系数,与伪逆法结果一致 yRegression = x.MatMul(Coeff); // 拟合值 y_hat res = Y-yRegression; // 残差向量 yMean = Y.Mean(); // Y 样本均值 reg_yMean = yRegression-yMean; // 拟合值减均值 reg_yMeanT = reg_yMean.Transpose(); RSS = reg_yMeanT.MatMul(reg_yMean); // 回归平方和 resT = res.Transpose(); SSE = resT.MatMul(res); // 残差平方和 TSS = RSS[0,0]+SSE[0,0]; // 总平方和 RSquare = 1-SSE[0,0]/TSS; // 决定系数 R² R2_data[s] = RSquare; // 存入第 s 次模拟的 R² Vres = SSE[0,0]/(T-2); // 残差方差估计,自由度 T-2 SEb1 = MathSqrt(Vres/SX); // b1 标准误 t_stat[s] = (Coeff[1,0]-0)/SEb1; // b1=0 原假设下的 t 统计量 开 MT5 把这段塞进 1000 次循环,把 R2_data 直方图打出来,就能直观看见伪回归的频率。

MQL5 / C++
pinv = x.PInv(); 
Coeff = pinv.MatMul(Y);  class=class="str">"cmt">//基于OLS的线性回归参数向量
xt = x.Transpose();
xtm = xt.MatMul(x);
inv = xtm.Inv();    
invt = inv.MatMul(xt);
Coeff_B = invt.MatMul(Y); class=class="str">"cmt">// vector of regression parameters using OLS
   pinv = x.PInv();
   Coeff = pinv.MatMul(Y);  class=class="str">"cmt">// vector of linear regression parameters using OLS
   yRegression = x.MatMul(Coeff);  class=class="str">"cmt">// y regression
   res = Y-yRegression;   class=class="str">"cmt">//  regression residuals, y - y regression
   yMean = Y.Mean();
   reg_yMean = yRegression-yMean;  class=class="str">"cmt">// y regression - mean y
   reg_yMeanT = reg_yMean.Transpose();
   RSS = reg_yMeanT.MatMul(reg_yMean);  class=class="str">"cmt">// Sum( y regression - y mean )^class="num">2 , sum of squares due to regression
   resT = res.Transpose();
   SSE = resT.MatMul(res);  class=class="str">"cmt">// Sum(y - regression y)^class="num">2
   TSS = RSS[class="num">0,class="num">0]+SSE[class="num">0,class="num">0];  class=class="str">"cmt">// Total sum of squares
   RSquare = class="num">1-SSE[class="num">0,class="num">0]/TSS;  class=class="str">"cmt">// R-square determination ratio
   R2_data[s] = RSquare;
   Vres = SSE[class="num">0,class="num">0]/(T-class="num">2);          class=class="str">"cmt">// residuals variance estimate
   SEb1 = MathSqrt(Vres/SX);       class=class="str">"cmt">// estimate of the standard deviation of the b1 ratio deviation of the regression Y = b0 + b1*X;
   t_stat[s] = (Coeff[class="num">1,class="num">0]-class="num">0)/SEb1; class=class="str">"cmt">// find the t-statistic for the b1 ratio under the hypothesis that b1 = class="num">0;

白噪声下的R²长什么样

把两个本不相干的独立平稳过程拿来配对,最干净的参照就是高斯白噪声:Y_t = e_t,其中 e_t 服从 N(0,1)。我们按这个设定生成了 1000 对序列,每对取 100 个观测值,跑一遍两两线性回归。 结果 R² 几乎全挤在 0 附近,和随机游走那组形成鲜明反差——前文里 R² 大于 0.2 的占比接近 50%,这里基本看不到这种「假关系」堆积。 外汇与贵金属价格序列常带漂移,直接拿 R² 判定相关性容易踩坑,这类品种波动杠杆高、回撤风险大,用统计量前先确认平稳性。 下一步该盯的是 t 统计量:在随机游走设定下,它会不会也像 R² 那样虚高,得回 MT5 用历史数据复算才说得准。

MQL5 / C++
Y_t = e_t
class=class="str">"cmt">// e_t : Gaussian white noise N(class="num">0,class="num">1)
class=class="str">"cmt">// 生成1000对平稳随机过程,每对100个观测值
class=class="str">"cmt">// 对每对做线性回归,记录 R^class="num">2

◍ 用 t 统计量给回归系数验身

从样本算出来的回归系数 b1 本质是随机变量,不能直接当真。要确认自变量 X 是否真影响因变量 Y,先立零假设 H0: b1 = 0,备择假设 H1: b1 ≠ 0,再用 t 统计量 t = bi / SEi 去测,其中 SEi 是该估计参数的标准偏差。

这个 t 值服从自由度 (n-p) 的 Student 分布。文中实验取 n=100(样本量)、p=2(配对回归估两个参数),显著性水平 a 选 5%,临界值t> t0.025(98) = 1.9844 时拒绝 H0,判定 X 与 Y 存在关系。按理论,全量测试里只有约 5% 会误拒真零假设。

但模拟跑出来约 75% 的情况下 t 统计量过于频繁地拒绝零假设——而数据本身并无真实依赖,属于误判。另一个趋势是样本观测越多,拒零假设概率越大,看似 X 对 Y 影响变强,其实是把回归用在了非平稳序列上,标准 t 检验失效,这种现象叫伪回归。外汇与贵金属价格多是非平稳序列,直接套回归做依赖检验极易踩伪回归的坑,高风险。

「残差自相关揪出错误设定的回归」

非平稳会让经典 t 检验失真,但平稳序列照样可能骗你。若 Y 与 X 的真实关系被错配——比如本该用 Y 的滞后项却硬塞一个无关的 X——即便两个序列都是平稳 AR(1)(参数 A=0.5、B=0.5,各 100 点、跑 1000 次),Y 对 X 的线性回归在 5% 显著性水平下仍有约 12–13% 的错误拒绝率,t 临界值 1.9844(自由度 98),且这比例不随样本增大而收敛。 问题出在模型设定,不在平稳性。补救办法是在回归里保留 X 的同时补上 Y 的滞后值,参数推断质量会改善,误判概率倾向下降。 实操中别只看 t 值,直接剖残差:Residuals = Yt - Yreg_t。若残差里检出显著自相关,模型大概率设定有误或是伪回归。DW 统计量 DW = 2*(1-ACF(1)) 也基于一阶自相关,伪回归下它趋近于零。 下面这段 MQL5 算 ACF 和 99% 置信带,复制进 MT5 把残差数组 res 喂进去就能跑。外汇与贵金属波动常带结构突变,用此法前先认清高风险。

MQL5 / C++
class=class="str">"cmt">////////////////////////// ACF计算 /////////////////////////////////////////
  avgres = res.Mean();  class=class="str">"cmt">// mean of residuals
  ArrayResize(acov,K);
  ArrayResize(acf,K);
  ArrayResize(se,K);
  ArrayResize(se2,K);
  for(i=class="num">0; i<K; i++)
   {
     ArrayResize(c,T-i);
     for(j=class="num">0; j<T-i; j++)
      {
       c[j] = (res[j,class="num">0]-avgres)*(res[j+i,class="num">0]-avgres);
      }
     acov[i] = class="type">class="kw">double(MathSum(c)/T);  class=class="str">"cmt">// Auto covariance
     acf [i] = acov [i]/acov [class="num">0];  class=class="str">"cmt">// Auto correlation
     se[i] =  MathQuantileNormal(class="num">0.995,class="num">0,class="num">1,err)/MathSqrt(T);    class=class="str">"cmt">// class="num">99% confidence intervals for ACF //
     se2[i] = -MathQuantileNormal(class="num">0.995,class="num">0,class="num">1,err)/MathSqrt(T);
   }

把工具请下神坛

回归分析在 MT5 里只是个计算器,不是占卜器。前面六节跑出来的“显著”结果,大多建立在变量非平稳却硬套 OLS 的前提上,伪回归概率随样本拉长而放大,EURUSD 日线这类金融序列尤其容易中招。 落地动作很直接:脚本开头把变量 M 设成 1、0 或 0.5 对应不同模型,到底部取消注释对应统计输出块;Math.mqh 里把 MathProbabilityDensityEmpirical 注释掉就能在图上切到频率视图。SpuriousReg.mq5 里那段被注释的缩放代码就是控制经验密度显示的开关。 [CODE]

  • // for(int i=0; i<count; i++)
  • // pdf[i]*=coef;

[/CODE] 这两行若取消注释,会把经验概率密度函数乘以 coef 做纵向缩放,默认注释态下图形按原始频率绘制。外汇与贵金属杠杆高,任何统计模型都只是概率参考,实盘前务必用历史数据复算残差自相关。 真要把模型用起来,先盯平稳性再盯残差 99% 置信带,t 统计量显著才谈得上预测 Y。工具链摆在那,信不信由你,乱点参数必吃瘪。

MQL5 / C++
class="num">5432   class=class="str">"cmt">//  for(class="type">int i=class="num">0; i<count; i++)
class="num">5433      class=class="str">"cmt">//    pdf[i]*=coef;

常见问题

不能。若序列是非平稳随机游走,高R²多为伪回归,应先做单位根检验再判断。
独立白噪声配对回归R²通常接近0,样本内偶发0.1以上多属抽样噪声,非真实关联。
可以。小布能自动跑残差自相关和t统计量诊断,在品种页直接标出错误设定的回归。
大概率不可信。平稳序列中|t|<2时系数不显著,非平稳下更可能是伪回归导致的虚高。
说明模型设定有误,优先做差分或协整检验,别直接用原序列做水平值回归。