🧩
MQL5 频谱分析程序:FFT 与图形对象面板
FFT频谱分析图形对象
频谱分析在交易中的用途
价格序列可以看作一种信号。对它做傅里叶变换,能得到“哪些周期/频率成分最强”的频谱——也就是找出市场里反复出现的周期性(如某段历史里存在一个约 N 根柱的波动节律)。文章用 FFT 分析移动平均线的脉冲特性,直观展示不同均线的频率响应,帮助你理解指标的滞后与平滑本质。
FFT 原理简述
快速傅里叶变换(Cooley-Tukey 基 2)把时域序列转成频域。它要求序列长度为 2 的幂(文章固定用 1024=2^10)。内部用复数(实部 re / 虚部 im)运算,通过“位反转置换 + 蝶形(butterfly)运算”逐级合并,把 O(N²) 的离散傅里叶变换降到 O(N·logN)。
MQL5 实现:调用 FFT 函数
文章把 FFT 实现封装在外部函数 realfastfouriertransform(取自 mql4.com),指标只需准备 1024 个输入点再调用。输入可以是外部指标零缓冲的 1024 个值,也可以是 SMA/LWMA 的脉冲(前 N 点为 1、其余 0)来观测其频率特性:
void get_input_data()
{
ArrayInitialize(InpData, 0.0);
switch(InputSource)
{
case 0: CopyBuffer(ExtHandle,0,0,ArraySize(InpData),InpData); break;
case 1: for(i=0;i<3;i++) InpData[i]=1; break; // SMA(3) 脉冲
case 2: for(i=0;i<32;i++) InpData[i]=1; break; // SMA(32) 脉冲
case 3: for(i=0;i<12;i++) InpData[i]=12-i; break; // LWMA(12) 脉冲
}
}
void fft_calc()
{
realfastfouriertransform(InpData, ArraySize(InpData), false); // FFT
for(i=1;i<ArraySize(Spectrum);i++)
{
k=i*2;
Spectrum[i]=InpData[k]*InpData[k] + InpData[k+1]*InpData[k+1]; // 实部^2+虚部^2 = 功率
}
Spectrum[0]=0.0; // 清直流分量
}
幅度谱与显示
FFT 后每个频率点是一对 (re, im),功率谱 = re²+im²(文章直接计算平方,未开方)。频谱用面板对象(标签/趋势线/矩形)绘制,并提供线性/对数(dB)、振幅/功率四种显示模式。要找“主导周期”,就找功率谱峰值对应的谐波索引 k,周期长度 ≈ 总样本数 / k。
坑
⚠ 频谱分析的现实约束
1) 长度必须是 2 的幂:固定 1024 点,非 2 的幂的数据要补零(zero-padding),补零会引入边界效应。2) 边界效应:序列首尾不连续会在频谱产生泄漏,可加窗(Hanning 等)缓解。3) 噪声:真实价格含强噪声,低频峰值才可信,高频尖峰常是噪声。4) 指标会改图表属性(隐藏网格、固定最小 0),应在独立窗口加载,移除时自动恢复。5) 本文只算功率谱和显示,未内置“自动反推周期并交易”的逻辑,需自行扩展。
常见问题
能作为参考,但不能直接信。频谱峰值告诉你“历史上这段序列里最强的周期性约多长”,但市场状态会变,过去的周期不一定延续。实务上把它当过滤/确认工具(比如只在周期共振时持仓),且要配合其他信号,别单靠它下单。
幅度谱通常取 sqrt(re²+im²),功率谱取 re²+im²。文章直接算平方得到功率谱,差别只是量纲(功率 vs 振幅),对“找哪个频率最强”的排序结论一致。若要和教科书幅度对比再开方即可。
FFT(基 2)要求长度正好 2 的幂。数据长度不够就补零到最近的 2 的幂(如 1024),多了就截断或分段。补零不会增加真实信息,但会让频率栅格更密;同时要注意补零带来的边界效应,必要时先加窗函数。