首页 / 交易学院 / 从零写一个 MQL5 自定义指标:SMA 全解剖
从零写一个 MQL5 自定义指标:SMA 全解剖
📐

从零写一个 MQL5 自定义指标:SMA 全解剖

代码结构、#property、OnInit/OnCalculate 与增量计算

MQL5 编程 难度 · 入门 2026-07-10 8 分钟阅读
#MQL5#自定义指标#SMA#OnCalculate#缓冲区

很多新手被一整页指标代码吓退。其实任何 MQL5 自定义指标都有最小且固定的骨架:全局声明、OnInit 初始化、OnCalculate 计算。我们拿最有名的简单移动平均线(SMA)当例子,一行一行拆开看。

一、指标代码的三段结构

第一段是全局层面代码:#property 指令、input 输入参数、以及作为指标缓冲区的动态数组。第二段 OnInit 只在指标加载时执行一次,做一次性设置。第三段 OnCalculate 在每笔新报价到来时被调用,负责计算并写入缓冲区。

✦ 注意
#property 是“常量定义”的另一种写法,末尾没有分号;input 参数后面的注释会直接显示在指标属性窗口里当参数名。

二、#property 与 input:对外暴露的开关

indicator_buffers / indicator_plots 告诉终端要用几个缓冲区和几幅图;indicator_type1 / indicator_color1 定义第一幅图是线形、什么颜色。input int MAPeriod = 13 是用户可在属性窗口改的平均周期;input int MAShift = 0 是水平平移(柱数)。

三、指标缓冲区:动态数组 + SetIndexBuffer

double ExtLineBuffer[] 声明为全局动态数组,它在 OnInit 里通过 SetIndexBuffer(0, ExtLineBuffer, INDICATOR_DATA) 被绑定为第 0 号指标缓冲区;再用 PlotIndexSetInteger 设置平移(PLOT_SHIFT)和绘图起点(PLOT_DRAW_BEGIN = MAPeriod),前 MAPeriod-1 根柱子没东西可平均,不画。

四、OnCalculate:每笔报价都跑一次的计算核心

OnCalculate 的入参由终端传入且为 const:rates_total(可用柱数)、prev_calculated(上次已算柱数)、begin(首柱索引)、price[](计算用价格数组)。柱的索引从 0 开始、0 是最旧的那根,缓冲区和价格数组同序递增。

五、增量计算:别每次都从头算

if(prev_calculated == 0) 算全部柱子,否则只算新出现的柱子(first = prev_calculated - 1)。主循环从左往右累加 MAPeriod 根收盘价求平均,写回 ExtLineBuffer[bar],最后 return rates_total。这样每来一根新 K 线只补算最新的,效率最高。

⚠ 别忘了护栏
柱数不够就直接 return(0):if(rates_total < MAPeriod - 1 + begin) return(0); 否则平均周期大、历史短的时候算出来全是无效值。

小结

常见问题

全局声明放 #property、input 和缓冲区数组,只加载一次;OnInit 负责一次性绑定缓冲区;OnCalculate 在每笔报价被调用做实际计算。三段各司其职,结构清晰也利于维护。
它告诉终端这个指标有几个缓冲区、画几幅图、画成线还是柱、什么颜色,以及绘图起点/平移。没有这些指令,终端不知道怎么把你的数组渲染成图表上的线。
如果每次 OnCalculate 都从头算所有柱子,历史越长越慢。prev_calculated 记录上次算到哪,本次只补算新柱子,是指标性能的基本写法。
.mq5 只是文本源代码,必须在 MetaEditor 里 Compile 编译成 .ex5 后,才能从导航器拖到图表上使用。