MQL5 简介(第 12 部分):构建自定义指标的初学者指南·进阶篇
📊

MQL5 简介(第 12 部分):构建自定义指标的初学者指南·进阶篇

(2/3)· 不调用 iMA 也能画出均线,并把线变成会说话的烛形

偏理论进阶 第 2/3 篇
不少交易者把内置 iMA、iRSI 当成指标的全部,一旦平台没给现成函数就束手无策。依赖封装接口会让你失去对计算逻辑的控制,遇到非常规品种周期只能干瞪眼。本篇拆掉这层黑箱,让你自己造工具。

◍ 彩色均线蜡烛的缓冲区账本

把移动平均画成蜡烛而不是线,第一道坎就是缓冲区数量。常规蜡烛需要开高低收 4 个缓冲区,但 MT5 的 DRAW_COLOR_CANDLES 绘图类型强制要求第 5 个颜色索引缓冲区:0 映射绿色看涨、1 映射红色看跌。少一个,编译能过,图表上却可能只显示空白或错色。 指标属性里 indicator_separate_window 决定它挂在副图而非主图;indicator_plots 1 配合 indicator_type1 DRAW_COLOR_CANDLES,再靠 indicator_color1 clrGreen,clrRed 绑定双色。实线边缘用 STYLE_SOLID、线宽 1 即可,这些在 #property 段一次写死,运行时不用动。 OnCalculate 里有个硬门槛:if(rates_total < period) 直接 return 0 并写错误。意思是历史柱数不够周期就别算,否则均值分母无效,统计会骗人。验证过周期数据后,外循环从 period-1 起步,内循环累加前 period 根柱的 open/high/low/close,sum 除周期得均值写进四个缓冲,再用 close>=open 判绿、否则判红写 ColorBuffer。 PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, period) 这句很关键,它让指标在第 period 根柱之后才起笔,避免左端缺数据导致的半截蜡烛。rates_total 作为返回值交给 MT5,是后续实时更新追柱的锚点。 这套蜡烛化均值结构,顺手给 Heikin Ashi 类指标留了接口,缓冲区的接法完全一致,后面换算法即可。

三均线叠加的绘图属性配置

在 MT5 自定义指标里,用 #property 前缀的编译指令可以直接定义多条均线的图表呈现,不必写一行绘图逻辑。下面这段配置同时挂了 MA200、MA100、MA50 三条线,分别用蓝、棕、紫区分,且都画在主图窗口(indicator_chart_window),和价格重叠看位。 注意原文里 indicator_label3 被重复声明了两次,都是 "MA 50",这种重复在编译时不会报错,但会拖慢预处理解析,实盘拷贝代码时建议删掉冗余块。MA200 用了 STYLE_DASHDOTDOT(点划线点),MA100 是 STYLE_DASH(虚线),MA50 是 STYLE_DOT(点线),线宽统一为 1。 indicator_buffers 和 indicator_plots 都设为 3,意味着指标预留了 3 个数据缓冲区和 3 个绘图通道。若你之后想加一条 MA20,两个数值都得改成 4,否则新线画不出来。外汇与贵金属波动剧烈,多均线叠加仅作趋势参照,杠杆风险高,信号失效可能很快。

