非平稳序列如何制造伪回归陷阱
非平稳序列如何制造伪回归陷阱
在 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 直方图打出来,就能直观看见伪回归的频率。
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 用历史数据复算才说得准。
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 喂进去就能跑。外汇与贵金属波动常带结构突变,用此法前先认清高风险。
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。工具链摆在那,信不信由你,乱点参数必吃瘪。
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;