首页 / 交易学院 / 小布知识库 / MQL5 无额外缓冲区的平滑算法类库
MQL5 无额外缓冲区的平滑算法类库
🧩

MQL5 无额外缓冲区的平滑算法类库

MQL5 编程 难度 · 高阶 2013 13 分钟阅读
平滑算法类库性能

一、为什么不用额外缓冲区

经典的做法是先算好中间结果放进“指标缓冲区”,再基于该缓冲区搜索做平均——这就需要额外的指标级缓冲区,代码又臭又长,而且每次调用 iMA 之类做中间计算并不快。本文的思路是:把中间状态保存在函数内部的类成员变量/小数组里,用递推方式在单周期内完成平均,完全不需要指标级额外缓冲区。

二、核心思路:内部状态递推

传统平均要取前 n 个值,必须开缓冲。改进后把“选值+累减”放进函数自身:当前柱的新值写入状态,最老的值移除,只保留“算一个柱所需”的精确数据量。关键是——在算当前柱之前,必须已在所有前柱上调用过该函数,状态才连续。这本质是用类成员+内部动态数组替代指标缓冲区,类似 EMA 的递推 EMA[i]=α·price[i]+(1-α)·EMA[i-1] 只需前一值。

三、平滑算法家族

文章把多种平滑封装成类(继承 CMovSeriesTools),并支持“可靠柱起始平移”与部分“动态改 Length”:

四、OnCalculate 里的递推调用

#include <MASeries_Cls.mqh>
static CMoving_Average MA1, MA2, MA3, MA4; // 静态:跨调用保留状态

int first = (prev_calculated==0)? 0 : prev_calculated-1;
for(int bar=first; bar<rates_total; bar++)
  {
   double m1 = MA1.MASeries(0, prev_calculated, rates_total, Length1, MODE_SMA,  price[bar], bar, false);
   double m2 = MA2.MASeries(0, prev_calculated, rates_total, Length2, MODE_EMA,  m1,        bar, false);
   double m3 = MA3.MASeries(0, prev_calculated, rates_total, Length3, MODE_SMMA, m2,        bar, false);
   double m4 = MA4.MASeries(0, prev_calculated, rates_total, Length4, MODE_LWMA, m3,        bar, false);
   MAx4[bar] = m4 + dPriceShift;
  }

五、相比标准指标的优势

六、坑

⚠ 顺序与声明是命门
1) 必须顺序调用:想在当前柱取平均值,必须先在所有前柱上调用过,否则内部状态错。2) 静态声明:类变量须在全局或 OnInit 声明为 static,不能在成员函数内声明静态类变量。3) 起点偏移:不同算法平移不同(如 LWMA 非末端要 +Length+1),不清晰时取大再递减。4) 除零防护:分母可能为 0 时赋 EMPTY_VALUE。5) 部分算法 Length 运行时不可改(EMA 参数为 double 但固定),只有 JMA/T3/超线性支持动态 Length。

七、各类平滑算法对比

平滑是把噪音滤掉、凸显趋势。SMA 简单但滞后等权;EMA 给近期更大权重、反应更快;SMMA(Wilder)更平滑适合慢线;还有各种自定义平滑核。选哪种取决于你要多快反应、能接受多大滞后。

没有最好的平滑,只有最适合信号的。短线信号用快平滑(EMA),长线趋势用慢平滑(SMMA),混用才是常态。

八、用 CSeries 类取平滑序列

标准库的 CSeries 系列(如 CiMA、CiSmooth)封装了「计算某指标的平滑序列」的逻辑,你直接拿缓冲值,不必自己写递推。换算法只改构造参数,代码更干净。

CiMA ma;
ma.Create(_Symbol, PERIOD_M15, 14, 0, MODE_EMA, PRICE_CLOSE);
double v = ma.Main(0);   // 最新 EMA 值
✦ 用类别手搓递推
CSeries 类封装了平滑计算与缓冲管理,换算法只改参数。手搓递推容易在边界(前 N 根)出 bug。

九、平滑的滞后权衡

平滑越强、滞后越大:噪音滤干净了,但信号也慢半拍,容易买在趋势中段、卖在回吐时。弱平滑反应快但易被噪音骗。权衡点在「你的策略靠不靠速度」。

实用做法:快慢两条平滑线配合——快线出信号、慢线定方向,既过滤噪音又不全丢速度。这比单条线鲁棒。

十、小结

✦ 小结
平滑滤噪音、凸显趋势:SMA 等权滞后、EMA 快、SMMA 更慢更平滑,按策略速度需求选。用 CSeries 类取序列最稳,换算法只改参数。核心权衡是滞后 vs 噪音,快慢双线配合比单线鲁棒。

常见问题

不是不要状态,而是不要“指标级缓冲区”。EMA 递推只需要前一个 EMA 值,这个值存在类成员变量里就行,不必开一个 INDICATOR_DATA/CALCULATIONS 缓冲。文章用类内部小数组滚动存储,达到同样效果但更省内存、更好复用。
因为递推状态是跨柱累积的(类似 EMA 依赖上一根的值)。如果你只从某根开始算,前面的状态是空的,结果会从错误基准出发,整条线都偏。所以初始化阶段也要从第一根开始把函数跑一遍把状态建起来。
对“在指标内部反复做中间平均”的场景,能且更快——省去反复调用 iMA 的开销。但若只是要一条标准 MA 线,直接用 iMA 句柄+CopyBuffer 更简单。文章的价值在于把多种平滑(JMA/T3/CCMO 等)做成可链式调用的类库。