MQL5 / C++
class="macro">#class="kw">property indicator_label3  "MA class="num">50"      class=class="str">"cmt">//GIVE PLOT TWO A NAME
class="macro">#class="kw">property indicator_type3   DRAW_LINE   class=class="str">"cmt">//TYPE OF PLOT THE THIRD MA
class="macro">#class="kw">property indicator_style3  STYLE_DOT   class=class="str">"cmt">//STYLE OF SPOT THE THIRD MA
class="macro">#class="kw">property indicator_width3  class="num">1           class=class="str">"cmt">//LINE THICKNESS THE THIRD MA
class="macro">#class="kw">property indicator_color3  clrPurple   class=class="str">"cmt">//LINE COLOR THE THIRD MA
class="macro">#class="kw">property indicator_label1  "MA class="num">200"      class=class="str">"cmt">//GIVE PLOT ONE A NAME
class="macro">#class="kw">property indicator_type1   DRAW_LINE   class=class="str">"cmt">//TYPE OF PLOT THE FIRST MA 
class="macro">#class="kw">property indicator_style1  STYLE_DASHDOTDOT   class=class="str">"cmt">//STYLE OF SPOT THE FIRST MA
class="macro">#class="kw">property indicator_width1  class="num">1           class=class="str">"cmt">//LINE THICKNESS THE FIRST MA
class="macro">#class="kw">property indicator_color1  clrBlue     class=class="str">"cmt">//LINE COLOR THE FIRST MA
class="macro">#class="kw">property indicator_label2  "MA class="num">100"   class=class="str">"cmt">//GIVE PLOT TWO A NAME
class="macro">#class="kw">property indicator_type2   DRAW_LINE   class=class="str">"cmt">//TYPE OF PLOT THE SECOND MA
class="macro">#class="kw">property indicator_style2  STYLE_DASH   class=class="str">"cmt">//STYLE OF SPOT THE SECOND MA
class="macro">#class="kw">property indicator_width2  class="num">1           class=class="str">"cmt">//LINE THICKNESS THE SECOND MA
class="macro">#class="kw">property indicator_color2  clrBrown     class=class="str">"cmt">//LINE COLOR THE SECOND MA
class="macro">#class="kw">property indicator_label3  "MA class="num">50"      class=class="str">"cmt">//GIVE PLOT TWO A NAME
class="macro">#class="kw">property indicator_type3   DRAW_LINE   class=class="str">"cmt">//TYPE OF PLOT THE THIRD MA
class="macro">#class="kw">property indicator_style3  STYLE_DOT   class=class="str">"cmt">//STYLE OF SPOT THE THIRD MA
class="macro">#class="kw">property indicator_width3  class="num">1           class=class="str">"cmt">//LINE THICKNESS THE THIRD MA
class="macro">#class="kw">property indicator_color3  clrPurple   class=class="str">"cmt">//LINE COLOR THE THIRD MA
class=class="str">"cmt">//INDICATOR IN CHART WINDOW
class="macro">#class="kw">property indicator_chart_window
class=class="str">"cmt">//SET INDICATOR BUFFER TO STORE DATA
class="macro">#class="kw">property indicator_buffers class="num">3
class=class="str">"cmt">//SET NUMBER FOR INDICATOR PLOTS
class="macro">#class="kw">property indicator_plots   class="num">3
class=class="str">"cmt">//SETTING PLOTS PROPERTIES
class=class="str">"cmt">//PROPERTIES OF THE FIRST MA(MA200)
class="macro">#class="kw">property indicator_label1  "MA class="num">200"   class=class="str">"cmt">//GIVE PLOT ONE A NAME
class="macro">#class="kw">property indicator_type1   DRAW_LINE   class=class="str">"cmt">//TYPE OF PLOT THE FIRST MA 
class="macro">#class="kw">property indicator_style1  STYLE_DASHDOTDOT   class=class="str">"cmt">//STYLE OF SPOT THE FIRST MA
class="macro">#class="kw">property indicator_width1  class="num">1           class=class="str">"cmt">//LINE THICKNESS THE FIRST MA
class="macro">#class="kw">property indicator_color1  clrBlue     class=class="str">"cmt">//LINE COLOR THE FIRST MA

「给三条均线分配画图属性与数据缓冲」

在 MT5 自定义指标里,三条均线(MA200 / MA100 / MA50)要同图显示,得先声明 3 个 plot 和 3 个 buffer。原文用 #property indicator_plots 3#property indicator_buffers 3 锁定了数量,并在主图窗口绘制(indicator_chart_window)。 MA100 被设成棕色虚线(clrBrown + STYLE_DASH),MA50 是紫色点线(clrPurple + STYLE_DOT),线宽都取 1。视觉上把快慢均线区分开,扫图时能直接看出排列关系,贵金属与外汇品种的高波动下这点尤其实用。 OnInit() 里用 SetIndexBuffer(0, buffer_mA200, INDICATOR_DATA) 把数组绑到索引 0,MA100 绑索引 1,MA50 绑索引 2。缓冲绑错索引,图表会画出串线的怪象,开 MT5 加载前务必核对注释里的 INDEX 对应。 外汇和贵金属杠杆高、滑点大,指标只是概率参考;均线排列多头不意味价格必涨,实盘前先用策略测试器跑一遍 EURUSD 的 H1 历史验证缓冲绑定无误。

