MQL5 简介(第 12 部分):构建自定义指标的初学者指南·进阶篇
(2/3)· 不调用 iMA 也能画出均线,并把线变成会说话的烛形
◍ 彩色均线蜡烛的缓冲区账本
把移动平均画成蜡烛而不是线,第一道坎就是缓冲区数量。常规蜡烛需要开高低收 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,否则新线画不出来。外汇与贵金属波动剧烈,多均线叠加仅作趋势参照,杠杆风险高,信号失效可能很快。
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 历史验证缓冲绑定无误。
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,指标即完成初始化。 别把正态当圣经:线型只是辅助辨识,真要判方向还得看均线夹角和价格位置关系,外汇和贵金属杠杆高,视觉清爽不代表信号可靠。
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 根之后才开始有有效输出。外汇与贵金属杠杆高,均线仅是概率参考,实盘须自担风险。
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);