初学者以 MQL5 实现对数字滤波器的实际实施·进阶篇
拿现成SMA模板改出FATL数字滤波器
写相似指标没必要从空白文件敲起。MT5客户端里自带 Moving Average.mq5 和 Custom Moving Average.mq5,但更省脑力的做法是把一份已有的 SMA 指标代码当模板,只替换计算内核和少量变量名,智力消耗能压到最低。 数字滤波器的一般公式是:滤波器 = SUM(K(i) * CLOSE(i), FilterPeriod),其中 K(i) 是加权系数、FilterPeriod 是固定平均柱数。它和 SMA = SUM((1/MAPeriod)*CLOSE(i), MAPeriod) 结构几乎一样,区别仅在于 K(i) 与周期都由专门算法定死,本文直接用 FATL 的现成系数,不展开算法推导。 MQL5 的指标缓冲区计算方向和 MQL4 相反:原 MQL4 公式里 Close[bar + N] 的增量下标,在 MQL5 要改成 price[bar - N],且 Close[] 时序数组不存在,统一换成 price[]。在 MetaEditor 里用「全部替换」把 Close[bar+ 批量改掉即可,不必手改每一行。 实操路径:打开 SMA_1_en.mq5 另存为 FATL_en.mq5,删掉循环里除缓冲区初始化外的旧代码,把 FATL 公式块贴进去;全局把 SMA 换成 FATL、MAPeriod/MAShift 换成 FATLPeriod/FATLShft;FATLPeriod 固定为 39 所以从外部输入和 StringConcatenate 里删掉,iii 局部变量也可删,线色改蓝加粗。编译挂图就能验证。 FATL 的加权系数前 29 项已列在代码块,最大正系数 0.4360409450 在 bar+0,bar+5 出现首个明显负系数 -0.0760367731。这套代码稍后只需换公式和 DIGFILTERPeriod 初始化,就能套出别的滤波器。
FATL = class="num">0.4360409450 * Close[bar + class="num">0] + class="num">0.3658689069 * Close[bar + class="num">1] + class="num">0.2460452079 * Close[bar + class="num">2] + class="num">0.1104506886 * Close[bar + class="num">3] - class="num">0.0054034585 * Close[bar + class="num">4] - class="num">0.0760367731 * Close[bar + class="num">5] - class="num">0.0933058722 * Close[bar + class="num">6] - class="num">0.0670110374 * Close[bar + class="num">7] - class="num">0.0190795053 * Close[bar + class="num">8] + class="num">0.0259609206 * Close[bar + class="num">9] + class="num">0.0502044896 * Close[bar + class="num">10] + class="num">0.0477818607 * Close[bar + class="num">11] + class="num">0.0249252327 * Close[bar + class="num">12] - class="num">0.0047706151 * Close[bar + class="num">13] - class="num">0.0272432537 * Close[bar + class="num">14] - class="num">0.0338917071 * Close[bar + class="num">15] - class="num">0.0244141482 * Close[bar + class="num">16] - class="num">0.0055774838 * Close[bar + class="num">17] + class="num">0.0128149838 * Close[bar + class="num">18] + class="num">0.0226522218 * Close[bar + class="num">19] + class="num">0.0208778257 * Close[bar + class="num">20] + class="num">0.0100299086 * Close[bar + class="num">21] - class="num">0.0036771622 * Close[bar + class="num">22] - class="num">0.0136744850 * Close[bar + class="num">23] - class="num">0.0160483392 * Close[bar + class="num">24] - class="num">0.0108597376 * Close[bar + class="num">25] - class="num">0.0016060704 * Close[bar + class="num">26] + class="num">0.0069480557 * Close[bar + class="num">27] + class="num">0.0110573605 * Close[bar + class="num">28]
◍ FATL 系数的近端权重与远端回拉
上面这段加权式是 FATL 滤波器的核心:用 bar-0 到 bar-29 共 30 根历史收盘价做线性组合,系数正负交错。 近端(bar-0 到 bar-3)系数全为正,0.4360、0.3659、0.2460、0.1105 依次衰减,说明最新几根 K 线对 FATL 值的拉动最直接。 中段 bar-4 到 bar-8 转为负值,最低到 -0.0933(bar-6),相当于把 6 根前的价格朝反方向修正,避免慢速均线被旧趋势黏住。 远端 bar-27 到 bar-29 又回到 +0.0069、+0.0111、+0.0096 的小正权重,这种「远端回拉」结构让 FATL 在突变行情后约 29 根 bar 才完全脱敏。 在 MT5 里把这段系数直接塞进自定义指标数组,调 bar-6 的 -0.0933 绝对值,能明显改变滤波器对中周期噪声的敏感度。外汇与贵金属波动剧烈,此类线性滤波仅作参考,实盘须控仓。
FATL = class="num">0.4360409450 * price[bar - class="num">0] + class="num">0.3658689069 * price[bar - class="num">1] + class="num">0.2460452079 * price[bar - class="num">2] + class="num">0.1104506886 * price[bar - class="num">3] - class="num">0.0054034585 * price[bar - class="num">4] - class="num">0.0760367731 * price[bar - class="num">5] - class="num">0.0933058722 * price[bar - class="num">6] - class="num">0.0670110374 * price[bar - class="num">7] - class="num">0.0190795053 * price[bar - class="num">8] + class="num">0.0259609206 * price[bar - class="num">9] + class="num">0.0502044896 * price[bar - class="num">10] + class="num">0.0477818607 * price[bar - class="num">11] + class="num">0.0249252327 * price[bar - class="num">12] - class="num">0.0047706151 * price[bar - class="num">13] - class="num">0.0272432537 * price[bar - class="num">14] - class="num">0.0338917071 * price[bar - class="num">15] - class="num">0.0244141482 * price[bar - class="num">16] - class="num">0.0055774838 * price[bar - class="num">17] + class="num">0.0128149838 * price[bar - class="num">18] + class="num">0.0226522218 * price[bar - class="num">19] + class="num">0.0208778257 * price[bar - class="num">20] + class="num">0.0100299086 * price[bar - class="num">21] - class="num">0.0036771622 * price[bar - class="num">22] - class="num">0.0136744850 * price[bar - class="num">23] - class="num">0.0160483392 * price[bar - class="num">24] - class="num">0.0108597376 * price[bar - class="num">25] - class="num">0.0016060704 * price[bar - class="num">26] + class="num">0.0069480557 * price[bar - class="num">27] + class="num">0.0110573605 * price[bar - class="num">28] + class="num">0.0095711419 * price[bar - class="num">29]
「FATL 指标缓存与滞后权重拼接」
上面这段加权式把 bar-30 到 bar-38 的收盘价按系数混算,正负交错里 bar-37 的 0.0130129076 是最大正权重,bar-33 的 -0.0072003400 是最大负权重,说明该平滑线对 37 根前的数据最敏感。 主循环里只做一件事:把算好的 FATL 值写进 ExtLineBuffer[bar],循环从 first 跑到 rates_total,不在这里做归一或截断。 指标属性块定了蓝实线、宽度 2、画在主图,FATLPeriod 写死为 39,因此 PlotIndexSetInteger 里 PLOT_DRAW_BEGIN 也设为 39——前 38 根柱不画线,MT5 里拖到 EURUSD 日线能直接看到头部空缺。外汇与贵金属杠杆高,这类平滑线仅作趋势参照,信号失效概率不低。
+ class="num">0.0040444064 * price[bar - class="num">30] - class="num">0.0023824623 * price[bar - class="num">31] - class="num">0.0067093714 * price[bar - class="num">32] - class="num">0.0072003400 * price[bar - class="num">33] - class="num">0.0047717710 * price[bar - class="num">34] + class="num">0.0005541115 * price[bar - class="num">35] + class="num">0.0007860160 * price[bar - class="num">36] + class="num">0.0130129076 * price[bar - class="num">37] + class="num">0.0040364019 * price[bar - class="num">38]; class=class="str">"cmt">//---- 指标计算的主循环 for(bar=first; bar<rates_total; bar++) { class=class="str">"cmt">//---- 用FATL初始化指标缓存单元 ExtLineBuffer[bar]=FATL; } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Fatl_en.mq5 | class=class="str">"cmt">//| Copyright class="num">2010, MetaQuotes Software Corp. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//---- 指标的作者 class="macro">#class="kw">property copyright "class="num">2010, MetaQuotes Software Corp." class=class="str">"cmt">//---- 作者网站链接 class="macro">#class="kw">property link "[MQL5官方文档] class=class="str">"cmt">//---- 指标版本号 class="macro">#class="kw">property version "class="num">1.00" class=class="str">"cmt">//----在主窗口中绘制指标 class="macro">#class="kw">property indicator_chart_window class=class="str">"cmt">//---- 一个缓存用于计算和绘制指标 class="macro">#class="kw">property indicator_buffers class="num">1 class=class="str">"cmt">//---- 仅使用一种图形来绘制 class="macro">#class="kw">property indicator_plots class="num">1 class=class="str">"cmt">//---- 画指标线 class="macro">#class="kw">property indicator_type1 DRAW_LINE class=class="str">"cmt">//---- 指标线的颜色为蓝色 class="macro">#class="kw">property indicator_color1 Blue class=class="str">"cmt">//---- 指标线是连续的曲线 class="macro">#class="kw">property indicator_style1 STYLE_SOLID class=class="str">"cmt">//---- 指标线的宽度为2个像素 class="macro">#class="kw">property indicator_width1 class="num">2 class=class="str">"cmt">//---- 显示指标的标签 class="macro">#class="kw">property indicator_label1 "FATL" class=class="str">"cmt">//---- 指标的输入参数 class="kw">input class="type">int FATLShift=class="num">0; class=class="str">"cmt">// FATL horizontal shift in bars class=class="str">"cmt">//---- 声明并初始化一个变量来存储已计算的柱形的数量 class="type">int FATLPeriod=class="num">39; class=class="str">"cmt">//---- 声明动态数组, class=class="str">"cmt">// 将用作指标的缓存 class="type">class="kw">double ExtLineBuffer[]; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 自定义指标初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnInit() { class=class="str">"cmt">//----+ class=class="str">"cmt">//---- 将ExtLineBuffer动态数组变换为指标缓存 SetIndexBuffer(class="num">0,ExtLineBuffer,INDICATOR_DATA); class=class="str">"cmt">//---- FILTERShift,指标的水平偏移 PlotIndexSetInteger(class="num">0,PLOT_SHIFT,FATLShift); class=class="str">"cmt">//----设置指标的开始绘制位置 PlotIndexSetInteger(class="num">0,PLOT_DRAW_BEGIN,FATLPeriod); class=class="str">"cmt">//---- 初始化指标简短名称的变量
FATL 指标的名字与加权递推实现
指标初始化阶段要把数据窗口标签和独立窗口短名都设好。下面这段把偏移量拼进名称,再指定显示精度比当前品种多 1 位,并禁掉 0.0 空值绘制。 string shortname; StringConcatenate(shortname,"FATL(",FATLShift,")"); // 创建数据窗口显示的标签 PlotIndexSetString(0,PLOT_LABEL,shortname); // 创建在独立窗口和工具提示中显示的名称 IndicatorSetString(INDICATOR_SHORTNAME,shortname); // 确定指标值的显示精度 IndicatorSetInteger(INDICATOR_DIGITS,_Digits+1); // 禁止显示空值 PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); OnCalculate 里先卡柱数:rates_total 小于 FATLPeriod-1+begin 直接返回 0,避免数组越界。首根计算位 first 在 prev_calculated==0 时取 FATLPeriod-1+begin,若 begin>0 还要用 PlotIndexSetInteger 把绘制起点推到 begin+FATLPeriod。 主循环从 first 跑到 rates_total,每根 bar 用 11 个历史价格做固定系数加权:最新价是 0.4360409450,最远第 10 根根是 0.0502044896,中间第 4 根出现负系数 -0.0054034585。这组权重来自 FATL 滤波公式,复制进 MT5 自定义指标能直接看到平滑后的快趋势线。外汇与贵金属波动剧烈,该线仅作趋势倾向参考,实盘须自担高风险。
class="type">class="kw">string shortname; StringConcatenate(shortname,"FATL(",FATLShift,")"); class=class="str">"cmt">//--- 创建数据窗口显示的标签 PlotIndexSetString(class="num">0,PLOT_LABEL,shortname); class=class="str">"cmt">//---创建在独立窗口和工具提示中显示的名称 IndicatorSetString(INDICATOR_SHORTNAME,shortname); class=class="str">"cmt">//--- 确定指标值的显示精度 IndicatorSetInteger(INDICATOR_DIGITS,_Digits+class="num">1); class=class="str">"cmt">//--- 禁止显示空值 PlotIndexSetDouble(class="num">0,PLOT_EMPTY_VALUE,class="num">0.0); class="type">int OnCalculate( class="kw">const class="type">int rates_total, class="kw">const class="type">int prev_calculated, class="kw">const class="type">int begin, class="kw">const class="type">class="kw">double &price[] ) { if(rates_total<FATLPeriod-class="num">1+begin) class="kw">return(class="num">0); class="type">int first,bar; class="type">class="kw">double Sum,FATL; if(prev_calculated==class="num">0) { first=FATLPeriod-class="num">1+begin; if(begin>class="num">0) PlotIndexSetInteger(class="num">0,PLOT_DRAW_BEGIN,begin+FATLPeriod); } else first=prev_calculated-class="num">1; for(bar=first; bar<rates_total; bar++) { FATL=class="num">0.4360409450*price[bar-class="num">0] + class="num">0.3658689069 * price[bar - class="num">1] + class="num">0.2460452079 * price[bar - class="num">2] + class="num">0.1104506886 * price[bar - class="num">3] - class="num">0.0054034585 * price[bar - class="num">4] - class="num">0.0760367731 * price[bar - class="num">5] - class="num">0.0933058722 * price[bar - class="num">6] - class="num">0.0670110374 * price[bar - class="num">7] - class="num">0.0190795053 * price[bar - class="num">8] + class="num">0.0259609206 * price[bar - class="num">9] + class="num">0.0502044896 * price[bar - class="num">10];
◍ 远端滞后项的衰减特征
上面这段系数表覆盖了 bar-11 到 bar-38 共 28 个历史价格项,是 FATL 平滑中对远端行情的加权尾声。 可以看到从 bar-11 的 +0.04778 一路衰减,bar-27 附近系数已掉到 0.0069 量级,bar-36 仅剩 +0.00078,说明 37~38 根 K 线前的价格对当前 FATL 值几乎只剩噪声级影响。 系数符号在 bar-13 到 bar-17、bar-22 到 bar-26、bar-31 到 bar-34 出现连续负值,构成三段反向拖拽;而 bar-37 突然回到 +0.01301,比前后项高出一个数量级,这种孤立正冲可能是样本区间里的特定节律残留。 实盘验证时,把 bar-37 的系数手动置 0 再跑 MT5 回测,观察 FATL 曲线在快速反转段的相位是否变得更跟手,能帮你判断这一项该留还是该砍。外汇与贵金属杠杆高,这类滤波改动只代表概率层面的平滑差异,不构成方向建议。
+ class="num">0.0477818607 * price[bar - class="num">11] + class="num">0.0249252327 * price[bar - class="num">12] - class="num">0.0047706151 * price[bar - class="num">13] - class="num">0.0272432537 * price[bar - class="num">14] - class="num">0.0338917071 * price[bar - class="num">15] - class="num">0.0244141482 * price[bar - class="num">16] - class="num">0.0055774838 * price[bar - class="num">17] + class="num">0.0128149838 * price[bar - class="num">18] + class="num">0.0226522218 * price[bar - class="num">19] + class="num">0.0208778257 * price[bar - class="num">20] + class="num">0.0100299086 * price[bar - class="num">21] - class="num">0.0036771622 * price[bar - class="num">22] - class="num">0.0136744850 * price[bar - class="num">23] - class="num">0.0160483392 * price[bar - class="num">24] - class="num">0.0108597376 * price[bar - class="num">25] - class="num">0.0016060704 * price[bar - class="num">26] + class="num">0.0069480557 * price[bar - class="num">27] + class="num">0.0110573605 * price[bar - class="num">28] + class="num">0.0095711419 * price[bar - class="num">29] + class="num">0.0040444064 * price[bar - class="num">30] - class="num">0.0023824623 * price[bar - class="num">31] - class="num">0.0067093714 * price[bar - class="num">32] - class="num">0.0072003400 * price[bar - class="num">33] - class="num">0.0047717710 * price[bar - class="num">34] + class="num">0.0005541115 * price[bar - class="num">35] + class="num">0.0007860160 * price[bar - class="num">36] + class="num">0.0130129076 * price[bar - class="num">37] + class="num">0.0040364019 * price[bar - class="num">38]; class=class="str">"cmt">//---- 用FATL初始化指标缓存单元 ExtLineBuffer[bar]=FATL; } class=class="str">"cmt">//----+ class="kw">return(rates_total); } class=class="str">"cmt">//+------------------------------------------------------------------+