MQL5 / C++
class="macro">#class="kw">property indicator_label2  "MA class="num">100"   class=class="str">"cmt">//GIVE PLOT TWO A NAME
class="macro">#class="kw">property indicator_type2   DRAW_LINE   class=class="str">"cmt">//TYPE OF PLOT THE SECOND MA
class="macro">#class="kw">property indicator_style2  STYLE_DASH  class=class="str">"cmt">//STYLE OF SPOT THE SECOND MA
class="macro">#class="kw">property indicator_width2  class="num">1           class=class="str">"cmt">//LINE THICKNESS THE SECOND MA
class="macro">#class="kw">property indicator_color2  clrBrown    class=class="str">"cmt">//LINE COLOR THE SECOND MA
class="macro">#class="kw">property indicator_label3  "MA class="num">50"     class=class="str">"cmt">//GIVE PLOT TWO A NAME
class="macro">#class="kw">property indicator_type3   DRAW_LINE   class=class="str">"cmt">//TYPE OF PLOT THE THIRD MA
class="macro">#class="kw">property indicator_style3  STYLE_DOT   class=class="str">"cmt">//STYLE OF SPOT THE THIRD MA
class="macro">#class="kw">property indicator_width3  class="num">1           class=class="str">"cmt">//LINE THICKNESS THE THIRD MA
class="macro">#class="kw">property indicator_color3  clrPurple   class=class="str">"cmt">//LINE COLOR THE THIRD MA
class="type">class="kw">double buffer_mA200[];  class=class="str">"cmt">//BUFFER FOR THE FIRST MA
class="type">class="kw">double buffer_mA100[];  class=class="str">"cmt">//BUFFER FOR THE SECOND MA
class="type">class="kw">double buffer_mA50[];   class=class="str">"cmt">//BUFFER FOR THE THIRD MA
class="type">int OnInit()
  {
  SetIndexBuffer(class="num">0, buffer_mA200, INDICATOR_DATA);  class=class="str">"cmt">//INDEX class="num">0 FOR MA200
  SetIndexBuffer(class="num">1, buffer_mA100, INDICATOR_DATA);  class=class="str">"cmt">//INDEX class="num">1 FOR MA100
  SetIndexBuffer(class="num">2, buffer_mA50, INDICATOR_DATA);   class=class="str">"cmt">//INDEX class="num">1 FOR MA50
  class="kw">return(INIT_SUCCEEDED);
  }
class="macro">#class="kw">property indicator_chart_window
class="macro">#class="kw">property indicator_buffers class="num">3
class="macro">#class="kw">property indicator_plots   class="num">3
class="macro">#class="kw">property indicator_label1  "MA class="num">200"   class=class="str">"cmt">//GIVE PLOT ONE A NAME

◍ 三均线指标的绘图属性与缓冲绑定

在 MT5 自定义指标里,#property 指令直接决定三条均线的视觉区分度。第一段声明把第一根线设为 DRAW_LINE 类型、STYLE_DASHDOTDOT 点划点线、宽度 1、clrBlue 蓝色,用来画 MA200;第二段给 MA100 命名为「MA 100」,用 STYLE_DASH 虚线、clrBrown 棕色;第三段 MA50 用 STYLE_DOT 点线、clrPurple 紫色。三种线型加三种颜色,肉眼扫图时不会把周期混淆。 数据缓冲用 double 数组承接:buffer_mA200、buffer_mA100、buffer_mA50 分别存三条均线的数值。周期通过 input int 暴露给使用者,默认值分别是 200、100、50,改参数不用动核心逻辑。 OnInit 里用 SetIndexBuffer 把数组绑到指标索引 0/1/2,类型都是 INDICATOR_DATA。紧接 PlotIndexSetInteger 设置 PLOT_DRAW_BEGIN,值等于对应周期——MA200 要攒够 200 根 bar 才起画,否则前段会是空线。跑通后返回 INIT_SUCCEEDED,指标即完成初始化。 别把正态当圣经:线型只是辅助辨识,真要判方向还得看均线夹角和价格位置关系,外汇和贵金属杠杆高,视觉清爽不代表信号可靠。

