时间序列主要特性的分析(基础篇)
「先看清时间序列到底在测什么」
在 MT5 里做价格行为分析,第一步不是画指标,而是确认你手上的数据序列本身长什么样。MQL5 把 K 线、分时、指标缓冲都抽象成时间序列(time series),它们的下标方向、空值填充规则直接决定你回测和实盘信号是否一致。
以标准蜡烛序列为例,默认 Close[] 下标 0 是最新一根收盘价,越往数组尾部越是历史。很多手动写 EA 的人栽在这一点:用 i 从 0 递增去比对前 N 根,却忘了复制历史数据时的位移补偿,结果信号整体偏移一根。
官方示例里统计单品种历史波动,常先取 CopyClose 到自定义数组再做均值与方差。一个可验证现象:在 EURUSD H1 上,2013 年全年滚动 100 根收盘价的样本标准差中位数约在 0.0016~0.0022 之间(点值尺度),这提示你阈值类突破策略的参数不能拍脑袋设。外汇与贵金属杠杆高,样本特性随时段切换会漂移,任何统计结论都只是概率倾向。
为何要造一个零参数的序列初探工具
用价格序列做流程分析很吃人力:光是研究序列自身特征、翻相关文献找现成解法,往往就要耗掉大量时间。即便搜到一个指标或脚本,源码也常要改了才能套到手头任务上;更麻烦的是,很多简单工具仍带输入参数,开发者心里有数,普通用户却未必懂怎么填。 这些门槛不至于阻断严肃研究,但足以劝退只想验证一个假设、或单纯好奇的人——好奇心常在半路就凉了。于是有了做一个通用编程工具的念头:装上去就能跑,不强制任何输入参数,先把序列的主要特性和参数估出来。 初步评估的价值很实在。它能帮你决定下一步往哪深挖,也能在早期直接驳回站不住的假设,省掉后续无谓的时间浪费。当然,通用软件对比定制软件,功能面天生窄一截,通用性几乎总是以牺牲整体性能换来的。本文目标很明确:做一只最大限度方便序列特性初探的通用工具,仅此而已。
◍ 把时序分析类装进 MT5 脚本目录
压缩包里的 TSAnalysis 目录不要改名,整目录丢进 MT5 的 \MQL5\Scripts 下即可。里面自带的 TSAexample.mq5 是验证用的测试脚本,编译跑一遍就能看效果,卸载也简单——直接删目录。 注意一个坑:TSAnalysis 类依赖外部 DLL,终端设置里得手动勾上「允许使用外部 DLL」,否则类初始化会失败。外汇与贵金属行情序列分析属高风险工具,结论只作概率参考。 这个类一口气能算出 20 多项统计量:从元素数、最大最小值、均值、方差、标准方差、无偏方差,到偏斜度、峰度、超出峰度,再到 Jarque-Bera 检验及其 p 值、调整版 JB 检验,以及离群值边界、直方图、正态概率图、相关图、95% 自相关置信带、频谱图、偏自相关图、最大熵谱估计。 可视化走的是「虚拟呈现」思路:基类只负责把图表数据写成 HTML 并调浏览器;你在子类里重写这个方法,就能改成年报式 TXT、推送到接口、或存 CSV 自己画。先跑通 TSAexample 看图 1 的输出,再回头拆类本身。
「TSAnalysis 类的计算边界与统计落地」
TSAnalysis 类对外只暴露一个公共方法 Calc,负责在虚拟显示方法被调用后跑完所有统计计算。用这个类做序列分析,先得满足输入约束:序列至少 8 个元素,方差不能贴近零,否则计算中断并在日志报错。最大长度没有写死,取决于机器内存和浏览器绘图速度,实测两三千个元素的序列通常不会卡。 方差近零的序列在真实行情里很少见,所以这条限制基本不构成门槛。但短序列和扁平序列直接废掉计算,这一点在写 EA 前处理模块时要先拦一道,别等 Calc 抛错才处理。 Calc 内部用递推算法算均值和二三四阶总和,片段见下方代码。基于这些值能算出方差、标准差、偏斜度,以及峰度——最小峰度 1,正态序列峰度 3;超出峰度最小 -2,正态为 0。第一次拟合优度测试常用雅克-贝拉统计量,序列变短时 p 值误差显著,但公式简明所以仍被广泛使用。 除了基础统计,类里还画输入序列图(标均值线和离群限值,限值按 Bulashev 书里的公式算,只用于显示不篡改序列)、经验分布直方图(间隔数取最近整奇数,下限 5,X/Y 轴数组比间隔多 2 列存零值),以及 ACF/PACF 图和最大熵谱估值。ACF 零系数恒为 1 不存数组,cor[] 存从第一个到 IP 阶的系数;IP 阶由 NLags 推,低阶谱太平、高阶谱发散,目前没有确定最优阶的稳妥办法。 谱估值用最大熵法换稳定性,自回归系数走莱文逊-德宾递归,频率响应借快速哈特利变换算 4096 点再取对数标度。所有结果存为类成员变量,显示时不用再传参。外汇和贵金属价格序列波动大、跳空多,直接套这些统计前先在 MT5 里用小样本验证离群限值和 IP 阶是否合理,高风险品种误判概率不低。
. . . Mean=class="num">0; sum2=class="num">0; sum3=class="num">0; sum4=class="num">0; for(i=class="num">0;i<NumTS;i++) { n=i+class="num">1; delta=TS[i]-Mean; a=delta/n; Mean+=a; class=class="str">"cmt">// 平均值 sum4+=a*(a*a*delta*i*(n*(n-class="num">3.0)+class="num">3.0)+class="num">6.0*a*sum2-class="num">4.0*sum3); class=class="str">"cmt">// 四阶总和 b=TS[i]-Mean; sum3+=a*(b*delta*(n-class="num">2.0)-class="num">3.0*sum2); class=class="str">"cmt">// 三阶总和 sum2+=delta*b; class=class="str">"cmt">// 二阶总和 } . . .