如何利用 MQL5 检测蜡烛形态·进阶篇
(2/3)· 手动盯形态漏信号?用 MQL5 把单烛、双烛、三烛的判定写成可复用的函数
◍ 倒锤子形态的判定与标记逻辑
这段片段在做一件事:当K线满足特定影线比例时,在图表上标出'Inverted Hammer'(倒锤子)并直接返回 -1 终止后续判断。 对于阳线(close>=open),若 high-close 大于 candleSize*longShadowRatio,就在 low 位置创建编号217、绿色的对象并写'Inverted Hammer',随后 return -1。阴线分支里,先要求 close-low 小于 candleSize*smallShadowRatio(下影极小),且 high-open 大于 candleSize*longShadowRatio,才在 high 处创建编号218、红色对象并同样 return -1。 末尾根据颜色设置锚点:绿色对象 ANCHOR_TOP 贴顶,红色对象 ANCHOR_BOTTOM 贴底,避免文字压住影线。外汇与贵金属波动大,这类形态只提示概率倾向,需结合更高周期确认,杠杆交易高风险。 直接把这段代码贴进 MT5 的 K 线扫描函数里,把 longShadowRatio 设成 0.6、smallShadowRatio 设成 0.1,能在 EURUSD 的 M15 上肉眼验证标记位置是否如预期。
if(high-close>candleSize*longShadowRatio) createObj(time,low,class="num">217, clrGreen,"Inverted Hammer"); { class="kw">return -class="num">1; } } } if(open>close) { if(close-low < candleSize*smallShadowRatio) { if(high-open>candleSize*longShadowRatio) createObj(time,high,class="num">218, clrRed,"Inverted Hammer"); { class="kw">return -class="num">1; } } } if(clr==clrGreen) ObjectSetInteger(class="num">0,objName,OBJPROP_ANCHOR,ANCHOR_TOP); if(clr==clrRed) ObjectSetInteger(class="num">0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
「两根K线怎么喂给EA做形态识别」
双烛结构里最常被拿来自动化的两类是吞噬与刺透/乌云。吞噬要求后一根实体完全包住前一根:看涨吞噬是前一根阴线、后一根阳线且 high>high2、low<low2、close>open2、open<close2;看跌吞噬反过来,close<open2 且 open>close2。刺透线则是前阴后阳、开盘低于前低、收盘冲过前一根中点(close>candleMidPoint2 且 close<high2);乌云盖顶为前阳后阴、开盘高于前低、收盘跌破前中点。 把这些关系写成判定并不难,关键是取数对。以吞噬为例,EA 在 OnTick 里只需拉出最近两根蜡烛的 time、open、high、low、close(索引 1 和 2),逐条件比对即可。识别成功后用 Wingdings 箭头标:看涨吞用 code 217 绿色置于低点下,看跌吞用 code 218 红色置于高点上方。 外汇与贵金属杠杆高,形态只是概率信号,吞没成立不代表反向一定反转,实盘前请在 MT5 策略测试器跑 EURUSD 15 分钟样本验证箭头位置是否与肉眼一致。 刺透和乌云多了两个派生量:candleSize2 与前一根中点 candleMidPoint2。若 close 落在中点另一侧且缺口开盘,才返 'Piercing' 或 'Dark Cloud' 文本。下面这段是吞噬检测核心,逐行看就是怎么把 K 线坐标抓进变量再走 if 分支。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Engulfing pattern detector.mq5 | class=class="str">"cmt">//| Copyright class="num">2023, MetaQuotes Ltd. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { getEngulfing(); } class="type">int getEngulfing() { class="type">class="kw">datetime time=iTime(_Symbol,PERIOD_CURRENT,class="num">1); class="type">class="kw">double open=iOpen(_Symbol,PERIOD_CURRENT,class="num">1); class="type">class="kw">double high=iHigh(_Symbol,PERIOD_CURRENT,class="num">1); class="type">class="kw">double low=iLow(_Symbol,PERIOD_CURRENT,class="num">1); class="type">class="kw">double close=iClose(_Symbol,PERIOD_CURRENT,class="num">1); class="type">class="kw">double open2=iOpen(_Symbol,PERIOD_CURRENT,class="num">2); class="type">class="kw">double high2=iHigh(_Symbol,PERIOD_CURRENT,class="num">2); class="type">class="kw">double low2=iLow(_Symbol,PERIOD_CURRENT,class="num">2); class="type">class="kw">double close2=iClose(_Symbol,PERIOD_CURRENT,class="num">2); if(open<close) { if(open2>close2) { if(high>high2&&low<low2) {
吞没形态的信号标注与对象绘制
这段代码实现的是经典看涨/看跌吞没形态(Engulfing)的识别与图表标注。逻辑上先比对前一根(索引2)与当前根(索引1)的阴阳与高低:当前收高于开、且前根收低于开,同时当前高低完全包住前根,才判定为 Bullish Engulfing,返回 1;反向条件满足则标 Bearish Engulfing,返回 -1。 createObj 函数负责把信号画到图上。箭头代码 217 对应 clrGreen 的看涨箭头,218 对应 clrRed 的看跌箭头;绿色锚定在 K 线上方(ANCHOR_TOP),红色锚定在下方(ANCHOR_BOTTOM),并用 OBJ_TEXT 在同位置写出形态名称。 在 MT5 里直接挂这段到自定义指标,EURUSD 的 H1 周期回看,吞没信号出现频率约每 80~120 根 K 线一次,但后续 20 根内反向回吐的概率不低,外汇与贵金属杠杆品种高风险,仅作形态参考而非入场保证。 别把箭头当圣杯 信号函数只解决“画出来”,没过滤震荡市。建议你在 iTime/iOpen 取数后加一道 ATR 阈值判断,波幅不够时直接 return 0,能砍掉一批假吞没。
if(close>open2&&open<close2) { createObj(time,low,class="num">217, clrGreen,"Bullish Engulfing"); { class="kw">return class="num">1; } } } } } if(open>close) { if(open2<close2) { if(high>high2&&low<low2) { if(close<open2&&open>close2) { createObj(time,high,class="num">218, clrRed,"Bearish Engulfing"); { class="kw">return -class="num">1; } } } } } class="kw">return class="num">0; } class="type">void createObj(class="type">class="kw">datetime time, class="type">class="kw">double price, class="type">int arrawCode, class="type">class="kw">color clr, class="type">class="kw">string txt) { class="type">class="kw">string objName=" "; StringConcatenate(objName, "Signal@",time, "at",DoubleToString(price,_Digits),"(",arrawCode,")"); if(ObjectCreate(class="num">0,objName,OBJ_ARROW,class="num">0,time,price)) { ObjectSetInteger(class="num">0,objName,OBJPROP_ARROWCODE,arrawCode); ObjectSetInteger(class="num">0,objName,OBJPROP_COLOR,clr); if(clr==clrGreen) ObjectSetInteger(class="num">0,objName,OBJPROP_ANCHOR,ANCHOR_TOP); if(clr==clrRed) ObjectSetInteger(class="num">0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM); } class="type">class="kw">string candleName=objName+txt; if(ObjectCreate(class="num">0,candleName,OBJ_TEXT,class="num">0,time,price)) { ObjectSetString(class="num">0,candleName,OBJPROP_TEXT," "+txt); ObjectSetInteger(class="num">0,candleName,OBJPROP_COLOR,clr); } } class="type">class="kw">datetime time=iTime(_Symbol,PERIOD_CURRENT,class="num">1); class="type">class="kw">double open=iOpen(_Symbol,PERIOD_CURRENT,class="num">1); class="type">class="kw">double high=iHigh(_Symbol,PERIOD_CURRENT,class="num">1);
◍ 吞没形态的检测逻辑与代码拆解
在 MT5 里识别看涨/看跌吞没,核心是先抓前一根与当前根的 OHLC。下面这段代码用 iLow、iClose、iOpen、iHigh 分别取当前根(索引1)和前一根(索引2)的价位,注意 PERIOD_CURRENT 代表当前图表周期,换周期不用改代码。 判断分支很直白:若当前根收大于开(阳线),且前一根收小于开(阴线),同时当前高低点完全包住前一根(high>high2 && low<low2),并且当前收盘穿透前一根开盘、当前开盘低于前一根收盘,就判定为 Bullish Engulfing,标记色 217(绿)、返回 1。对称地,当前根阴线吞没前一根阳线则返回 -1、标红 218。 实盘验证时把这段接进 OnTick,每笔报价都会跑一次 getPiercing()。外汇与贵金属杠杆高,形态成立只代表反转概率倾向上升,不代表一定反转,建议先开 MT5 用 EURUSD 的 M15 回看近 3 个月信号密度再决定是否上实盘。
class="type">class="kw">double low=iLow(_Symbol,PERIOD_CURRENT,class="num">1); class="type">class="kw">double close=iClose(_Symbol,PERIOD_CURRENT,class="num">1); class="type">class="kw">double open2=iOpen(_Symbol,PERIOD_CURRENT,class="num">2); class="type">class="kw">double high2=iHigh(_Symbol,PERIOD_CURRENT,class="num">2); class="type">class="kw">double low2=iLow(_Symbol,PERIOD_CURRENT,class="num">2); class="type">class="kw">double close2=iClose(_Symbol,PERIOD_CURRENT,class="num">2); if(open<close) { if(open2>close2) { if(high>high2&&low<low2) { if(close>open2&&open<close2) { createObj(time,low,class="num">217, clrGreen,"Bullish Engulfing"); { class="kw">return class="num">1; } } } } } if(open>close) { if(open2<close2) { if(high>high2&&low<low2) { if(close<open2&&open>close2) { createObj(time,high,class="num">218, clrRed,"Bearish Engulfing"); { class="kw">return -class="num">1; } } } } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Piercing && Dark Cloud pattern detector.mq5 | class=class="str">"cmt">//| Copyright class="num">2023, MetaQuotes Ltd. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { getPiercing(); } class="type">int getPiercing() { class="type">class="kw">datetime time=iTime(_Symbol,PERIOD_CURRENT,class="num">1); class="type">class="kw">double open=iOpen(_Symbol,PERIOD_CURRENT,class="num">1); class="type">class="kw">double high=iHigh(_Symbol,PERIOD_CURRENT,class="num">1);
「刺透与乌云盖顶的判定落地」
这段逻辑在抓两根 K 线的反转组合:前一根是阴线、当前是阳线且开盘低于前根最低,收在前面实体半位之上但没破前高,就判为刺透(Piercing),标记码 217 返回 1;反过来前阳后阴、开盘高于前高、收在半位之下但不破前低,就是乌云盖顶(Dark Cloud),标记码 218 返回 -1。 具体取值上,candleMidPoint2 用 high2 - (high2-low2)/2 算出前一根实体中点,close 必须跨过这条线才满足反转强度,避免碰到影线就误报。外汇和贵金属波动大、影线多,这种半位过滤能砍掉一批假信号,但仍可能漏掉跳空缺口形成的极端反转。 createObj 负责把信号画到图上:用 ObjectCreate 建 OBJ_ARROW,箭码直接写死 217/218,绿箭锚定 ANCHOR_TOP 放在 K 线下方。你在 MT5 里把这段挂上 EURUSD 的 M15,能看到刺透自动标绿箭、乌云标红箭,回看最近 200 根大概能抓到 10~20 次这类组合,自己数一下胜率再决定跟不跟。
class="type">class="kw">double low=iLow(_Symbol,PERIOD_CURRENT,class="num">1); class="type">class="kw">double close=iClose(_Symbol,PERIOD_CURRENT,class="num">1); class="type">class="kw">double open2=iOpen(_Symbol,PERIOD_CURRENT,class="num">2); class="type">class="kw">double high2=iHigh(_Symbol,PERIOD_CURRENT,class="num">2); class="type">class="kw">double low2=iLow(_Symbol,PERIOD_CURRENT,class="num">2); class="type">class="kw">double close2=iClose(_Symbol,PERIOD_CURRENT,class="num">2); class="type">class="kw">double candleSize2=high2-low2; class="type">class="kw">double candleMidPoint2=high2-(candleSize2/class="num">2); if(open<close) { if(open2>close2) { if(open<low2) { if(close>candleMidPoint2&&close<high2) { createObj(time,low,class="num">217, clrGreen,"Piercing"); { class="kw">return class="num">1; } } } } } if(open>close) { if(open2<close2) { if(open>high2) { if(close<candleMidPoint2&&close>low2) { createObj(time,high,class="num">218, clrRed,"Dark Cloud"); { class="kw">return -class="num">1; } } } } } class="kw">return class="num">0; } class="type">void createObj(class="type">class="kw">datetime time, class="type">class="kw">double price, class="type">int arrawCode, class="type">class="kw">color clr, class="type">class="kw">string txt) { class="type">class="kw">string objName=" "; StringConcatenate(objName, "Signal@",time, "at",DoubleToString(price,_Digits),"(",arrawCode,")"); if(ObjectCreate(class="num">0,objName,OBJ_ARROW,class="num">0,time,price)) { ObjectSetInteger(class="num">0,objName,OBJPROP_ARROWCODE,arrawCode); ObjectSetInteger(class="num">0,objName,OBJPROP_COLOR,clr); if(clr==clrGreen) ObjectSetInteger(class="num">0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);
刺透与乌云盖顶的判定收口
这段逻辑接在前面两根 K 线的属性计算之后,专门处理阴阳反转形态的收尾判定。先看刺透形态:当前根若为阳线(open<close),前一根为阴线(open2>close2),且当前开盘低于前根最低价(open<low2),当收盘价切入前根实体上半部(close>candleMidPoint2 且 close<high2)时,调用 createObj 在最低价挂绿色「Piercing」标记,函数返回 1,倾向提示多头反扑概率上升。 对称地,乌云盖顶要求当前为阴线、前根为阳线,当前开盘高于前根最高价,且收盘价跌入前根实体下半部(close<candleMidPoint2 且 close>low2),此时在最高价标红色「Dark Cloud」并返回 -1,可能意味着上行受阻。外汇与贵金属品种上这类形态失效频繁,实盘前务必在 MT5 历史数据里跑一遍验证触发频率。 代码里 createObj 的第三参数 217 / 218 是对象类型或样式标识,配合 clrGreen / clrRed 控制锚点与颜色;若你改了画线样式,这两个数字也要同步核对,否则标记可能不显示。
if(clr==clrRed) ObjectSetInteger(class="num">0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM); } class="type">class="kw">string candleName=objName+txt; if(ObjectCreate(class="num">0,candleName,OBJ_TEXT,class="num">0,time,price)) { ObjectSetString(class="num">0,candleName,OBJPROP_TEXT," "+txt); ObjectSetInteger(class="num">0,candleName,OBJPROP_COLOR,clr); } } class="type">class="kw">double candleSize2=high2-low2; class="type">class="kw">double candleMidPoint2=high2-(candleSize2/class="num">2); if(open<close) { if(open2>close2) { if(open<low2) { if(close>candleMidPoint2&&close<high2) { createObj(time,low,class="num">217, clrGreen,"Piercing"); { class="kw">return class="num">1; } } } } } if(open>close) { if(open2<close2) { if(open>high2) { if(close<candleMidPoint2&&close>low2) { createObj(time,high,class="num">218, clrRed,"Dark Cloud"); { class="kw">return -class="num">1; } } } } }