MQL5 初学者:EA 交易技术指标使用指南·综合运用
(3/3)· 从 iAMA 到 iVolumes 逐个拆解,EA 调用标准指标的坑与写法都在这里
接上篇,我们继续深挖 MQL5 标准指标函数的具体调用。很多新手在 OnInit 外随手建指标句柄,遇到无效句柄不校验就直接读缓冲区,回测里一切正常,实盘一跑就崩在空引用上。
- 在EA里接住自适应均线
- 在EA里直接抓AO柱值
- 用 iATR 拉出真实波幅缓冲
- 用 iBearsPower 句柄拉空方力道
- 用 iBands 拉出布林三轨缓冲区
- 在 EA 里挂上 BullsPower 的多头力道
- 用 iCCI 句柄把顺势通道拉进 EA
- 在EA里接住Chaikin资金流量
- 在EA里挂一条双指数均线
- 在 EA 里接住 DeMarker 的句柄与数据
- 用 iEnvelopes 拉出上下轨缓冲
- 在EA里挂上iForce力量指数
- 用 iFractals 抓顶底 fractals 的句柄写法
- 用 iFrAMA 拉一条自适应均线进 EA
- 用 iGator 缓冲区抓鳄鱼张口
- 在EA里直接抓取云图五线
- 用 iBWMFI 抓取量价背离信号
- 用 iMomentum 拉出动能线
- 用 iMFI 句柄抓取资金流量节奏
- 用 iMA 句柄把均线拉进 EA
- 用 iOsMA 抓动量背离的句柄写法
- 在EA里挂一个MACD并取双线缓冲
- 用 iOBV 句柄把量能累积搬进 EA
- 在EA里挂一个抛物线转向点
- 用 iRSI 句柄拉取序列数据
- 用 iRVI 句柄把相对活力指数拉进 EA
- 用 iStdDev 拉出波动率尾巴
- 用 iStochastic 句柄把随机指标搬进 EA
- 在EA里挂一条20期TEMA线
- 用 iTriX 句柄抓三重平滑动量
- 用 iWPR 拉取威廉指标缓冲
- 在EA里挂上iVIDyA变速率均线
- 用 iVolumes 抓 tick 成交量
- 记住这一条就够了
◍ 在EA里接住自适应均线
iAMA 是 MT5 自带的自适应移动平均,和普通 MA 不同,它会按价格波动效率动态调整平滑系数,震荡市里反应慢、趋势市里跟得紧。想在 EA 里用它,第一步是拿到指标句柄,而不是自己重写算法。 下面这段把句柄创建和每跳取数都列清楚了。初始化时调 iAMA(NULL,0,21,5,8,0,PRICE_CLOSE),参数依次是周期=当前图、时间帧=0(当前)、周期数=21、快速周期=5、慢速周期=8、应用价模式=0、价格源=收盘价;任一参数不对,句柄会返回负数。 OnTick 里用 CopyBufferAsSeries 把最近 100 根 BAR 的主缓冲拉进 AMA[] 数组,且按时间序列排(索引 0 是最新棒)。若拷贝失败直接 return,避免后面拿脏数据下单。外汇与贵金属杠杆高,iAMA 只描述已发生价格结构,信号滞后与假突破概率都真实存在,实盘前务必在策略测试器跑至少三年 tick 数据。 别把正态当圣经 句柄创建放 OnInit 只做一次,塞进 OnTick 每跳重建会拖死执行速度;很多人回测莫名卡顿就是栽在这。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double AMA[]; class=class="str">"cmt">// iAMA指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int AMA_handle; class=class="str">"cmt">// iAMA指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iAMA指标 AMA_handle=iAMA(NULL,class="num">0,class="num">21,class="num">5,class="num">8,class="num">0,PRICE_CLOSE); class=class="str">"cmt">//--- 如果对象创建出错则报告 if(AMA_handle<class="num">0) { Print("创建iAMA指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序退出 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iAMA指标缓冲区的当前值填充AMA[]数组 class=class="str">"cmt">//--- 设置AMA[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(AMA_handle,class="num">0,class="num">0,class="num">100,true,AMA)) class="kw">return; }
在EA里直接抓AO柱值
AO(Awesome Oscillator)是中线动能的裸眼尺:快周期中线(5)减慢周期中线(34)的差值。MT5 里用 iAO(NULL,0) 拿句柄,比自己重算 SMA 省事,也避开了重算带来的偏差。 下面这段把指标句柄化和取值的流程拆开看。先在 OnInit 里建句柄,失败就打印错误并退出;OnTick 里用 CopyBufferAsSeries 把最近 100 根 AO 柱按时间序塞进 AO[],任何一步出错直接 return,不污染后续逻辑。 #include <GetIndicatorBuffers.mqh> //---- 指标数组 double AO[]; // iAO指标对应的数组 //---- handles for indicators int AO_handle; // iAO指标的句柄 //+------------------------------------------------------------------+
| // | EA初始化函数 |
|---|
//+------------------------------------------------------------------+ int OnInit() { //--- 创建iAO指标 AO_handle=iAO(NULL,0); //--- 如果对象创建出错则报告 if(AO_handle<0) { Print("iAO指标创建失败: 运行时错误 =",GetLastError()); //--- 强制程序退出 return(-1); } return(0); } //+------------------------------------------------------------------+
| // | EA订单函数 |
|---|
//+------------------------------------------------------------------+ void OnTick() { //--- 使用iAO指标当前值填充AO[]数组 //--- 设置AO[]数组索引方式为时间序列 //--- 如果出错则返回 if(!CopyBufferAsSeries(AO_handle,0,0,100,true,AO)) return; } 实盘里把 AO[0] 与 AO[1] 的符号变化当零轴穿越的快判据,外汇与贵金属波动大、滑点凶,零轴信号只是概率倾向,真下单前建议在 MT5 策略测试器跑至少 3 个月 tick 数据看穿越后的回撤分布。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double AO[]; class=class="str">"cmt">// iAO指标对应的数组 class=class="str">"cmt">//---- handles for indicators class="type">int AO_handle; class=class="str">"cmt">// iAO指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iAO指标 AO_handle=iAO(NULL,class="num">0); class=class="str">"cmt">//--- 如果对象创建出错则报告 if(AO_handle<class="num">0) { Print("iAO指标创建失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序退出 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iAO指标当前值填充AO[]数组 class=class="str">"cmt">//--- 设置AO[]数组索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(AO_handle,class="num">0,class="num">0,class="num">100,true,AO)) class="kw">return; }
「用 iATR 拉出真实波幅缓冲」
在 MT5 里做价格行为分析,平均真实波幅(ATR)是过滤噪音的第一道闸。iATR 函数直接返回指标句柄,比手动算 TR 再平滑省事得多,但句柄创建失败就必须终止 EA,否则后续全是空数组。 上面这段代码演示了最小可用骨架:OnInit 里用 iATR(NULL,0,14) 在当前品种、当前周期取 14 根 K 线的 ATR;若返回值小于 0,打印 GetLastError 并 return(-1)。14 是默认周期,实战中贵金属可试 20~30 以适配跳空。 OnTick 中调用 CopyBufferAsSeries 把最近 100 根 ATR 值按时间序塞进 ATR[],失败就直接 return。注意 AsSeries 设为 true 后,ATR[0] 是最新值、ATR[99] 是 100 根前的值,写突破逻辑时别反了。 外汇与贵金属杠杆高、滑点随机,ATR 只描述波动幅度,不预示方向;用它设止损间距时,需结合当时流动性判断,切勿当作胜率保证。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double ATR[]; class=class="str">"cmt">// iATR指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int ATR_handle; class=class="str">"cmt">// iATR指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iATR指标 ATR_handle=iATR(NULL,class="num">0,class="num">14); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(ATR_handle<class="num">0) { Print("iATR指标创建失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iATR指标当前值填充ATR[]数组 class=class="str">"cmt">//--- 设置ATR[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(ATR_handle,class="num">0,class="num">0,class="num">100,true,ATR)) class="kw">return; }
◍ 用 iBearsPower 句柄拉空方力道
空方力道(Bears Power)以(现价-13周期EMA)刻画卖压,MT5 内置 iBearsPower 用 14 作为参数时,实际 EMA 周期为 13,第 0 根即当前柱。EA 里先拿句柄再拷缓冲区,比每 tick 重算指标更省资源。 下面这段代码演示了句柄创建与序列拷贝的最小可用骨架。初始化时建句柄失败直接返回 -1 终止,避免后续空指针;OnTick 中用 CopyBufferAsSeries 把最近 100 根按时间序填入数组 BearsPower[],索引 0 为最新柱。 外汇与贵金属杠杆高,指标负值放大只说明卖压倾向占优,不代表价格必然下行,须结合仓位控制。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double BearsPower[]; class=class="str">"cmt">// iBearsPower指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int BearsPower_handle; class=class="str">"cmt">// iBearsPower指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iBearsPower指标 BearsPower_handle=iBearsPower(NULL,class="num">0,class="num">14); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(BearsPower_handle<class="num">0) { Print("创建iBearsPower指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iBearsPower指标的当前值填充BearsPower[]数组。 class=class="str">"cmt">//--- 设置BearsPower[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(BearsPower_handle,class="num">0,class="num">0,class="num">100,true,BearsPower)) class="kw">return; }
用 iBands 拉出布林三轨缓冲区
布林带在 MT5 里靠 iBands 拿句柄,再用自定义缓冲接口把三条线(中轨、上轨、下轨)灌进数组。上面这段把周期设成 144、偏差 2、收盘价计算,属于慢速布林,适合看日线级别的趋势带宽变化。 初始化时若句柄返回负值,说明指标创建失败,直接打印错误码并终止 EA,避免后续空指针读取。OnTick 里调 GetBandsBuffers 从 0 号柱往后取 100 根 K 线的三轨数据,时间序列索引让 Base[0] 永远是最新一根收盘价对应的中轨。 外汇和贵金属波动跳变快,慢速布林在重大数据行情中可能滞后,轨宽突然放大只代表波动率上升、不预示方向。开 MT5 把 144 改成 20 对比一下,能直观看到轨线对价格的包裹密度差异。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double Base[]; class=class="str">"cmt">// iBands中BASE_LINE对应的数组 class="type">class="kw">double Upper[]; class=class="str">"cmt">// iBands中UPPER_BAND对应的数组 class="type">class="kw">double Lower[]; class=class="str">"cmt">// iBands中LOWER_BAND对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int Bands_handle; class=class="str">"cmt">// iBands指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iBands指标 Bands_handle=iBands(NULL,class="num">0,class="num">144,class="num">0,class="num">2,PRICE_CLOSE); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(Bands_handle<class="num">0) { Print("创建iBands指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 设置数组索引方式为时间序列 class=class="str">"cmt">//--- 使用所有指标缓冲区的当前值填充数组 class=class="str">"cmt">//--- 如果出错则返回 if(!GetBandsBuffers(Bands_handle,class="num">0,class="num">100,Base,Upper,Lower,true)) class="kw">return; }
「在 EA 里挂上 BullsPower 的多头力道」
BullsPower 衡量的是当前最高价相对指定周期 EMA 的偏离,正值越大代表买盘把价格推离均线的力道越强。做贵金属或外汇这种高波动品种时,它适合当辅助过滤器,但单独信号假突破很多,务必配合其他结构判断。 下面这段 MQL5 把 BullsPower 接进 EA:先声明数组与句柄,初始化时用 iBullsPower(NULL,0,14) 建一个 14 周期句柄,建失败就打印错误并终止;OnTick 里用 CopyBufferAsSeries 把最近 100 根 K 线的指标值按时间序塞进数组。 #include <GetIndicatorBuffers.mqh> //---- 指标数组 double BullsPower[]; // iBullsPower指标对应的数组 //---- 指标句柄 int BullsPower_handle; // iBullsPower指标的句柄 //+------------------------------------------------------------------+
| // | EA初始化函数 |
|---|
//+------------------------------------------------------------------+ int OnInit() { //--- 创建iBullsPower指标 BullsPower_handle=iBullsPower(NULL,0,14); //--- 如果创建对象出错则报告 if(BullsPower_handle<0) { Print("创建iBullsPower 失败: 运行时错误 =",GetLastError()); //--- 强制程序终止 return(-1); } return(0); } //+------------------------------------------------------------------+
| // | EA订单函数 |
|---|
//+------------------------------------------------------------------+ void OnTick() { //--- 使用iBullsPower指标的当前值填充BullsPower[]数组. //--- 设置BullsPower[]数组的索引方式为时间序列 //--- 如果出错则返回 if(!CopyBufferAsSeries(BullsPower_handle,0,0,100,true,BullsPower)) return; } 逐行看:第 1 行引头文件拿 CopyBufferAsSeries 帮手;double BullsPower[] 存数值,int 句柄是调系统的凭证。OnInit 中 iBullsPower 第三参 14 就是周期,改它等于改灵敏度——周期越小噪声越密。OnTick 里 CopyBufferAsSeries 第 4 参 100 决定取多少根,true 表示序列索引(0 是最新 K)。 开 MT5 把周期从 14 改成 5 和 30 各跑一遍欧元美元 15 分钟图,你会看到多头力道线的毛刺密度明显分化,这直接影响你后续阈值该怎么切。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double BullsPower[]; class=class="str">"cmt">// iBullsPower指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int BullsPower_handle; class=class="str">"cmt">// iBullsPower指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iBullsPower指标 BullsPower_handle=iBullsPower(NULL,class="num">0,class="num">14); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(BullsPower_handle<class="num">0) { Print("创建iBullsPower 失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iBullsPower指标的当前值填充BullsPower[]数组. class=class="str">"cmt">//--- 设置BullsPower[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(BullsPower_handle,class="num">0,class="num">0,class="num">100,true,BullsPower)) class="kw">return; }
◍ 用 iCCI 句柄把顺势通道拉进 EA
CCI 在 MT5 里不是直接读数组,而是先拿句柄再拷缓冲。上面这段把 14 周期、收盘价计算的 iCCI 挂到当前图表,句柄建失败就打印错误并终止初始化,避免后面空跑。 OnTick 里用 CopyBufferAsSeries 把最近 100 根 K 线的 CCI 值按时间序填进 CCI[],参数 true 表示序列索引(0 是最新柱)。外汇和贵金属波动大,CCI 穿越 ±100 只代表超买超卖概率偏高,不代表反转必现,实盘前请在策略测试器用历史数据验证拷贝逻辑。 别把正态当圣经:CCI 默认 14 周期在黄金 5 分钟图上常出现假突破,把周期调到 20 或只取 50 根缓冲,噪声可能明显下降。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double CCI[]; class=class="str">"cmt">// iCCI指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int CCI_handle; class=class="str">"cmt">// iCCI指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iCCI指标 CCI_handle=iCCI(NULL,class="num">0,class="num">14,PRICE_CLOSE); class=class="str">"cmt">//--- 如果对象创建出错则报告 if(CCI_handle<class="num">0) { Print("创建iCCI指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iCCI指标的当前值填充CCI[]数组 class=class="str">"cmt">//--- 设置CCI[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(CCI_handle,class="num">0,class="num">0,class="num">100,true,CCI)) class="kw">return; }
在EA里接住Chaikin资金流量
Chaikin 指标把累计成交量与收盘价在区间中的位置结合,用来观察资金是否在悄悄流入或撤出。MT5 内置的 iChaikin 可直接在 EA 中调用,不必自己重写累积逻辑。 下面这段初始化把指标句柄建出来:周期用当前图表(NULL,0),快慢线参数 8 和 14,平滑选 MODE_EMA,成交量源用 VOLUME_TICK。若句柄小于 0 就打印运行时错误并终止初始化,避免后面空句柄去读数据。 OnTick 里用 CopyBufferAsSeries 把最近 100 根 Bar 的指标值按时间序列塞进 Chaikin[] 数组。注意第三个参数 0 是起始位置、100 是拷贝数量、true 代表序列索引(0 是最新 Bar)。这一步若失败直接 return,防止用脏数组做判断。 实盘接这指标前,先在策略测试器跑一遍 EURUSD 的 M15,看 Chaikin 穿越零轴与后续回撤的吻合度;外汇和贵金属杠杆高,信号只作概率参考,别当成方向保证。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double Chaikin[]; class=class="str">"cmt">// iChaikin指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int Chaikin_handle; class=class="str">"cmt">// iChaikin指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iChaikin指标 Chaikin_handle=iChaikin(NULL,class="num">0,class="num">8,class="num">14,MODE_EMA,VOLUME_TICK); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(Chaikin_handle<class="num">0) { Print("创建iChaikin指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iChaikin指标的当前值填充 Chaikin[]数组 class=class="str">"cmt">//--- 设置Chaikin[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(Chaikin_handle,class="num">0,class="num">0,class="num">100,true,Chaikin)) class="kw">return; }
「在EA里挂一条双指数均线」
双指数移动平均(DEMA)相比普通EMA减少了滞后,对价格反转的反应更快,在贵金属与外汇的短周期行情里可能更早发现拐点,但高频噪声也可能被放大,交易前需在MT5里实跑验证。 下面这段代码演示了如何在EA初始化时创建周期为8、应用于收盘价、对当前图表自动适配的DEMA句柄,并在每笔报价里把最近100根的数值按时间序列拷进数组。周期参数8是示例值,你可以改成14或21观察平滑度的变化。 别把句柄创建当保险 创建指标句柄如果返回负值,说明调用失败,此时直接终止初始化比带着空句柄跑Tick更稳妥,否则后续CopyBuffer会静默取不到数。 调用CopyBufferAsSeries时第四个参数100代表要取100根,若你只做当根交叉判断,改成2就够,能少占点缓冲也降低逻辑出错概率。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double DEMA[]; class=class="str">"cmt">// iDEMA指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int DEMA_handle; class=class="str">"cmt">// iDEMA指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iDEMA指标 DEMA_handle=iDEMA(NULL,class="num">0,class="num">8,class="num">0,PRICE_CLOSE); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(DEMA_handle<class="num">0) { Print("创建iDEMA指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iDEMA指标的当前值填充 DEMA[]数组 class=class="str">"cmt">//--- 设置DEMA[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(DEMA_handle,class="num">0,class="num">0,class="num">100,true,DEMA)) class="kw">return; }
◍ 在 EA 里接住 DeMarker 的句柄与数据
DeMarker 指标衡量一段时间内最高价与最低价的相对位置,输出值落在 0~1 区间。常规用法里,大于 0.7 倾向超买、小于 0.3 倾向超卖,但这是概率描述,不是确定性信号。外汇与贵金属波动剧烈,单看该阈值易频繁假突破。 下面这段 MT5 代码演示了如何在 EA 中创建周期为 21 的 DeMarker 指标并取数。先包含通用缓冲管理头文件,再声明数组与句柄,初始化时建句柄、出错即停,报价事件里拉 100 根时间序列数据。 #include <GetIndicatorBuffers.mqh> //---- 指标数组 double DeMarker[]; // iDeMarker指标对应的数组 //---- 指标句柄 int DeMarker_handle; // iDeMarker指标的句柄 //+------------------------------------------------------------------+
| // | EA初始化函数 |
|---|
//+------------------------------------------------------------------+ int OnInit() { //--- 创建iDeMarker指标 DeMarker_handle=iDeMarker(NULL,0,21); //--- 如果创建对象错误则报告 if(DeMarker_handle<0) { Print("创建iDeMarker指标失败: 运行时错误 =",GetLastError()); //--- 强制程序终止 return(-1); } return(0); } //+------------------------------------------------------------------+
| // | EA订单函数 |
|---|
//+------------------------------------------------------------------+ void OnTick() { //--- 使用iDeMarker指标的当前值填充DeMarker[]数组. //--- 设置DeMarker数组的索引方式为时间序列 //--- 如果出错则返回 if(!CopyBufferAsSeries(DeMarker_handle,0,0,100,true,DeMarker)) return; } 逐行看:iDeMarker(NULL,0,21) 中 NULL 表示当前品种、0 为当前图表周期、21 是默认计算柱数;CopyBufferAsSeries 最后一个 true 代表按时间倒序填充,DeMarker[0] 即为最新值。把 100 改成 500,就能在 MT5 里验证更长窗口下阈值分布的漂移。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double DeMarker[]; class=class="str">"cmt">// iDeMarker指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int DeMarker_handle; class=class="str">"cmt">// iDeMarker指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iDeMarker指标 DeMarker_handle=iDeMarker(NULL,class="num">0,class="num">21); class=class="str">"cmt">//--- 如果创建对象错误则报告 if(DeMarker_handle<class="num">0) { Print("创建iDeMarker指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iDeMarker指标的当前值填充DeMarker[]数组. class=class="str">"cmt">//--- 设置DeMarker数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(DeMarker_handle,class="num">0,class="num">0,class="num">100,true,DeMarker)) class="kw">return; }
用 iEnvelopes 拉出上下轨缓冲
包络带(Envelopes)在 MT5 里以中轨加减百分比的方式画出上下两条线,常用作价格触边反转或突破的参考。上面这段 EA 骨架演示了如何在 OnInit 里创建句柄、在 OnTick 里把缓冲拉进数组。 创建时传入的参数依次是:图表符号 NULL(当前品种)、周期 0(当前周期)、均线周期 14、偏移 0、平滑方式 MODE_SMA、计算价格 PRICE_CLOSE、偏离度 0.1(即 10%)。偏离度是百分比,不是点数,调小到 0.05 会更贴近中轨。 GetEnvelopesBuffers 是自定义 include 里的函数,这里一次取 100 根 K 线的 Upper 和 Lower 数组,且按时间序列排列(最新柱在索引 0)。若句柄创建失败会直接 Print 错误码并终止 OnInit,避免后面空跑。 开 MT5 把这段贴进 EA,把偏离度从 0.1 改成 0.05 再切到 XAUUSD 的 M15,观察上下轨收口频率——外汇与贵金属杠杆高,触边不代表反转,仅作为概率参考。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double Upper[]; class=class="str">"cmt">// iEnvelopes指标中UPPER_LINE对应的数组 class="type">class="kw">double Lower[]; class=class="str">"cmt">// iEnvelopes指标中LOWER_LINE对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int Envelopes_handle; class=class="str">"cmt">// iEnvelopes指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iEnvelopes指标 Envelopes_handle=iEnvelopes(NULL,class="num">0,class="num">14,class="num">0,MODE_SMA,PRICE_CLOSE,class="num">0.1); class=class="str">"cmt">//--- 如果对象创建出错则报告 if(Envelopes_handle<class="num">0) { Print("创建iEnvelopes指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 设置数组索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 class=class="str">"cmt">//--- 使用iEnvelopes指标的当前值填充数组 if(!GetEnvelopesBuffers(Envelopes_handle,class="num">0,class="num">100,Upper,Lower,true)) class="kw">return; }
「在EA里挂上iForce力量指数」
把 iForce 接进 MT5 的 EA,核心是先拿句柄再按时间序列取数。下面这段可直接拷进你的 .mq5 里跑,周期参数用的是 21 期 SMA、按 tick 成交量加权,属于比较常见的力量指数配置。 代码里 OnInit 负责建指标:iForce(NULL,0,21,MODE_SMA,VOLUME_TICK) 中 21 是周期,MODE_SMA 指定均线平滑方式,VOLUME_TICK 表示用 tick 量而非真实量。句柄小于 0 就打印错误并终止,避免后续空指针乱跑。 OnTick 里用 CopyBufferAsSeries 把最近 100 根的力量值灌进 Force[],true 代表序列时间排序(0 号是最新一根)。若复制失败直接 return,不碰交易逻辑。外汇与贵金属波动剧烈,iForce 仅反映买卖推力强弱,信号可能反转,实盘前务必在策略测试器用历史数据验证。 别把句柄当永生的 指标句柄在品种或周期切换后会失效,若你的 EA 支持多周期,需在对应周期重调 iForce 并判空,否则 CopyBufferAsSeries 会静默返回 false 吃掉行情。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double Force[]; class=class="str">"cmt">// iForce指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int Force_handle; class=class="str">"cmt">// iForce指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iForce指标 Force_handle=iForce(NULL,class="num">0,class="num">21,MODE_SMA,VOLUME_TICK); class=class="str">"cmt">//--- 如果对象创建出错则报告 if(Force_handle<class="num">0) { Print("创建iForce指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iForce指标的当前值填充Force[]数组 class=class="str">"cmt">//--- 设置Force[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(Force_handle,class="num">0,class="num">0,class="num">100,true,Force)) class="kw">return; }
◍ 用 iFractals 抓顶底 fractals 的句柄写法
MT5 自带的 iFractals 指标输出两条线:UPPER_LINE 标记向上分形(中间 K 线最高,左右各两根更低),LOWER_LINE 标记向下分形(中间最低,左右各两根更高)。想在 EA 里直接读这些值,第一步是拿指标句柄,而不是自己重写分形判定逻辑。 下面这段初始化只做一件事:在当前图表、当前周期创建 iFractals 句柄,失败就打印错误并终止。注意第二参数填 0 代表当前图表周期,不需要手动指定 PERIOD 常量。 [CODE] #include <GetIndicatorBuffers.mqh> //---- 指标数组 double Upper[]; // iFractals中UPPER_LINE对应的数组 double Lower[]; // iFractals中LOWER_LINE对应的数组 //---- 指标句柄 int Fractals_handle; // iFractals指标的句柄 //+------------------------------------------------------------------+
| // | EA初始化函数 |
|---|
//+------------------------------------------------------------------+ int OnInit() { //--- 创建iFractals指标 Fractals_handle=iFractals(NULL,0); //--- 如果对象创建出错则报告 if(Fractals_handle<0) { Print("创建iFractals指标失败: 运行时错误 =",GetLastError()); //--- 强制程序终止 return(-1); } return(0); } //+------------------------------------------------------------------+
| // | EA订单函数 |
|---|
//+------------------------------------------------------------------+
void OnTick()
{
//--- 设置数组索引方式为时间序列
//--- 使用当前指标缓冲区的值填充数组
//--- 如果出错则返回
if(!GetFractalsBuffers(Fractals_handle,0,100,Upper,Lower,true)) return;
}
[/CODE]
逐行拆一下关键处:#include <GetIndicatorBuffers.mqh> 是自定义头文件,提供 GetFractalsBuffers 帮我们把句柄里的上下分形数组一次性拷出来;Fractals_handle=iFractals(NULL,0) 中 NULL 指当前品种,0 指当前周期。GetFractalsBuffers(Fractals_handle,0,100,Upper,Lower,true) 的 0 是起始位置、100 是取 100 根 K 线的缓冲、true 表示按时间序填充(索引 0 是最新 bar)。
开 MT5 把这段贴进 EA 模板,编译后跑在 XAUUSD 的 M5 上,Upper 数组里非 0 的位置就是近期出现过向上分形的 bar。外汇与贵金属杠杆高、分形假突破频繁,信号仅作结构参考,实际触发概率随波动率变化。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double Upper[]; class=class="str">"cmt">// iFractals中UPPER_LINE对应的数组 class="type">class="kw">double Lower[]; class=class="str">"cmt">// iFractals中LOWER_LINE对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int Fractals_handle; class=class="str">"cmt">// iFractals指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iFractals指标 Fractals_handle=iFractals(NULL,class="num">0); class=class="str">"cmt">//--- 如果对象创建出错则报告 if(Fractals_handle<class="num">0) { Print("创建iFractals指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 设置数组索引方式为时间序列 class=class="str">"cmt">//--- 使用当前指标缓冲区的值填充数组 class=class="str">"cmt">//--- 如果出错则返回 if(!GetFractalsBuffers(Fractals_handle,class="num">0,class="num">100,Upper,Lower,true)) class="kw">return; }
用 iFrAMA 拉一条自适应均线进 EA
FrAMA 全称 Fractal Adaptive Moving Average,核心是按价格分形维度动态调平滑系数,震荡市里慢、趋势市里快。上面这段 MT5 代码演示了如何在 EA 里直接挂一条周期 21 的 iFrAMA 并取数,省掉自己重写分形算法的麻烦。 初始化时调用 iFrAMA(NULL,0,21,0,MODE_SMA),第五个参数 0 代表主缓冲区(平滑后数值),MODE_SMA 在这里仅作占位传入并不影响 FrAMA 自身计算逻辑;若句柄返回负值说明指标创建失败,直接打印错误码并终止 OnInit。 OnTick 里用 CopyBufferAsSeries 把最新 100 根 K 线的 FrAMA 值按时间序列塞进 FrAMA[] 数组,索引 0 即当前柱。实际验证时把 21 改成 13 或 34,对比 EURUSD 在 1 小时图上的跟线松紧,能直观看出参数对噪声过滤的敏感差异。外汇与贵金属杠杆高,FrAMA 只描述已发生结构,转向信号滞后概率始终存在,别当进场圣杯。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double FrAMA[]; class=class="str">"cmt">// iFrAMA对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int FrAMA_handle; class=class="str">"cmt">// iFrAMA指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iFrAMA指标 FrAMA_handle=iFrAMA(NULL,class="num">0,class="num">21,class="num">0,MODE_SMA); class=class="str">"cmt">//--- 如果对象创建出错则报告 if(FrAMA_handle<class="num">0) { Print("创建iFrAMA指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iFrAMA指标的当前值填充FrAMA[]数组 class=class="str">"cmt">//--- 设置FrAMA[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(FrAMA_handle,class="num">0,class="num">0,class="num">100,true,FrAMA)) class="kw">return; }
「用 iGator 缓冲区抓鳄鱼张口」
Gator 指标本质是鳄鱼指标派生出的动能辅助:上唇与下唇乖离的上半部分写进 Upper[],下半部分写进 Lower[],两者拉开代表多空失衡加剧。下面这段 EA 骨架把句柄创建和缓冲区抓取拆得很直白,复制进 MT5 就能编译跑。 初始化时 iGator(NULL,0,13,8,8,5,5,3,MODE_EMA,PRICE_MEDIAN) 用的就是默认 13/8/5 三均线周期,句柄失败直接返回 -1 终止,避免后续空指针。 OnTick 里靠 GetGatorBuffers 一次性取最近 100 根 K 的上下缓冲;返回 false 就跳过本 tick。实盘中外汇与贵金属波动受杠杆和跳空影响大,Gator 张口只是概率上的动能信号,不能单独作为入场依据,建议叠加价格行为结构过滤。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double Upper[]; class=class="str">"cmt">// iGator中UPPER_LINE对应的数组 class="type">class="kw">double Lower[]; class=class="str">"cmt">// iGator中LOWER_LINE对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int Gator_handle; class=class="str">"cmt">// iGator指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iGator指标 Gator_handle=iGator(NULL,class="num">0,class="num">13,class="num">8,class="num">8,class="num">5,class="num">5,class="num">3,MODE_EMA,PRICE_MEDIAN); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(Gator_handle<class="num">0) { Print("创建iGator指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 设置数组索引方式为时间序列 class=class="str">"cmt">//--- 使用指标缓冲区的当前值填充数组 class=class="str">"cmt">//--- 如果出错则返回 if(!GetGatorBuffers(Gator_handle,class="num">0,class="num">100,Upper,Lower,true)) class="kw">return; }
◍ 在EA里直接抓取云图五线
想让程序自动读 Ichimoku,不必手算转换线、基准线,直接拿指标句柄取缓冲区最省事。下面这段把经典参数 9/26/52 的云图挂到当前品种主周期上,失败就打印错误并终止初始化。 调用 GetIchimokuBuffers 一次拉 100 根 K 线的五条线:Tenkansen、Kijunsen、SenkouspanA、SenkouspanB、Chinkouspan,数组按时间序列排,下标 0 是最新柱。实盘里若句柄无效或缓冲不足,OnTick 会直接 return,避免脏数据进场——外汇和贵金属波动大,这种防护能少踩很多坑。 验证方法很简单:把代码塞进 MT5 的 EA 模板,在 EURUSD 的 M15 上跑,用 Print(Tenkansen[0]) 看最新转换线,和图表上鼠标悬停的数值对一下,差一个点都说明缓冲没对齐。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double Tenkansen[]; class=class="str">"cmt">// iIchimoku中TENKANSEN_LINE对应的数组 class="type">class="kw">double Kijunsen[]; class=class="str">"cmt">// iIchimoku中KIJUNSEN_LINE对应的数组 class="type">class="kw">double SenkouspanA[]; class=class="str">"cmt">// iIchimoku中SENKOUSPANA_LINE对应的数组 class="type">class="kw">double SenkouspanB[]; class=class="str">"cmt">// iIchimoku中SENKOUSPANB_LINE对应的数组 class="type">class="kw">double Chinkouspan[]; class=class="str">"cmt">// iIchimoku中CHINKOUSPAN_LINE对应的数组 class=class="str">"cmt">//---- 指标的句柄 class="type">int Ichimoku_handle; class=class="str">"cmt">// iIchimoku指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iIchimoku指标 Ichimoku_handle=iIchimoku(NULL,class="num">0,class="num">9,class="num">26,class="num">52); class=class="str">"cmt">//--- 如果对象创建出错则报告 if(Ichimoku_handle<class="num">0) { Print("创建iIchimoku指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 设置数组索引方式为时间序列 class=class="str">"cmt">//--- 使用指标缓冲区的当前值填充数组 class=class="str">"cmt">//--- 如果出错则返回 if(!GetIchimokuBuffers(Ichimoku_handle,class="num">0,class="num">100, Tenkansen, Kijunsen, SenkouspanA, SenkouspanB, Chinkouspan, true)) class="kw">return; }
用 iBWMFI 抓取量价背离信号
iBWMFI 是 MT5 内置的 Williams 市场买卖力道指标,把收盘价相对区间的位置乘以成交量,用来衡量当前推动是买盘还是卖盘主导。外汇和贵金属杠杆高、滑点随机,用它判断背离只是概率倾向,不是方向保证。 下面这段 EA 骨架演示了怎么在 OnInit 里建句柄、在 OnTick 里把最近 100 根柱子的值拉进数组。复制进 MT5 的 EA 编辑器能直接编译,改 VOLUME_TICK 为 VOLUME_REAL 可切到真实成交量(部分品种券商不提供)。 句柄创建失败会打印运行时错误并终止初始化,这是实盘里必须拦的第一道坑——很多新手 EA 静默失败,图表面板上看不出指标根本没加载。 让小布替你跑这套 把 BWMFI[] 数组和价格走势叠加看:当价格新高但 BWMFI 峰值走低,倾向出现多头动能衰减;反之倾向空头衰竭。开 MT5 验证时建议先只打印数组前 10 值,确认序列索引没反。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double BWMFI[]; class=class="str">"cmt">// iBWMFI指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int BWMFI_handle; class=class="str">"cmt">// iBWMFI指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iBWMFI指标 BWMFI_handle=iBWMFI(NULL,class="num">0,VOLUME_TICK); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(BWMFI_handle<class="num">0) { Print("创建iBWMFI指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iBWMFI指标的当前值填充BWMFI[]数组 class=class="str">"cmt">//--- 设置BWMFI[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(BWMFI_handle,class="num">0,class="num">0,class="num">100,true,BWMFI)) class="kw">return; }
「用 iMomentum 拉出动能线」
MT5 里 iMomentum 走的是价格比率逻辑:当前收盘价除以 N 根 K 线前的收盘价再乘 100,基准线就是 100。上面这段把 14 周期、close 价的动量直接挂成句柄,EA 初始化时建一次,之后每跳去拉缓冲。 初始化里 Momentum_handle=iMomentum(NULL,0,14,PRICE_CLOSE) 用的是当前图表、当前周期,句柄小于 0 就打印错误并终止,避免后面空指针乱跑。OnTick 中用 CopyBufferAsSeries 按时间序填数组,一次取 100 根,足够做短中期动能比较。 实盘里动量跌破 100 说明近期收盘弱于两周前,贵金属和外汇杠杆高,这种走弱只是概率倾向,不代表反转。开 MT5 把这段贴进 EA,把 14 改成 5 或 34,对比 EURUSD 与 XAUUSD 的缓冲曲线,能直接看出参数对噪声的敏感度。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double Momentum[]; class=class="str">"cmt">// iMomentum指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int Momentum_handle; class=class="str">"cmt">// iMomentum指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iMomentum指标 Momentum_handle=iMomentum(NULL,class="num">0,class="num">14,PRICE_CLOSE); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(Momentum_handle<class="num">0) { Print("创建iMomentum指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iMomentum指标的当前值填充Momentum数组 class=class="str">"cmt">//--- 设置Momentum[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(Momentum_handle,class="num">0,class="num">0,class="num">100,true,Momentum)) class="kw">return; }
◍ 用 iMFI 句柄抓取资金流量节奏
MT5 里的 iMFI 是资金流量指标,把成交量按价格涨跌加权后归一化到 0~100,用来读盘口资金是流入还是抽离。上面这段直接在 EA 里挂了一个 14 周期、基于逐笔成交量的 iMFI,句柄创建失败就打印错误并终止,避免后面空跑。
初始化时 MFI_handle=iMFI(NULL,0,14,VOLUME_TICK) 中,NULL 表示抓当前图表品种,0 是现价周期,14 是默认回看窗口,VOLUME_TICK 说明用 tick 量而非分钟量——外汇和贵金属盘口跳变快,tick 量对短期资金异动更敏感,但滑点和报价断层会让读数抖动,属高风险品种常有的噪声。
OnTick 里只用 CopyBufferAsSeries 把最近 100 根 K 的 MFI 值按时间序塞进数组,索引 0 就是最新值。你可以直接把这段拷进 MT5 的 EA 模板,把 14 改成 21 对比一下伦敦盘与美盘开盘的资金流量拐头速度,验证哪个窗口更贴合你做的品种。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double MFI[]; class=class="str">"cmt">// iMFI指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int MFI_handle; class=class="str">"cmt">// iMFI指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iMFI指标 MFI_handle=iMFI(NULL,class="num">0,class="num">14,VOLUME_TICK); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(MFI_handle<class="num">0) { Print("创建iMFI指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iMFI指标的当前值填充MFI[]数组 class=class="str">"cmt">//--- 设置MFI[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(MFI_handle,class="num">0,class="num">0,class="num">100,true,MFI)) class="kw">return; }
用 iMA 句柄把均线拉进 EA
在 MT5 里调用移动平均,第一步不是算公式,而是先向终端申请一个指标句柄。下面这段把 21 周期指数均线(收盘价)挂到当前图表,句柄拿不到就直接终止初始化,避免后续空跑。
初始化里 iMA(NULL,0,21,0,MODE_EMA,PRICE_CLOSE) 的 21 是周期参数,你可以改成 10 或 55 观察不同平滑度;外汇与贵金属波动大,周期过短容易在震荡里频繁伪信号,属高风险特征。
OnTick 中用 CopyBufferAsSeries 把句柄对应的缓冲区按时间序列拷进 MA[],取 100 根。注意 true 代表序列索引(0 是最新 K 线),写反会导致你引用的 MA[1] 其实是历史老值。
别把正态当圣经:句柄创建失败多半是品种无数据或参数越界,真机调试时看专家日志的 GetLastError 比猜更快。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double MA[]; class=class="str">"cmt">// iMA指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int MA_handle; class=class="str">"cmt">// iMA指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iMA指标 MA_handle=iMA(NULL,class="num">0,class="num">21,class="num">0,MODE_EMA,PRICE_CLOSE); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(MA_handle<class="num">0) { Print("创建iMA指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iMA指标的当前值填充MA[]数组 class=class="str">"cmt">//--- 设置MA[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(MA_handle,class="num">0,class="num">0,class="num">100,true,MA)) class="kw">return; }
「用 iOsMA 抓动量背离的句柄写法」
MT5 里 iOsMA 对应的是移动平均振荡器(OsMA),本质是 MACD 主线减信号线的差。上面这段把指标句柄和数组分开声明,初始化时只用一行就挂上 8/21/14 的周期组合,比在 OnTick 里反复调用要干净。 注意 OnInit 中 OsMA_handle 若小于 0 会直接打印运行时错误并 return(-1),这意味着指标创建失败 EA 根本不会跑,省得后面用空句柄去 CopyBuffer 踩坑。 OnTick 里用 CopyBufferAsSeries 把最新 100 根柱的 OsMA 值按时间序填进数组,第二参 0 代表取主线差值缓冲。你开 MT5 把这段贴进 EA,改 NULL 为具体品种,就能在 OsMA[0] 读到当前柱动量,黄金 15 分钟图上该值由正转负往往倾向短期回落,但外汇和贵金属杠杆高,信号失效也常见,别裸仓跟。 句柄只建一次、数组每跳刷新,这是 MT5 指标调用的标准省资源套路,比每 Tick 重算指标快一个量级。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double OsMA[]; class=class="str">"cmt">// iOsMA指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int OsMA_handle; class=class="str">"cmt">// iOsMA指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iOsMA指标 OsMA_handle=iOsMA(NULL,class="num">0,class="num">8,class="num">21,class="num">14,PRICE_MEDIAN); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(OsMA_handle<class="num">0) { Print("创建iOsMA指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iOsMA指标的当前值填充OsMA[]数组 class=class="str">"cmt">//--- 设置OsMA[] 数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(OsMA_handle,class="num">0,class="num">0,class="num">100,true,OsMA)) class="kw">return; }
◍ 在EA里挂一个MACD并取双线缓冲
MT5 里用 iMACD 拿双线,标准周期是 12/26/9,价格源取收盘价。上面这段把句柄创建和缓冲读取拆得很清楚:OnInit 里建句柄,失败就打印错误并终止;OnTick 里靠 GetMACDBuffers 一次性把 Main 和 Signal 两条线填进数组。 代码逐行拆解: #include <GetIndicatorBuffers.mqh> 引入自定义缓冲读取工具。 double Main[]、double Signal[] 分别承接 MACD 主线与信号线。 int MACD_handle 存指标句柄,后续所有读取都靠它。 OnInit 中 MACD_handle=iMACD(NULL,0,12,26,9,PRICE_CLOSE) 在 current 图表建默认参数 MACD。 if(MACD_handle<0) 判错,Print 出 GetLastError 并返回 -1 终止初始化。 OnTick 中 if(!GetMACDBuffers(MACD_handle,0,100,Main,Signal,true)) return; 从 0 号柱往后取 100 根,按时间序列填充两数组,失败直接跳出本次 tick。 实盘接这层时记住:外汇和贵金属杠杆高、滑点大,MACD 双线金叉死叉只是概率信号,真要开仓得叠一层过滤。开 MT5 把这段塞进 EA 模板,改 GetMACDBuffers 的 100 为你的可视 K 线数,就能直接观察缓冲对齐有没有偏移。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double Main[]; class=class="str">"cmt">// iMACD指标中MAIN_LINE对应的数组 class="type">class="kw">double Signal[]; class=class="str">"cmt">//iMACD指标中SIGNAL_LINE对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int MACD_handle; class=class="str">"cmt">// iMACD指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iMACD指标 MACD_handle=iMACD(NULL,class="num">0,class="num">12,class="num">26,class="num">9,PRICE_CLOSE); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(MACD_handle<class="num">0) { Print("创建iMACD指标: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 设置数组索引方式为时间序列 class=class="str">"cmt">//--- 使用指标缓冲区的当前值填充数组 class=class="str">"cmt">//--- 如果出错则返回 if(!GetMACDBuffers(MACD_handle,class="num">0,class="num">100,Main,Signal,true)) class="kw">return; }
用 iOBV 句柄把量能累积搬进 EA
在 MT5 里接 OBV,第一步不是算公式,而是拿到指标句柄。iOBV(NULL,0,VOLUME_TICK) 这句在当前图表、当前周期上建了一个基于逐笔成交量的 OBV 实例,返回的整数就是后续所有读数的门禁卡。 句柄拿不到就别往下走。OnInit 里若 OBV_handle<0,直接 Print 运行时错误并 return(-1),EA 初始化失败总比带着空数组跑 Tick 强——后者会在 OnTick 里静默丢数据。 真正取数在 OnTick。CopyBufferAsSeries(OBV_handle,0,0,100,true,OBV) 一次性把最新 100 根 K 线的 OBV 值按时间序列塞进 OBV[],索引 0 即最新柱。外汇与贵金属杠杆高,OBV 只是量能倾向的参考,背离信号失败概率不低,验证前先用策略测试器跑一遍 EURUSD 的 M15 看填充是否连续。 下面这段是最小可编译骨架,重点看句柄创建和序列拷贝两处: #include <GetIndicatorBuffers.mqh> //---- 指标数组 double OBV[]; // iOBV指标对应的数组 //---- 指标句柄 int OBV_handle; // iOBV指标的句柄 //+------------------------------------------------------------------+
| // | EA初始化函数 |
|---|
//+------------------------------------------------------------------+ int OnInit() { //--- 创建iOBV指标 OBV_handle=iOBV(NULL,0,VOLUME_TICK); //--- 如果创建对象出错则报告 if(OBV_handle<0) { Print("创建iOBV指标失败: 运行时错误 =",GetLastError()); //--- 强制程序终止 return(-1); } return(0); } //+------------------------------------------------------------------+
| // | EA订单函数 |
|---|
//+------------------------------------------------------------------+ void OnTick() { //--- 使用iOBV指标的当前值填充OBV[]数组 //--- 设置OBV[]数组的索引方式为时间序列 //--- 如果出错则返回 if(!CopyBufferAsSeries(OBV_handle,0,0,100,true,OBV)) return; }
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double OBV[]; class=class="str">"cmt">// iOBV指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int OBV_handle; class=class="str">"cmt">// iOBV指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iOBV指标 OBV_handle=iOBV(NULL,class="num">0,VOLUME_TICK); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(OBV_handle<class="num">0) { Print("创建iOBV指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iOBV指标的当前值填充OBV[]数组 class=class="str">"cmt">//--- 设置OBV[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(OBV_handle,class="num">0,class="num">0,class="num">100,true,OBV)) class="kw">return; }
「在EA里挂一个抛物线转向点」
抛物线 SAR 在 MT5 里用 iSAR() 直接拿句柄,参数依次是图表符号、周期、步长、最大值。上面这段把步长写死成 0.02、最大值 0.2,是 Welwilder 原始设定的常用组合,适合趋势启动慢但延续性强的品种。 初始化时若句柄返回负数,说明指标创建失败,用 GetLastError() 把运行时错误打进日志,然后 return(-1) 终止 EA,避免后面空句柄去读数据把终端搞崩。 OnTick 里用 CopyBufferAsSeries 把最近 100 根 K 线的 SAR 值按时间序塞进 SAR[] 数组。注意第三个参数起始位 0、第四个长度 100,意味着每次 tick 都重拉一遍窗口,CPU 占用不高但足够覆盖短线反转观察。 外汇与贵金属波动受杠杆放大,SAR 在震荡市会频繁翻转,实盘前务必在策略测试器里用历史数据验证翻转频率与滑点影响。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double SAR[]; class=class="str">"cmt">// iSAR指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int SAR_handle; class=class="str">"cmt">// iSAR指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iSAR指标 SAR_handle=iSAR(NULL,class="num">0,class="num">0.02,class="num">0.2); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(SAR_handle<class="num">0) { Print("创建iSAR指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iSAR指标的当前值填充SAR[]数组 class=class="str">"cmt">//--- 设置SAR[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(SAR_handle,class="num">0,class="num">0,class="num">100,true,SAR)) class="kw">return; }
◍ 用 iRSI 句柄拉取序列数据
在 MT5 里调 RSI,先别急着手写计算公式,直接拿内置的 iRSI 函数拿句柄最省事。下面这段把周期设成 21、价格源用收盘价,比默认的 14 周期更平滑,对黄金 4H 级别的假突破过滤概率会高一些。 初始化阶段创建句柄,失败就打印错误码并终止 EA,这是避免后续空指针崩盘的基本动作。OnInit 里只建一次句柄,不要放到 OnTick 反复建,不然每跳都吃资源。 真正取数在 OnTick,用 CopyBufferAsSeries 把指标缓冲按时间序填进 RSI[],一次拉 100 根。你开 MT5 把这段贴进 EA,改个符号或周期就能直接看数组里的值,验证 RSI 滞后到底有多少根。外汇和贵金属杠杆高,RSI 只作辅助,信号失效时回撤可能很快。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double RSI[]; class=class="str">"cmt">// iRSI指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int RSI_handle; class=class="str">"cmt">// iRSI指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iRSI指标 RSI_handle=iRSI(NULL,class="num">0,class="num">21,PRICE_CLOSE); class=class="str">"cmt">//--- 如果创建对象失败则报告 if(RSI_handle<class="num">0) { Print("创建iRSI指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iRSI指标的当前值填充RSI[]数组 class=class="str">"cmt">//--- 设置RSI[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(RSI_handle,class="num">0,class="num">0,class="num">100,true,RSI)) class="kw">return; }
用 iRVI 句柄把相对活力指数拉进 EA
相对活力指数(RVI)衡量收盘价在价格波动区间里的位置,用来判断当前动能是偏买还是偏卖。MT5 里通过 iRVI() 直接拿指标句柄,比手动算 OHLC 的四则运算省事得多。 下面这段 EA 骨架把 iRVI 接进了 OnInit 与 OnTick。周期传 0 表示用当前图表周期,平滑参数 14 是 MT5 默认值,你可以改成 10 或 20 观察信号灵敏度变化。 #include <GetIndicatorBuffers.mqh> //---- 指标数组 double Main[]; // iRVI指标中MAIN_LINE对应的数组 double Signal[]; // iRVI指标中SIGNAL_LINE对应的数组 //---- 指标句柄 int RVI_handle; // iRVI指标的句柄 //+------------------------------------------------------------------+
| // | EA初始化函数 |
|---|
//+------------------------------------------------------------------+ int OnInit() { //--- 创建iRVI指标 RVI_handle=iRVI(NULL,0,14); //--- 如果对象创建出错则报告 if(RVI_handle<0) { Print("创建iRVI指标失败: 运行时错误 =",GetLastError()); //--- 强制程序终止 return(-1); } return(0); } //+------------------------------------------------------------------+
| // | EA订单函数 |
|---|
//+------------------------------------------------------------------+ void OnTick() { //--- 设置数组索引方式为时间序列 //--- 使用指标缓冲区当前值填充数组 //--- 如果出错则返回 if(!GetRVIBuffers(RVI_handle,0,100,Main,Signal,true)) return; } 代码逐行拆解: 第1行引入 GetIndicatorBuffers.mqh,里面封装了取缓冲区的函数。 第3–4行声明 Main 与 Signal 两个 double 数组,分别接 RVI 主线与信号线。 第6行声明 RVI_handle 整型变量,存指标句柄。 OnInit 里 RVI_handle=iRVI(NULL,0,14) 在当前图创建周期默认、参数14的 RVI;若返回负值就打印错误并终止初始化。 OnTick 中调用 GetRVIBuffers 把最新100根 K 线的主线、信号线填进数组,失败就直接 return 不往下跑。 开盘前把这段塞进 MT5 策略测试器,把 RVI_handle 打印出来,若返回正数说明句柄有效;外汇与贵金属杠杆高,RVI 仅作动能参考,实际触发下单还需叠加止损逻辑。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double Main[]; class=class="str">"cmt">// iRVI指标中MAIN_LINE对应的数组 class="type">class="kw">double Signal[]; class=class="str">"cmt">// iRVI指标中SIGNAL_LINE对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int RVI_handle; class=class="str">"cmt">// iRVI指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iRVI指标 RVI_handle=iRVI(NULL,class="num">0,class="num">14); class=class="str">"cmt">//--- 如果对象创建出错则报告 if(RVI_handle<class="num">0) { Print("创建iRVI指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 设置数组索引方式为时间序列 class=class="str">"cmt">//--- 使用指标缓冲区当前值填充数组 class=class="str">"cmt">//--- 如果出错则返回 if(!GetRVIBuffers(RVI_handle,class="num">0,class="num">100,Main,Signal,true)) class="kw">return; }
「用 iStdDev 拉出波动率尾巴」
标准差指标在 MT5 里靠 iStdDev 直接取句柄,比自己算方差省事,但句柄创建失败必须拦在 OnInit 里,否则后续 CopyBuffer 会静默空跑。上面这段把周期写死成 20、价格用收盘价、均线模式 MODE_SMA,是贵金属 4H 上最常用的保守配置。 初始化时传 NULL 和 0 表示绑定当前图表品种与周期,若返回负值就打印 GetLastError 并 return(-1),EA 会立刻停掉不再吃 tick。这一道防线能避免你半夜发现策略没跑却查不到原因。 OnTick 里用 CopyBufferAsSeries 把最近 100 根的标准差按时间序塞进 StdDev[],参数 true 代表序列索引(0 是最新柱)。外汇与贵金属杠杆高、跳空频繁,StdDev 放大时仓位要主动缩,否则回撤可能超出预期。 把 20 改成 10 或 50,在 MT5 策略测试器里跑同一段 EURUSD 数据,你会看到 StdDev 峰值位置明显前移或钝化,这就是调参的直观抓手。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double StdDev[]; class=class="str">"cmt">// iStdDev对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int StdDev_handle; class=class="str">"cmt">// iStdDev指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iStdDev指标 StdDev_handle=iStdDev(NULL,class="num">0,class="num">20,class="num">0,MODE_SMA,PRICE_CLOSE); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(StdDev_handle<class="num">0) { Print("创建iStdDev指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iStdDev指标的当前值填充StdDev[]数组 class=class="str">"cmt">//--- 设置StdDev[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(StdDev_handle,class="num">0,class="num">0,class="num">100,true,StdDev)) class="kw">return; }
◍ 用 iStochastic 句柄把随机指标搬进 EA
在 MT5 里调用随机指标,第一步是拿句柄而不是读价格。上面代码用 iStochastic(NULL,0,5,3,3,MODE_SMA,STO_LOWHIGH) 建了一个 %K 周期 5、慢速 3、信号 3、SMA 平滑、基于高低价的经典随机,句柄存进 Stochastic_handle。 OnInit 里若句柄小于 0 就打印运行时错误并 return(-1),这能避免后续 Tick 里空指针式报错。实盘外汇或贵金属波动大,句柄创建失败常发生在品种停盘或参数越界时,必须拦掉。 OnTick 中通过 GetStochasticBuffers 把主线和信号线缓冲区按时间序列填进 Main[] 与 Signal[],范围锁 0~100。拿到这两个数组后,你就可以在下一行写交叉判断,例如 Main[0]>Signal[0] 且 Main[1]<=Signal[1] 作为金叉倾向信号。 代码逐行拆解: #include <GetIndicatorBuffers.mqh> 引入自定义缓冲区获取头文件 double Main[] 存主线 %K 数值 double Signal[] 存信号线 %D 数值 int Stochastic_handle 存指标句柄 int OnInit() 初始化函数 Stochastic_handle=iStochastic(...) 创建指标并返回句柄 if(Stochastic_handle<0) 创建失败分支 Print 输出错误并 return(-1) 终止初始化 return(0) 初始化成功 void OnTick() 每笔报价触发 if(!GetStochasticBuffers(...)) return 填充数组失败则退出本次 Tick
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double Main[]; class=class="str">"cmt">// iStochastic指标中MAIN_LINE对应的数组 class="type">class="kw">double Signal[]; class=class="str">"cmt">// iStochastic指标中SIGNAL_LINE对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int Stochastic_handle; class=class="str">"cmt">// iStochastic指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iStochastic指标 Stochastic_handle=iStochastic(NULL,class="num">0,class="num">5,class="num">3,class="num">3,MODE_SMA,STO_LOWHIGH); class=class="str">"cmt">//--- 如果对象创建出错则报告 if(Stochastic_handle<class="num">0) { Print("创建iStochastic指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 设置数组的索引方式为时间序列 class=class="str">"cmt">//--- 使用指标缓冲区的当前值填充到数组中 class=class="str">"cmt">//--- 如果出错则返回 if(!GetStochasticBuffers(Stochastic_handle,class="num">0,class="num">100,Main,Signal,true)) class="kw">return; }
在EA里挂一条20期TEMA线
想把三重指数平滑均线(TEMA)直接嵌进MT5的EA,不必手搓算法,调用现成的iTEMA()即可。下面这段把指标句柄建出来,再在每个报价 tick 把最近100根K线的TEMA值灌进数组,省去重复计算。 初始化时以当前图表、当前周期、周期参数20、偏移0、收盘价源创建指标;句柄小于0就打印错误并终止,避免后续空指针。OnTick里用CopyBufferAsSeries按时间序取0号缓冲区的100个值,失败直接return,不耽误主逻辑。 外汇与贵金属杠杆高,TEMA只是滞后平滑工具,金叉死叉信号出现后价格仍可能反向扫损,实盘前务必在策略测试器跑多周期回测。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double TEMA[]; class=class="str">"cmt">// iTEMA指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int TEMA_handle; class=class="str">"cmt">// iTEMA指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iTEMA指标 TEMA_handle=iTEMA(NULL,class="num">0,class="num">20,class="num">0,PRICE_CLOSE); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(TEMA_handle<class="num">0) { Print("创建iTEMA指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iTEMA指标的当前值填充TEMA[]数组 class=class="str">"cmt">//--- 设置TEMA[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(TEMA_handle,class="num">0,class="num">0,class="num">100,true,TEMA)) class="kw">return; }
「用 iTriX 句柄抓三重平滑动量」
TriX 本质是对收盘价做三次指数平滑后再取一阶差分,用来剥掉均线里的噪声、只留趋势加速度。MT5 里不用自己写平滑循环,直接拿内置 iTriX 函数要句柄最省事。 下面这段 EA 骨架把周期写死成 20、价格域用收盘价。实盘里把 NULL 和 0 换成具体品种与图表周期,才能跨品种挂同一套逻辑。 OnInit 里建句柄失败就打印错误码并 return(-1),这是防止后续 CopyBuffer 读到空句柄导致爆仓式误信号的底线。外汇与贵金属杠杆高,句柄异常不拦截,可能让策略在断开重连瞬间乱发单。 OnTick 中用 CopyBufferAsSeries 按时间序取最近 100 根 TriX 值进数组,参数 true 决定序列方向。你打开 MT5 把 100 改成 500,能明显看到小周期反转被平滑掉的比例上升,倾向更少的假突破。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double TriX[]; class=class="str">"cmt">// iTriX指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int TriX_handle; class=class="str">"cmt">// iTriX指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iTriX指标 TriX_handle=iTriX(NULL,class="num">0,class="num">20,PRICE_CLOSE); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(TriX_handle<class="num">0) { Print("创建iTriX指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iTriX指标的当前值填充TriX[]数组 class=class="str">"cmt">//--- 设置TriX[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(TriX_handle,class="num">0,class="num">0,class="num">100,true,TriX)) class="kw">return; }
◍ 用 iWPR 拉取威廉指标缓冲
在 MT5 的 EA 里调用 iWPR,第一步是拿句柄而不是读数值。上面代码在 OnInit 里用 iWPR(NULL,0,14) 建了一个当前品种、当前周期、周期参数为 14 的威廉指标句柄,失败就打印错误并终止初始化。 OnTick 里真正取数靠 CopyBufferAsSeries:把句柄 0 号缓冲、从 0 到 100 根 K 线、按时间序列塞进 WPR[] 数组。这样 WPR[0] 就是最新一根 K 的 WPR 值,老数据往后排。 外汇和贵金属波动大,14 周期 WPR 在极端行情可能连续贴 -100 或 0,信号钝化概率不低。开 MT5 把这段直接贴进 EA 模板,改一下 14 这个参数,就能看到不同灵敏度下缓冲数组的变化。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double WPR[]; class=class="str">"cmt">// iWPR指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int WPR_handle; class=class="str">"cmt">// iWPR指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iWPR指标 WPR_handle=iWPR(NULL,class="num">0,class="num">14); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(WPR_handle<class="num">0) { Print("创建iWPR 指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iWPR指标的当前值填充WPR[]数组 class=class="str">"cmt">//--- 设置WPR[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(WPR_handle,class="num">0,class="num">0,class="num">100,true,WPR)) class="kw">return; }
在EA里挂上iVIDyA变速率均线
iVIDyA 是基于波动性调节平滑系数的动态均线,比传统 SMA 在震荡市里少给假突破信号。想在 MT5 的 EA 中直接调用它,核心是先拿句柄再按时间序列取缓冲。 下面这段 MQL5 演示了最小可用骨架:初始化时建句柄,每笔报价把最近 100 根柱的 iVIDyA 值灌进数组。参数里 14 是短期周期、21 是长期参考、PRICE_MEDIAN 用中间价计算,换品种时别照抄 NULL 和 0,实盘建议显式写图表 ID。 #include <GetIndicatorBuffers.mqh> //---- 指标数组 double VIDyA[]; // iVIDyA指标对应的数组 //---- handles for indicators int VIDyA_handle; // iVIDyA指标的句柄 //+------------------------------------------------------------------+
| // | EA初始化函数 |
|---|
//+------------------------------------------------------------------+ int OnInit() { //--- 创建iVIDyA指标 VIDyA_handle=iVIDyA(NULL,0,14,21,0,PRICE_MEDIAN); //--- 如果创建对象出错则报告 if(VIDyA_handle<0) { Print("创建iVIDyA指标失败: 运行时错误 =",GetLastError()); //--- 强制程序终止 return(-1); } return(0); } //+------------------------------------------------------------------+
| // | EA订单函数 |
|---|
//+------------------------------------------------------------------+ void OnTick() { //--- 使用iVlDyA指标的当前值填充VIDyA[]数组 //--- 设置VIDyA[]数组的索引方式为时间序列 //--- 如果出错则返回 if(!CopyBufferAsSeries(VIDyA_handle,0,0,100,true,VIDyA)) return; } 逐行看:第 1 行引头文件,提供 CopyBufferAsSeries 这类批量取缓冲的封装;VIDyA_handle 拿不到会进 if 分支打印错误码并终止,避免后面空数组乱算。OnTick 里那句 CopyBufferAsSeries 的 true 决定数组按时间倒序排,0 号位就是最新值,写交叉逻辑时别搞反下标。 外汇与贵金属杠杆高,iVIDyA 只过滤噪声不预示方向,信号触发后价格仍可能反向,先用策略测试器跑历史再上模拟盘。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double VIDyA[]; class=class="str">"cmt">// iVIDyA指标对应的数组 class=class="str">"cmt">//---- handles for indicators class="type">int VIDyA_handle; class=class="str">"cmt">// iVIDyA指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iVIDyA指标 VIDyA_handle=iVIDyA(NULL,class="num">0,class="num">14,class="num">21,class="num">0,PRICE_MEDIAN); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(VIDyA_handle<class="num">0) { Print("创建iVIDyA指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iVlDyA指标的当前值填充VIDyA[]数组 class=class="str">"cmt">//--- 设置VIDyA[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(VIDyA_handle,class="num">0,class="num">0,class="num">100,true,VIDyA)) class="kw">return; }
「用 iVolumes 抓 tick 成交量」
MT5 自带的 iVolumes 能直接取成交量序列,参数 VOLUME_TICK 代表按逐笔 tick 计,而不是按分钟 bar 聚合。对黄金和外汇来说,tick 量比 bar 量更贴近真实流动性脉冲,尤其在数据行情前后。 下面这段 EA 骨架演示了最小可用接法:初始化时建句柄,OnTick 里用 CopyBufferAsSeries 把最近 100 根序列倒序填进数组。句柄失败就打印错误并终止,避免空跑。 注意 CopyBufferAsSeries 最后一个 true 是把数组设为时间序列(索引 0 是最新 tick),若填 false 则索引 0 是最旧数据,写条件判断时极易反向。外汇与贵金属杠杆高、滑点突变频繁,仅凭成交量异动入场仍属概率行为,须配合止损。
class="macro">#include <GetIndicatorBuffers.mqh> class=class="str">"cmt">//---- 指标数组 class="type">class="kw">double Volumes[]; class=class="str">"cmt">// iVolumes指标对应的数组 class=class="str">"cmt">//---- 指标句柄 class="type">int Volumes_handle; class=class="str">"cmt">// iVolumes指标的句柄 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 创建iVolumes指标 Volumes_handle=iVolumes(NULL,class="num">0,VOLUME_TICK); class=class="str">"cmt">//--- 如果创建对象出错则报告 if(Volumes_handle<class="num">0) { Print("创建 iVolumes 指标失败: 运行时错误 =",GetLastError()); class=class="str">"cmt">//--- 强制程序终止 class="kw">return(-class="num">1); } class="kw">return(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA订单函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 使用iVolumes指标的当前值填充Volumes[]数组 class=class="str">"cmt">//--- 设置Volumes[]数组的索引方式为时间序列 class=class="str">"cmt">//--- 如果出错则返回 if(!CopyBufferAsSeries(Volumes_handle,class="num">0,class="num">0,class="num">100,true,Volumes)) class="kw">return; }
◍ 记住这一条就够了
在 MT5 的 EA 里挂标准指标并不比老版本麻烦,关键是把所有可能出错的分支都先堵死——外汇和贵金属杠杆高,一个未处理的空句柄就可能让实盘单子飞出去。 下面这段就是把布林带的价格源从 PRICE_CLOSE 换成自定义均线句柄的写法,核心就在最后一个参数: Bands_handle=iBands(NULL,0,144,0,2, MA_Custom_handle); 先拿 iCustom 拿到自定义 MA 的句柄,再把这个句柄喂给 iBands,终端里手动选『上一指标』本质就是传 handle 而不是枚举价格。 开 MT5 新建 EA,把 MA_Custom_handle 和 Bands_handle 两行原样贴进 OnInit,编译后看右侧数据窗口能否取到缓冲区;取不到就说明句柄生命周期或品种周期写错了。真金白银的事,校验不过就别让机器人跑。
Bands_handle=iBands(NULL,class="num">0,class="num">144,class="num">0,class="num">2,PRICE_CLOSE); Bands_handle=iBands(NULL,class="num">0,class="num">144,class="num">0,class="num">2,PRICE_CLOSE); class="type">int iBands( class="type">class="kw">string symbol, class=class="str">"cmt">// 字符名 ENUM_TIMEFRAMES period, class=class="str">"cmt">// 期间 class="type">int bands_period, class=class="str">"cmt">// 计算平均线的周期 class="type">int bands_shift, class=class="str">"cmt">// 指示器水平偏移 class="type">class="kw">double deviation, class=class="str">"cmt">// 标准差数 ENUM_APPLIED_PRICE applied_price class=class="str">"cmt">// 价格类型或句柄 ); MA_Custom_handle=iCustom(NULL,class="num">0,"Examples\\Custom Moving Average", MA_Period, MA_Shift, MA_Method, PRICE_CLOSE ); Bands_handle=iBands(NULL,class="num">0,class="num">144,class="num">0,class="num">2, MA_Custom_handle );