MQL5 / C++
class="macro">#class="kw">property indicator_type1   DRAW_LINE   class=class="str">"cmt">//TYPE OF PLOT THE FIRST MA 
class="macro">#class="kw">property indicator_style1   STYLE_DASHDOTDOT   class=class="str">"cmt">//STYLE OF SPOT THE FIRST MA
class="macro">#class="kw">property indicator_width1   class="num">1        class=class="str">"cmt">//LINE THICKNESS THE FIRST MA
class="macro">#class="kw">property indicator_color1   clrBlue    class=class="str">"cmt">//LINE COLOR THE FIRST MA
class=class="str">"cmt">//PROPERTIES OF THE SECOND MA(MA100)
class="macro">#class="kw">property indicator_label2   "MA class="num">100"   class=class="str">"cmt">//GIVE PLOT TWO A NAME
class="macro">#class="kw">property indicator_type2   DRAW_LINE   class=class="str">"cmt">//TYPE OF PLOT THE SECOND MA
class="macro">#class="kw">property indicator_style2   STYLE_DASH   class=class="str">"cmt">//STYLE OF SPOT THE SECOND MA
class="macro">#class="kw">property indicator_width2   class="num">1         class=class="str">"cmt">//LINE THICKNESS THE SECOND MA
class="macro">#class="kw">property indicator_color2   clrBrown    class=class="str">"cmt">//LINE COLOR THE SECOND MA
class=class="str">"cmt">//PROPERTIES OF THE THIRD MA(MA50)
class="macro">#class="kw">property indicator_label3   "MA class="num">50"     class=class="str">"cmt">//GIVE PLOT TWO A NAME
class="macro">#class="kw">property indicator_type3   DRAW_LINE   class=class="str">"cmt">//TYPE OF PLOT THE THIRD MA
class="macro">#class="kw">property indicator_style3   STYLE_DOT   class=class="str">"cmt">//STYLE OF SPOT THE THIRD MA
class="macro">#class="kw">property indicator_width3   class="num">1         class=class="str">"cmt">//LINE THICKNESS THE THIRD MA
class="macro">#class="kw">property indicator_color3   clrPurple    class=class="str">"cmt">//LINE COLOR THE THIRD MA
class=class="str">"cmt">//SET MA BUFFER TO STORE DATA
class="type">class="kw">double buffer_mA200[];  class=class="str">"cmt">//BUFFER FOR THE FIRST MA
class="type">class="kw">double buffer_mA100[];  class=class="str">"cmt">//BUFFER FOR THE SECOND MA
class="type">class="kw">double buffer_mA50[];   class=class="str">"cmt">//BUFFER FOR THE THIRD MA
class=class="str">"cmt">//SET MA PERIOD
input class="type">int period_ma200 = class="num">200;  class=class="str">"cmt">//PERIOD FOR THE FIRST MA
input class="type">int period_ma100 = class="num">100;  class=class="str">"cmt">//PERIOD FOR THE SECOND MA
input class="type">int period_ma50  = class="num">50;   class=class="str">"cmt">//PERIOD FOR THE THIRD MA
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Custom indicator initialization function                         |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
class=class="str">"cmt">//SETTING BUFFER
   SetIndexBuffer(class="num">0, buffer_mA200, INDICATOR_DATA);  class=class="str">"cmt">//INDEX class="num">0 FOR MA200
   SetIndexBuffer(class="num">1, buffer_mA100, INDICATOR_DATA);  class=class="str">"cmt">//INDEX class="num">1 FOR MA100
   SetIndexBuffer(class="num">2, buffer_mA50, INDICATOR_DATA);   class=class="str">"cmt">//INDEX class="num">1 FOR MA50
class=class="str">"cmt">//SETTING BARS TO START PLOTTING
   PlotIndexSetInteger(class="num">0, PLOT_DRAW_BEGIN, period_ma200);
   PlotIndexSetInteger(class="num">1, PLOT_DRAW_BEGIN, period_ma100);
   PlotIndexSetInteger(class="num">2, PLOT_DRAW_BEGIN, period_ma50);
class=class="str">"cmt">//---
   class="kw">return(INIT_SUCCEEDED);
  }

三均线缓冲区的填充与绘制起点

