使用计量经济学方法分析图表·综合运用
(3/3)·把前两篇的时域与非线性模型拼成完整诊断链,避开‘看图形凭感觉’的盲区
◍ 用傅里叶共轭算自相关再跑Ljung-Box
这段实现里,先对序列做正向 FFT(F.Forward(nFFT)),随后在循环里把输出搬进 Data21,再与自身的共轭 cData 做乘法。复数乘共轭后虚部抵消,只剩实部,相当于在频域完成了自相关的对称运算,比时域逐 lag 滑动快一个量级。 权重化逆变换 F1.InverseT(nFFT) 之后,用 getComplexArr 把复数结果压成 double 二维数组 rA,再取 rA[i][0] 填进 ACF 并除以 rA[0][0] 做归一化。归一后首项为 1,第 k 项即滞后 k 的自相关系数,可直接拿去画外汇小时线 EURUSD 的 ACF 图验证。 lbqtest 函数封装了 Ljung-Box-Pierce 检验:固定看 lags[3]={10,15,20} 三个滞后,最大 lag 设 20,显著性水平 alpha 全取 0.05。它先调 autocorr 算出 21 长 ACF,再丢掉首项 1 得到 20 长 acf 数组供 Q 统计量使用。 开盘前把这段贴进 MT5 脚本,用最近 500 根 XAUUSD 的 log return 跑一遍,若 H[0]~H[2] 有多个 false,说明在 10/15/20 滞后上序列可能非随机,存在可捕捉的均值回复倾向;贵金属杠杆高,信号失效时回撤可能剧烈,仓位要控。
F.Forward(nFFT); class=class="str">"cmt">//perform direct Fourier transformation for(class="type">int i=class="num">0;i<nFFT;i++) { Data21[i].opEqual(F.Output[i]);class=class="str">"cmt">//assign the values of the F.Output array to the Data21 array; cData[i].conjugate(Data21[i]); class=class="str">"cmt">//perform conjugation for the array Data21 Data21[i].opMultEq(cData[i]); class=class="str">"cmt">//multiplication of the complex number by the one adjacent to it class=class="str">"cmt">//results in a complex number that has only real component not equal to zero } F1.setCFFT(Data21,Data22); class=class="str">"cmt">//initialize data-members for the instance F1 F1.InverseT(nFFT); class=class="str">"cmt">//perform weighter reverse Fourier transformation getComplexArr(rA,F1.Output); class=class="str">"cmt">//get the result in class="type">class="kw">double format after class=class="str">"cmt">//weighted reverse Fourier transformation for(class="type">int i=class="num">0;i<nLags+class="num">1;i++) { ACF[i]=rA[i][class="num">0]; class=class="str">"cmt">//in the output ACF array save the calculated values class=class="str">"cmt">//of autocorrelation function ACF[i]=ACF[i]/rA[class="num">0][class="num">0]; class=class="str">"cmt">//normalization relatively to the first element } } class="type">void lbqtest(class="type">bool &H[],class="type">class="kw">double &rets[]) class=class="str">"cmt">/* Function that implements the Q test of Ljung-Box-Pierce H - output array of logic values, that confirm or disprove the zero hypothesis on the specified lag; rets - array of observations of the stochastic time series; */ { class="type">class="kw">double lags[class="num">3]={class="num">10.0,class="num">15.0,class="num">20.0}; class=class="str">"cmt">//specified lags class="type">int maxLags=class="num">20; class=class="str">"cmt">//maximum number of lags class="type">class="kw">double ACF[]; ArrayResize(ACF,class="num">21); class=class="str">"cmt">//epmty ACF array class="type">class="kw">double acf[]; ArrayResize(acf,class="num">20); class=class="str">"cmt">//alternate ACF array autocorr(ACF,rets,maxLags); class=class="str">"cmt">//calculated ACF array for(class="type">int i=class="num">0;i<class="num">20;i++) acf[i]=ACF[i+class="num">1]; class=class="str">"cmt">//remove the first element - one, fill class=class="str">"cmt">//alternate array class="type">class="kw">double alpha[class="num">3]={class="num">0.05,class="num">0.05,class="num">0.05}; class=class="str">"cmt">//array of levels of significance of the test
「Ljung-Box 统计量的数组落地」
这段实现把 Ljung-Box 的 Q 公式拆成了纯数组运算:Q = T(T+2)·Σ(ρ(k)²/(T-k)),其中 T 是样本长度、k 为滞后阶、ρ(k) 是第 k 阶自相关系数。MT5 里没有现成封装,只能自己用 ArrayResize 铺辅助数组。 先开六个 double/int 数组:idx 存索引偏移、arrLags 存滞后阶、stat 存 Q 值、sum 与 iACF 做累加中介、还有给指定滞后用的 stat1。maxLags 决定循环上界,len 取 rets 实际长度,二者差 1 就可能影响 p 值精度。 第一层 for 把 arrLags[i] 填成 i+1,idx[i] 算成 len-arrLags[i],iACF[i] 直接算 ρ²/idx。随后 cumsum 做累进求和,第二层 for 乘回 len*(len+2) 得到各阶 stat[i]。 最后按传入的 lags 挑出 stat1,用 1-gammp(lags/2, stat1/2) 算 p 值;当 alpha[i] >= pValue[i] 时 H[i] 置真,意味着该阶自相关在给定显著性下显著异于零。外汇与贵金属波动聚类明显,p 值小于 0.05 的滞后阶往往集中在前 10~20 阶,可据此判断回看窗口该取多长。
class="type">class="kw">double idx[]; ArrayResize(idx,maxLags); class=class="str">"cmt">//auxiliary array of indexes class="type">int len=ArraySize(rets); class=class="str">"cmt">//length of the array of observations class="type">int arrLags[];ArrayResize(arrLags,maxLags); class=class="str">"cmt">//auxiliary array of lags class="type">class="kw">double stat[]; ArrayResize(stat,maxLags); class=class="str">"cmt">//array of Q statistics class="type">class="kw">double sum[]; ArrayResize(sum,maxLags); class=class="str">"cmt">//auxiliary array po sums class="type">class="kw">double iACF[];ArrayResize(iACF,maxLags); class=class="str">"cmt">//auxiliary ACF array for(class="type">int i=class="num">0;i<maxLags;i++) { class=class="str">"cmt">//fill: arrLags[i]=i+class="num">1; class=class="str">"cmt">//auxiliary array of lags idx[i]=len-arrLags[i]; class=class="str">"cmt">//auxiliary array of indexes iACF[i]=pow(acf[i],class="num">2)/idx[i]; class=class="str">"cmt">//auxiliary ACF array } cumsum(sum,iACF); class=class="str">"cmt">//sum the auxiliary ACF array class=class="str">"cmt">//by progressive total for(class="type">int i=class="num">0;i<maxLags;i++) stat[i]=sum[i]*len*(len+class="num">2); class=class="str">"cmt">//fill the array Q statistics class="type">class="kw">double stat1[]; class=class="str">"cmt">//alternate of the array of Q statistics ArrayResize(stat1,ArraySize(lags)); for(class="type">int i=class="num">0;i<ArraySize(lags);i++) stat1[i]=stat[lags[i]-class="num">1]; class=class="str">"cmt">//fill the alternate array of specified lags class="type">class="kw">double pValue[ArraySize(lags)]; class=class="str">"cmt">//array of &class="macro">#x27;p&class="macro">#x27; values for(class="type">int i=class="num">0;i<ArraySize(lags);i++) { pValue[i]=class="num">1-gammp(lags[i]/class="num">2,stat1[i]/class="num">2); class=class="str">"cmt">//calculation of &class="macro">#x27;p&class="macro">#x27; values H[i]=alpha[i]>=pValue[i]; class=class="str">"cmt">//estimation of zero hypothesis } }
别急着下结论
非线性 GARCH 模型的价值不在于替你喊方向,而是从数学上把序列的波动边界正式刻画出来,并为指定步数给出预测区间。作者在原讨论里也点明:它确定的是未来收益的界限,以及在验证范围内模拟价格行为,而不是预测涨跌符号。 把这套东西接进 MT5 后,你能直接用预测方差去压力测试现成 EA——比如把 GarchTest 脚本跑出来的边界喂给历史回放,看策略在极端波动里会不会爆仓。外汇和贵金属杠杆高,波动边界只是概率参考,实盘仍可能瞬间击穿。 文件落点记一下:ReturnsIndicator.mq5 放 Indicators,Complex_class.mqh 与 FFT_class.mqh 进 Include,GarchTest.mq5 丢进 Scripts,编译不过就查 154 行附近的整数表达式报错。跑通之后,你才算真正摸到了用严方法代替肉眼目测的门槛。