针对初学者的 MQL 5 中的自定义指标(基础篇)
在 MT5 里写第一个自定义指标
MQL5 的自定义指标和 EA 不同,它不参与下单,只负责在图表上算数、画线、出缓冲。对刚接触 MT5 的开发者来说,先搞懂指标文件结构比背语法更重要。
一个最基础的指标要声明 #property indicator_separate_window 或主图叠加,并至少定义一个缓冲区(buffer)用来存计算结果。MT5 会在每根 K 线走完或实时 tick 进来时,调用 OnCalculate 把值写进 buffer。
官方示例库里有一篇 2013-09-13 发布的入门贴,累计浏览 8 066、评论 23,作者 Nikolay Kositsin。这个数字说明:即便多年过去,最朴素的自定义指标写法仍是新手高频查阅对象,你照着敲一遍比看十篇概念文更实在。
「中年起步的交易编程门槛」
任何学科的底子都建立在基础认知上,数学、音乐、编程皆如此。若从很小就开始接触相似训练,底层逻辑会建立得更具体全面,后续学复杂内容阻力小。 现实里,多数做外汇和贵金属的人是人到中年才第一次碰金融与股票市场,此时再回头补基础,理解成本明显偏高,且容易卡在工具层。 本文这一节只做一件事:帮你跨过用 MQL5 给 MetaTrader 5 写自定义指标的最初那道坎。外汇与贵金属杠杆高、波动剧烈,先能把工具跑通,才有谈策略的前提。
◍ 用一段裸 SMA 代码看清指标骨架
想弄懂 MT5 自定义指标怎么跑,最快的路子不是看文档,而是直接读一段能编译、能上图的裸代码。下面这份简单移动平均线(SMA)示例不夹任何花活,只做一件事:把最近 MAPeriod 根 K 线的收盘价加总除以周期数。 公式层面,SMA = SUM(CLOSE(i), MAPeriod) / MAPeriod。SUM 是窗口内收盘价求和,CLOSE(i) 是第 i 根柱的收盘,MAPeriod 就是平均周期。代码里默认 MAPeriod=13、MAShift=0,意味着主图红线上没有任何水平偏移。 代码头部用 #property 声明了三件关键事:indicator_chart_window 表示画在主图而非独立窗口;indicator_buffers 1 和 indicator_plots 1 说明只有一个数据缓冲、一条绘制线;indicator_type1 DRAW_LINE 配合 indicator_color1 Red 把这条线渲染成红色。 OnInit 里 SetIndexBuffer(0, ExtLineBuffer, INDICATOR_DATA) 把数组绑给 0 号缓冲;PlotIndexSetInteger 两行分别设了线偏移和起始绘制位置(MAPeriod-1 之前数据不足不画)。OnCalculate 中若 rates_total 小于 MAPeriod-1 直接返回 0;首次计算从 MAPeriod-1+begin 起,后续借助 prev_calculated 只补算新 bar,双层循环求 Sum 再除周期写进缓冲。 打开 MT5 新建一个 SMA.mq5,把上面代码整段贴入编译,拖到 EURUSD 图表上,你就能看到一条 13 期红色均线。外汇与贵金属杠杆高、回测不代表实盘,调 MAPeriod 从 13 改成 5 或 50,可直观比对平滑度差异。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| SMA.mq5 | class=class="str">"cmt">//| Copyright class="num">2009, MetaQuotes Software Corp. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property indicator_chart_window class="macro">#class="kw">property indicator_buffers class="num">1 class="macro">#class="kw">property indicator_plots class="num">1 class="macro">#class="kw">property indicator_type1 DRAW_LINE class="macro">#class="kw">property indicator_color1 Red class="kw">input class="type">int MAPeriod = class="num">13; class="kw">input class="type">int MAShift = class="num">0; class="type">class="kw">double ExtLineBuffer[]; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 自定义指标初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnInit() { SetIndexBuffer(class="num">0, ExtLineBuffer, INDICATOR_DATA); PlotIndexSetInteger(class="num">0, PLOT_SHIFT, MAShift); PlotIndexSetInteger(class="num">0, PLOT_DRAW_BEGIN, MAPeriod - class="num">1); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 自定义指标迭代函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ 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 < MAPeriod - class="num">1) class="kw">return(class="num">0); class="type">int first, bar, iii; class="type">class="kw">double Sum, SMA; if (prev_calculated == class="num">0) first = MAPeriod - class="num">1 + begin; else first = prev_calculated - class="num">1; for(bar = first; bar < rates_total; bar++) { Sum = class="num">0.0; for(iii = class="num">0; iii < MAPeriod; iii++) Sum += price[bar - iii]; SMA = Sum / MAPeriod; ExtLineBuffer[bar] = SMA; } class="kw">return(rates_total); } class=class="str">"cmt">//+------------------------------------------------------------------+
注释只是给读代码的人看的
打开一段 MT5 指标源码,最先撞进眼里的往往是成排的 "//" 开头行。它们就是单行注释,从 "//" 起、到换行止,编译器直接跳过,不参与任何运算。 把注释整段删掉,程序该算什么还算什么,逻辑零损伤;但一周后你回看自己的 SMA 逻辑,大概率得从头脑补哪段是 OnInit 哪段是 OnCalculate。注释存在的唯一理由,是保住代码的可读性。 示例里第一部分写指标名和版权,中间用分隔条标出初始化函数与迭代函数,最后一行收尾关代码。作者想在 "//" 后面写任何帮理解的话都行,外汇与贵金属 EA 开发高风险,注释写清假设比写漂亮话有用。 下面这段就是典型单行注释块,逐行看:前四行用 "//+---+" 画框并标出 SMA.mq5 及版权信息;接着两个分隔块分别标 "自定义指标初始化函数" 和 "自定义指标迭代函数";最末 "//+---+" 只是收尾。全部以 "//" 起头,对执行无任何影响。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| SMA.mq5 | class=class="str">"cmt">//| Copyright class="num">2009, MetaQuotes Software Corp. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 自定义指标初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 自定义指标迭代函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+