如何利用 MQL5 创建自定义指标(Heiken Ashi)(基础篇)
◍ 在 MT5 里手搓一个 Heiken Ashi 指标
Heiken Ashi(平均K线)把相邻K线的开盘收盘做平滑,能滤掉部分噪音,让趋势段更连续。MT5 自带的 HA 是内置的,但用 MQL5 自己写一个自定义版本,你可以改颜色逻辑、加缓冲、或者接进自己的 EA。
自定义指标的核心是 OnCalculate:它每次来新报价或新柱都会被终端调用,你必须把算好的值写进 plot 缓冲区。下面这段最小实现,只算 HA 的四条价格,未含任何信号判断。
外汇与贵金属波动剧烈,HA 只是视图变换,不预测方向,实盘前请在策略测试器里跑历史数据验证缓冲写入是否正确。
class="macro">#class="kw">property indicator_chart_window class="macro">#class="kw">property indicator_buffers class="num">4 class="macro">#class="kw">property indicator_plots class="num">4 class="type">class="kw">double haOpen[], haHigh[], haLow[], haClose[]; class="type">int OnInit() { SetIndexBuffer(class="num">0, haOpen, INDICATOR_DATA); SetIndexBuffer(class="num">1, haHigh, INDICATOR_DATA); SetIndexBuffer(class="num">2, haLow, INDICATOR_DATA); SetIndexBuffer(class="num">3, haClose, INDICATOR_DATA); class="kw">return(INIT_SUCCEEDED); } 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="type">int start = (prev_calculated > class="num">0) ? prev_calculated - class="num">1 : class="num">0; for(class="type">int i = start; i < rates_total; i++) { haClose[i] = (open[i] + high[i] + low[i] + close[i]) / class="num">4.0; haOpen[i] = (i > class="num">0) ? (haOpen[i-class="num">1] + haClose[i-class="num">1]) / class="num">2.0 : (open[i] + close[i]) / class="num">2.0; haHigh[i] = MathMax(high[i], MathMax(haOpen[i], haClose[i])); haLow[i] = MathMin(low[i], MathMin(haOpen[i], haClose[i])); } class="kw">return(rates_total); }
「用 iCustom 绕开内置指标的死板限制」
读图工具人人都需要,但 MT5 内置指标改不动逻辑,也未必有契合你打法那一个。原文作者点出一条务实路径:借 iCustom 函数把自定义指标挂进图表,按自己的参数和偏好重画信号,而不是跟现成指标将就。 本篇系列以自定义 Heiken Ashi 为样例,后续会覆盖指标定义、裸 HA 指标、挂 HA 的 EA,以及 HA 叠 EMA 的系统。代码全部用 MT5 自带的 MQL5 在 MetaEditor 里写,没装好环境的可先翻前一篇「在 MetaEditor 中编写 MQL5 代码」。 外汇与贵金属杠杆高、滑点跳空频繁,下面所有示例仅作教学验证,实盘套用需自担回测与穿仓风险。iCustom 只是把外部指标接入 EA 的通道,信号强弱仍取决于你写的指标逻辑,不保证任何胜率。
从零搭一个 Heiken Ashi 自定义指标
MT5 自带指标覆盖不了所有分析逻辑,当你要用内置没有的数学或统计口径看盘时,只能自己写。自定义指标就是用户在 MQL5 里造的分析工具,能直接挂进 MetaTrader 5 图表辅助判断走势。 新建流程很固定:在 MetaEditor 的导航器里点开 Indicators 文件夹,点“新建”,程序类型选“自定义指标”,依次填名称与参数偏好,完成后编辑器就打开,可以写代码了。 以 Heiken Ashi 为例,它表面像普通蜡烛图,但每根蜡烛的四个价都重算过。开盘价取前一根开盘加前一根收盘的一半;收盘价取当期开高低收四价平均;最高价和最低价则分别在当期极值与开收之间取最大、最小。 这种算法等于对价格做了平滑,把部分市场噪音滤掉。实盘里把传统日式蜡烛放上半屏、Heiken Ashi 放下半屏对照,蓝红烛条直接标多空倾向,假信号概率会低一些。外汇和贵金属波动大、杠杆高,这类平滑仅降噪不保本,验证时先用模拟盘跑。
◍ 手搓一个子窗口 HA 指标
在 MT5 里写一个自定义 Heiken Ashi 指标,核心是把普通 K 线的 OHLC 重算成 haOpen、haHigh、haLow、haClose,再按方向染色。原文实现的版本放在主图下方的独立子窗口,看涨染蓝、看跌染红,缓冲区一共开了 5 个双精度数组,其中前 4 个存价格、第 5 个 haColor 存颜色索引。 #property 段先定骨架:indicator_separate_window 让它进副窗,indicator_buffers 5 对应五个数组,indicator_plots 1 表示只画一组图形,indicator_type1 用 DRAW_COLOR_CANDLES 才能按 haColor 切换蓝红。indicator_color1 写死 clrBlue, clrRed,indicator_width1 2 让烛条粗一点,indicator_label1 把四个数据列名一次性挂上。 OnInit 里用 SetIndexBuffer 把 0~3 号缓冲区绑成 INDICATOR_DATA、4 号绑成 INDICATOR_COLOR_INDEX;随后 IndicatorSetInteger 设小数位跟 _Digits 走,IndicatorSetString 把短名写成 Simple Heiken Ashi,PlotIndexSetDouble 把 PLOT_EMPTY_VALUE 设 0.0,最后 return INIT_SUCCEEDED。 OnCalculate 的启动位由 prev_calculated 决定:首次跑 prev_calculated==0 时 start=1,否则 start=prev_calculated-1,避免重复算历史。for 循环从 i=start 跑到 rates_total 且未被 IsStopped 中断,每根 bar 算完四个 ha 值写回数组,再判 haOpen[i]<haClose[i] 给 haColor[i] 赋蓝、否则赋红,函数尾返回 rates_total 供下次增量调用。 编译零报错后,指标会躺在导航器 Indicators 目录下,拖到图表弹出的通用窗口里“颜色”选项卡默认就是蓝涨红跌,可手动改。外汇与贵金属杠杆高,HA 只平滑视觉、不预测拐点,实盘前请在模拟盘验证染色逻辑与你的交易系统是否冲突。
class="macro">#class="kw">property indicator_separate_window class="macro">#class="kw">property indicator_buffers class="num">5 class="macro">#class="kw">property indicator_plots class="num">1 class="macro">#class="kw">property indicator_type1 DRAW_COLOR_CANDLES class="macro">#class="kw">property indicator_color1 clrBlue, clrRed class="macro">#class="kw">property indicator_width1 class="num">2 class="macro">#class="kw">property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close" class="type">class="kw">double haOpen[]; class="type">class="kw">double haHigh[]; class="type">class="kw">double haLow[]; class="type">class="kw">double haClose[]; class="type">class="kw">double haColor[]; class="type">int OnInit() SetIndexBuffer(class="num">0,haOpen,INDICATOR_DATA); SetIndexBuffer(class="num">1,haHigh,INDICATOR_DATA); SetIndexBuffer(class="num">2,haLow,INDICATOR_DATA); SetIndexBuffer(class="num">3,haClose,INDICATOR_DATA); SetIndexBuffer(class="num">4,haColor,INDICATOR_COLOR_INDEX); IndicatorSetInteger(INDICATOR_DIGITS,_Digits); IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi"); PlotIndexSetDouble(class="num">0,PLOT_EMPTY_VALUE,class="num">0.0); class="kw">return(INIT_SUCCEEDED); 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[],