初学者以 MQL5 实现对数字滤波器的实际实施·进阶篇
(2/3)· 编译零错误不代表逻辑无误,弄懂 MetaEditor 报错机制才能少走弯路
「拿现成SMA模板改出FATL数字滤波器」
想在 MT5 里快速写一个新指标,没必要从空白文件啃语法。拿之前写好的 SMA 指标代码当模板,改算法和变量名就能省掉大量重复劳动。比如 FATL 这种数字滤波器,公式本质是加权求和:滤波器 = SUM(K(i) * CLOSE(i), FilterPeriod),和 SMA = SUM((1/MAPeriod)*CLOSE(i), MAPeriod) 结构几乎一样,只是权重 K(i) 和周期是指定的。 MQL4 里 FATL 用 Close[bar+偏移] 正向取价,但 MQL5 的指标缓冲区计算是反向的,且没有 Close[] 时序数组。所以在 MetaEditor 里用「全部替换」把 Close[bar+表达式] 换成 price[bar-表达式],方向就对了。 实操路径:打开 SMA_1_en.mq5 另存为 FATL_en.mq5,删掉循环里除缓冲区初始化外的代码,把 FATL 公式块贴进去;再把文字 SMA 替换成 FATL,MAPeriod/MAShift 改成 FATLPeriod/FATLShft。FATLPeriod 固定为 39,直接从外部变量和 StringConcatenate() 里删掉,局部变量 iii 也可删,线色改成蓝色加粗即可编译测试。 FATL 指标的成品代码就是后续其他滤波器的母板。以后再写类似指标,只需替换计算公式、把 FATL 字样改成 DIGFILTER、给 DIGFILTERPeriod 赋对应维度。外汇与贵金属市场波动剧烈, Indicators 仅作参考,实盘前务必在策略测试器跑历史数据验证。
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 快趋势线拆解成 30 根 K 线的线性加权。注意 bar-0 到 bar-3 的系数均为正且递减(0.4360、0.3659、0.2460、0.1105),说明近期收盘价对当前 FATL 值主导权最高。 从 bar-4 开始系数转负并探至 bar-7 的 -0.0933 谷底,随后在正负之间震荡收敛,到 bar-29 只剩 0.0096 的微正权重。这种远端弱、近端强的结构,让 FATL 对最新价格反应灵敏,又滤掉了 30 周期外的噪声。 原文里还有一段以 Close[bar+29] 到 Close[bar+38] 为正向加权(最高 +0.0130)的辅助项,它用的是未来偏移收盘价做平滑参考,实盘不能直接照抄,仅用于理解滤波器设计思路。外汇与贵金属杠杆高,此类加权均线仅作概率参考,不代表方向必然成立。
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 取正系数 0.0040444064,bar-31 到 bar-34 连续四个负系数(最小 -0.0072003400 在 bar-33),bar-35、36 微弱转正,bar-37 突然拉到 +0.0130129076,最后 bar-38 收在 +0.0040364019。这种远端跳变权重说明滤波器对 37 根前的价格仍保留较强记忆,回测 EURUSD H1 时容易在趋势反转第 3~4 根就钝化。 主循环极简:从 first 跑到 rates_total,每根直接把已算好的 FATL 值写进 ExtLineBuffer[bar],不另做平滑。也就是说指标线本身就是 FATL 序列的裸绘制,想改显示滞后只要动 OnInit 里的 PlotIndexSetInteger(0,PLOT_SHIFT,FATLShift)。 初始化段把缓存绑成 INDICATOR_DATA,画线和宽度写死 Blue / 2px,FATLPeriod=39 同时用作 DRAW_BEGIN,前 38 根不画——开 MT5 把周期改成 21 看前段空白是否缩短,就能验证这个耦合。
+ 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指标的名称绑定与加权计算核心」
在 MT5 自定义指标里,先把数据窗口标签和独立窗口短名绑定到动态字符串上,能让多周期加载时不撞名。下面这段代码把『FATL(偏移值)』拼进 shortname,再分别用 PlotIndexSetString 和 IndicatorSetString 写到图表与 tooltip,显示精度取 _Digits+1,空值禁显为 0.0。 代码里的 OnCalculate 是逐根重算入口。若 rates_total 小于 FATLPeriod-1+begin 直接 return(0),说明历史柱不够;首根计算位 first 在 prev_calculated==0 时定为 FATLPeriod-1+begin,若 begin>0 还要用 PlotIndexSetInteger 把绘图起点往后推 begin+FATLPeriod 根。 主循环从 first 扫到 rates_total,FATL 值是 price 数组近 11 根(bar-0 到 bar-10)的固定系数加权:最近三根系数 0.436/0.365/0.246 为正且递减,bar-4 到 bar-7 转负,bar-9 与 bar-10 又回正 0.0259/0.0502。这组权重是 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=class="str">"cmt">// 当前报价下的历史柱形数据 class="kw">const class="type">int prev_calculated, class=class="str">"cmt">// 先前报价下的历史柱形数据 class="kw">const class="type">int begin, class=class="str">"cmt">// 开始有效计算的柱形位置 class="kw">const class="type">class="kw">double &price[] class=class="str">"cmt">// 用于指标计算的价格数组 ) { class=class="str">"cmt">//---- 检查用于计算的柱形数量是否足够 if(rates_total<FATLPeriod-class="num">1+begin) class="kw">return(class="num">0); class=class="str">"cmt">//---- 声明局部变量 class="type">int first,bar; class="type">class="kw">double Sum,FATL; class=class="str">"cmt">//---- 柱形重算循环中,计算“第一个”开始值 if(prev_calculated==class="num">0) class=class="str">"cmt">//检查第一个指标值的计算 { first=FATLPeriod-class="num">1+begin; class=class="str">"cmt">// 所有柱形的开始计算位置 class=class="str">"cmt">//--- 在“begin”柱的基础上增加数据开始位,因为 class=class="str">"cmt">// 此计算是基于另外一个指标的值 if(begin>class="num">0) PlotIndexSetInteger(class="num">0,PLOT_DRAW_BEGIN,begin+FATLPeriod); } else first=prev_calculated-class="num">1; class=class="str">"cmt">// 新柱形计算的开始位置 class=class="str">"cmt">//---- 指标计算的主循环 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]
远端滞后项的衰减尾巴
上面这段是 FATL 平滑函数尾部的滞后项累加,覆盖 bar-11 到 bar-38 共 28 个历史价格点。系数从 bar-11 的 +0.04778 一路衰减,到 bar-35 附近已贴近 0(仅 +0.00055),说明 35 根 K 线以外的价格对当前平滑值几乎无贡献。 注意 bar-13 到 bar-17 出现连续负值(-0.00477 至 -0.03389),这是滤波核在抵消中频噪声;而 bar-37 突然回弹到 +0.01301,属于长周期分量的残留权重。直接在 MT5 里把这段贴进自定义指标,改 ExtLineBuffer 输出,就能看到远端项对曲线的拖尾效果。 外汇与贵金属波动剧烈,这类平滑值仅作趋势参考,实盘信号概率性成立,不代表方向确定性。
+ 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">//+------------------------------------------------------------------+