指标核心计算放在 OnCalculate 里,用三段独立循环分别填 MA200、MA100、MA50 的缓冲区。MA200 取 high 序列的均值,MA100 取 close,MA50 取 open,这种采样源差异会让三条线在同样周期参数下呈现不同敏感度和相位偏移,读者可在 MT5 里改采样源验证曲线形态变化。 循环起点都是 period - 1,因为第 0 到 period-2 根 K 线不足以凑满窗口;每次把对应长度的序列反向累加再除以周期数写进 buffer。return 直接给 rates_total,意味着每根新柱都重算全量,小周期跑历史数据可能偏慢,但逻辑最直白。 周期由三个 input 控制:200、100、50,都是整数 extern 变量,可在加载指标时改。PlotIndexSetInteger 把每条线的 PLOT_DRAW_BEGIN 设为各自周期,避免前面空段画零值——MA200 要从第 199 根之后才开始有有效输出。外汇与贵金属杠杆高,均线仅是概率参考,实盘须自担风险。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Custom indicator iteration function                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnCalculate(const class="type">int rates_total,
                const class="type">int prev_calculated,
                const class="type">class="kw">datetime &time[],
                const class="type">class="kw">double &open[],
                const class="type">class="kw">double &high[],
                const class="type">class="kw">double &low[],
                const class="type">class="kw">double &close[],
                const class="type">long &tick_volume[],
                const class="type">long &volume[],
                const class="type">int &spread[])
  {
class=class="str">"cmt">//CALCULATE THE MOVING AVERAGE FOR THE THE First MA(MA200)
   for(class="type">int i = period_ma200 - class="num">1; i < rates_total; i++)
     {
      class="type">class="kw">double sum = class="num">0.0;
      for(class="type">int j = class="num">0; j < period_ma200; j++)
        {
         sum += high[i - j];
        }
      buffer_mA200[i] = sum / period_ma200;
     }
class=class="str">"cmt">//CALCULATE THE MOVING AVERAGE FOR THE THE SECOND MA(MA100)
   for(class="type">int i = period_ma100 - class="num">1; i < rates_total; i++)
     {
      class="type">class="kw">double sum = class="num">0.0;
      for(class="type">int j = class="num">0; j < period_ma100; j++)
        {
         sum += close[i - j];
        }
      buffer_mA100[i] = sum / period_ma100;
     }
class=class="str">"cmt">//CALCULATE THE MOVING AVERAGE FOR THE THE THIRD MA(MA50)
   for(class="type">int i = period_ma50 - class="num">1; i < rates_total; i++)
     {
      class="type">class="kw">double sum = class="num">0.0;
      for(class="type">int j = class="num">0; j < period_ma50; j++)
        {
         sum += open[i - j];
        }
      buffer_mA50[i] = sum / period_ma50;
     }
class=class="str">"cmt">//--- class="kw">return value of prev_calculated for next call
   class="kw">return(rates_total);
  }
class=class="str">"cmt">//SET MA PERIOD
input class="type">int period_ma200 = class="num">200;   class=class="str">"cmt">//PERIOD FOR THE FIRST MA
input class="type">int period_ma100 = class="num">100;   class=class="str">"cmt">//PERIOD FOR THE SECOND MA
input class="type">int period_ma50  = class="num">50;    class=class="str">"cmt">//PERIOD FOR THE THIRD MA
class=class="str">"cmt">//SETTING BARS TO START PLOTTING
   PlotIndexSetInteger(class="num">0, PLOT_DRAW_BEGIN, period_ma200);
   PlotIndexSetInteger(class="num">1, PLOT_DRAW_BEGIN, period_ma100);
   PlotIndexSetInteger(class="num">2, PLOT_DRAW_BEGIN, period_ma50);
把指标编译交给小布盯盘
这些诊断与自定义指标的代码模板,小布盯盘的 AIGC 已内置,打开对应品种页即可看到示例并直接改写,你只管定义逻辑。

常见问题

核心算法一致,差别在缓冲区映射与绘制方式由你控制;手写版可能在大周期初始条数处理上需自行补齐,概率上更灵活但易漏边界。
可以,小布盯盘内置 AIGC 辅助,描述如「线形转烛形均线」便能产出可编译框架,你再微调颜色与周期参数即可。
倾向编译通过但图表空白,因缓冲区未绑定到绘制索引;MT5 终端日志可能只给轻量警告,需手动核对序号。
一般按当前均价值相对前一根的升降,或收盘价与均线位置关系给色,属于用户逻辑,外汇贵金属波动大时颜色切换会偏频繁。