如何利用 MQL5 检测蜡烛形态·综合运用
(3/3)·把十字星、吞没、晨星等形态写成可复用函数,让你的终端自己报信号
很多交易者盯着图表手动数蜡烛,漏看一根就可能错过关键反转。把形态识别写进 MQL5,终端会在跳价时自动判定,你只需要在信号出现时做决策。本文是系列收尾篇,聚焦单烛、双烛、三烛形态的综合检测实现。
◍ 三烛形态
在这一部分中,我们将看到混合形态中的两种形态,它们是星形(Star)形态(晨星、暮星),和三个内部形态(向上、向下)。 星形(Star)形态: 晨星: 它与我们提过的三根蜡烛结构相同。 它由两根蜡烛之间的小蜡烛形成,第一根是较长看跌,第二根是较长看涨。 下图是它的图例: 取决于其显著性,它表明推动力从卖出转向买入,因为自卖方控制下的压低后,买方控制市场,并推高价格。 暮星形态: 它与我们提过的三根蜡烛结构相同。 它由两根蜡烛之间的小蜡烛形成,第一根是较长看涨,第二根是较长看跌。 下图是它的图例: 取决于其显著性,它表明推动力从买入转向卖出,因为自买方控制下的推高后,卖方控制市场,并压低价格。 当我们想要创建一个可检测这种形态的程序时,我们需要定义最后一根蜡烛的时间和价格,以及最后一根蜡烛之前两根蜡烛的价格数据,之前第三根蜡烛的大小,并将它们相互比较,以便判定它们彼此的相对位置,从而根据特定条件获得特定信号。 以下是创建此程序的完整代码: 此代码的不同之处 依据 middleCandleRatio 参数,创建(getStar) 创建变量保存最后一根蜡烛时间和价格数据(open、high、low、close),和最后三根蜡烛的大小(candlesize、candleSize2 和 candleSize3 ) 形态的条件 若为晨星形态的情况: 如果最后一根蜡烛看涨(open<close),第三根蜡烛看跌(open3>close3),candleSize2<candleSize 的 middleCandleRatio 0.5,同时 candleSize2<candleSize3 的 middleCandleRatio,我们需要程序在形态低点下方返回一个绿色箭头对象,和 “Morning Star” 文本, 然后终止函数。 若为暮星形态的情况: 如果最后一根蜡烛看跌(open>close), 第三根蜡烛看涨(open3<close3) ,candleSize2<candleSize 的 middleCandleRatio 0.5,同时 candleSize2<candleSize3 的 middleCandleRatio,我们需要程序在形态低点下方返回一个红色箭头对象,和 “Evening Star” 文本, 然后终止函数。 在编译此代码,且没有错误,并执行其 EA 后,我们可从测试中获得与以下示例相同的信号: 晨星: 如我们所见,我们在检测到的形态下方的图表上得到所需对象的期望信号。 暮星: 如我们所见,我们在检测到的形态下方的图表上得到所需对象的期望信号。 作为星形形态的注解,相同的形态形成与中间的小蜡烛有间隙,如果您想获得相同的形态,可以将其作为附加条件添加到代码之中。 三内含形态: 三内含向上: 这也是三根蜡烛形态,第一根蜡烛是较长看跌,第二根是较短看涨蜡烛,且全部在第一根蜡烛内部,第三根是较长看涨蜡烛,收于第一根高点上方。 以下是此形态的图例。 取决于其显著性,它表明买方控制的潜在看涨。 三内含向下: 这也是三根蜡烛形态,第一根蜡烛是较长看涨,第二根是较短看跌蜡烛,且全部在第一根蜡烛内部,第三根是较长看跌蜡烛,收于第一根低点下方。 以下是此形态的图例。 取决于其显著性,它表明卖方控制的潜在看跌。 如果我们想创建一个可检测此类形态的程序,我们还需定义最后一根蜡烛的时间和最后三根蜡烛的价格数据,程序会在每次跳价时检查这些数值,并判定其彼此的相对位置,以便根据形态返回相应的信号作为图表上的对象。 以下是该程序的完整代码: 此代码中的不同之处在于形态的
「晨星与暮星的信号判定和图形标注」
这段逻辑用三根 K 线识别经典反转形态:当前根(索引1)为阳线且三根前(索引3)为阴线时,若中间根(索引2)的实体振幅同时小于左右两根乘以 middleCandleRatio,就判定为晨星并回传 1;反之为暮星回传 -1,都不满足回传 0。 middleCandleRatio 是形态有效性的核心阈值,实盘里常取 0.3~0.5,值越小代表中间十字星越萎缩、信号越苛刻。外汇与贵金属波动剧烈,此类形态仅代表概率倾斜,不代表后续必反转,请先在 MT5 策略测试器用历史数据验证。 createObj 负责把信号画到图上:晨星用箭头代码 217 配 clrGreen 锚定在 K 线顶部,暮星用 218 配 clrRed 锚定底部,同时用 OBJ_TEXT 在同级坐标写出 "Morning Star" 或 "Evening Star" 字样,方便肉眼复核。 下面这段是判定与标注的 MQL5 原文,逐行看逻辑比读说明更快:先取 close3 与前三根收盘比对阴阳,再比实体大小,最后调 createObj 落图形。
class="type">class="kw">double close3=iClose(_Symbol,PERIOD_CURRENT,class="num">3); class="type">class="kw">double candleSize=high-low; class="type">class="kw">double candleSize2=high2-low2; class="type">class="kw">double candleSize3=high3-low3; if(open<close) { if(open3>close3) { if(candleSize2<candleSize*middleCandleRatio && candleSize2<candleSize3*middleCandleRatio) { createObj(time,low,class="num">217, clrGreen,"Morning Star"); { class="kw">return class="num">1; } } } } if(open>close) { if(open3<close3) { if(candleSize2<candleSize*middleCandleRatio && candleSize2<candleSize3*middleCandleRatio) { createObj(time,high,class="num">218, clrRed,"Evening Star"); { 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">int getStar(class="type">class="kw">double middleCandleRatio) 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);
三K线星型形态的MT5判定逻辑
晨星与暮星这类三K线反转形态,核心不在于名字,而在于中间那根K线相对两侧的'萎缩'。下面这段代码直接取当前周期最近三根K线(索引1/2/3,即倒数第二、三、四根已完成K线)的 OHLC 与实体高度,用 middleCandleRatio 做中间根的尺寸过滤。 double high=iHigh(_Symbol,PERIOD_CURRENT,1); // 取倒数第二根最高价 double low=iLow(_Symbol,PERIOD_CURRENT,1); // 取倒数第二根最低价 double close=iClose(_Symbol,PERIOD_CURRENT,1);// 取倒数第二根收盘价 double open2=iOpen(_Symbol,PERIOD_CURRENT,2); // 取倒数第三根开盘价 double high2=iHigh(_Symbol,PERIOD_CURRENT,2); // 取倒数第三根最高价 double low2=iLow(_Symbol,PERIOD_CURRENT,2); // 取倒数第三根最低价 double close2=iClose(_Symbol,PERIOD_CURRENT,2);// 取倒数第三根收盘价 double open3=iOpen(_Symbol,PERIOD_CURRENT,3); // 取倒数第四根开盘价 double high3=iHigh(_Symbol,PERIOD_CURRENT,3); // 取倒数第四根最高价 double low3=iLow(_Symbol,PERIOD_CURRENT,3); // 取倒数第四根最低价 double close3=iClose(_Symbol,PERIOD_CURRENT,3);// 取倒数第四根收盘价 double candleSize=high-low; // 倒数第二根实体+影线总高度 double candleSize2=high2-low2; // 倒数第三根总高度 double candleSize3=high3-low3; // 倒数第四根总高度 if(open<close) // 倒数第二根为阳线 { if(open3>close3) // 倒数第四根为阴线 { if(candleSize2<candleSize*middleCandleRatio && candleSize2<candleSize3*middleCandleRatio) // 中间根显著小于两侧 { createObj(time,low,217, clrGreen,"Morning Star"); // 在低点画绿色标记,编码217 return 1; // 返回多头信号 } } } if(open>close) // 倒数第二根为阴线 { if(open3<close3) // 倒数第四根为阳线 { if(candleSize2<candleSize*middleCandleRatio && candleSize2<candleSize3*middleCandleRatio) { createObj(time,high,218, clrRed,"Evening Star"); // 在高点画红色标记,编码218 return -1; // 返回空头信号 } } } 判定只依赖已收盘K线,因此信号在每根K线收线后才会固定,盘中闪现不算数。middleCandleRatio 若设为 0.5,意味着中间根高度必须不到两侧任一根的一半才触发,参数调小则形态更苛刻、信号更少。 外汇与贵金属杠杆高、滑点大,星型形态只是概率倾向反转,实盘须结合更大周期结构过滤,切勿单独据此重仓。
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); class="type">class="kw">double open3=iOpen(_Symbol,PERIOD_CURRENT,class="num">3); class="type">class="kw">double high3=iHigh(_Symbol,PERIOD_CURRENT,class="num">3); class="type">class="kw">double low3=iLow(_Symbol,PERIOD_CURRENT,class="num">3); class="type">class="kw">double close3=iClose(_Symbol,PERIOD_CURRENT,class="num">3); class="type">class="kw">double candleSize=high-low; class="type">class="kw">double candleSize2=high2-low2; class="type">class="kw">double candleSize3=high3-low3; if(open<close) { if(open3>close3) { if(candleSize2<candleSize*middleCandleRatio && candleSize2<candleSize3*middleCandleRatio) { createObj(time,low,class="num">217, clrGreen,"Morning Star"); { class="kw">return class="num">1; } } } } if(open>close) { if(open3<close3) { if(candleSize2<candleSize*middleCandleRatio && candleSize2<candleSize3*middleCandleRatio) { createObj(time,high,class="num">218, clrRed,"Evening Star"); { class="kw">return -class="num">1; } } } }
◍ 三内部形态在MT5里的裸写识别
三内部(Three Inside)是价格行为里典型的反转确认形态,分向上和向下两类。向上三内部要求第3根阴线、第2根阳线完全包在第3根实体内、第1根阳线再突破第3根高点;向下则对称反转。下面这段代码在每笔报价时抓取最近3根当前周期K线并做条件判定,命中即在K线低位画标记。 外汇与贵金属杠杆高,形态失效是常态,这段代码只做识别不替你下单,信号出现后仍需人工确认上下文。 代码逐行看:iTime/iOpen/iHigh/iLow/iClose 分别取1、2、3号K线(序号从0当前往回数)的时间与OHLC;先判 open3>close3 即第3根收阴,再看 open2<close2 第2根收阳且被第3根实体容纳(open2>low3 && close2<high3),最后第1根收阳且实体处于第2根内部、收盘价破第3根高点,则画绿色『3 Inside Up』对象,编号217是箭头样式。向下分支逻辑镜像,判第3根阳、第2根阴、第1根阴破第3根低点。
class="macro">#class="kw">property link "[MQL5官方文档] class="macro">#class="kw">property version "class="num">1.00" class="type">void OnTick() { getthreeInside(); } class="type">int getthreeInside() { 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); class="type">class="kw">double open3=iOpen(_Symbol,PERIOD_CURRENT,class="num">3); class="type">class="kw">double high3=iHigh(_Symbol,PERIOD_CURRENT,class="num">3); class="type">class="kw">double low3=iLow(_Symbol,PERIOD_CURRENT,class="num">3); class="type">class="kw">double close3=iClose(_Symbol,PERIOD_CURRENT,class="num">3); if(open3>close3) { if(open2<close2) { if(open2>low3&&close2<high3) { if(open<close&&open>open2&&open<close2) { if(close>high3) { createObj(time,low,class="num">217, clrGreen,"class="num">3 Inside Up"); { class="kw">return class="num">1; } } } } } } if(open3<close3) { if(open2>close2) { if(open2<high3&&close2>low3) { if(open>close&&open<open2&&open>close2) { if(close<low3) {
「三内升跌形态的信号标注函数」
这段逻辑把「三内跌」(3 Inside Down) 与「三内升」(3 Inside Up) 的识别结果直接画到 MT5 主图。前面判断出三内跌时调用 createObj(time,high,218,clrRed,"3 Inside Down"),箭头代码 218 对应红色向下标记,锚点落在 K 线底部;三内升则传 217 与 clrGreen,锚点置顶。 createObj 本身先拼出唯一对象名:Signal@+时间+at+价格(按 _Digits 精度)+括号里箭头码,再用 OBJ_ARROW 建箭头、OBJ_TEXT 建文字标签。绿色走 ANCHOR_TOP,红色走 ANCHOR_BOTTOM,肉眼上涨信号压在最高上方、下跌信号贴在最低下方,不挡实体。 识别嵌套很直白:以三内升为例,第3根须为阴线(open3>close3),第2根为阳线且实体被第3根吞没(open2<close2 且高低在第3根范围内),第1根阳线开盘介于第2根实体内部且收盘突破第3根高点(close>high3)才确认。外汇与贵金属波动大,这种形态只提示概率倾向反转,实盘须自验。
createObj(time,high,class="num">218, clrRed,"class="num">3 Inside Down"); { 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); } } if(open3>close3) { if(open2<close2) { if(open2>low3&&close2<high3) { if(open<close&&open>open2&&open<close2) { if(close>high3) { createObj(time,low,class="num">217, clrGreen,"class="num">3 Inside Up"); { class="kw">return class="num">1; } } } } } } if(open3<close3) { if(open2>close2) { if(open2<high3&&close2>low3) {
三内向下破位的代码判定
在 MT5 的 K 线扫描逻辑里,三内跌(3 Inside Down)并非靠肉眼数蜡烛,而是用三根前置 K 线加当前 K 线做联立条件。上面这段代码片段只负责「确认并标记」环节,前置的 inside bar 结构已在更早分支里筛过。 判定核心是:当前 K 线为阴线(open>close),且其实体开盘价低于前一根开盘价(open<open2)、却高于前一根收盘价(open>close2);在此基础上,若收盘价跌破再前一根低点 low3,则视为向下破位。 破位成立后调用 createObj 在 time 位置、high 价位画一个编号 218、红色标签为「3 Inside Down」的对象,并返回 -1 终止后续同帧判断。外汇与贵金属品种上,这种形态出现后价格惯性下破的概率偏高,但杠杆市场随时反向,实盘前务必用策略测试器跑一遍近 3 个月数据。
if(open>close&&open<open2&&open>close2) { if(close<low3) { createObj(time,high,class="num">218, clrRed,"class="num">3 Inside Down"); { class="kw">return -class="num">1; } } }
◍ 别急着下结论
前面六节把单烛、双烛、三烛的识别程序都拆完了:十字星与锤形归在 Doji_pattern_detector.mq5(1.42 KB)和 Hammer_pattern_detector.mq5(2.75 KB);吞噬、刺透、乌云盖顶共用 Engulfing_pattern_detector.mq5(2.37 KB)和 Piercing_ss_Dark_Cloud_pattern_detector.mq5(2.44 KB);星状与三内含则由 Star_pattern_detector.mq5(3.32 KB)、Three_inside_pattern_detector.mq5(2.88 KB)承载。 这些脚本只是把形态从图表里抓出来,不代表出现信号就该动手。外汇和贵金属杠杆高、滑点跳空频繁,同一组吞噬形态在欧美盘与亚盘的成功概率可能差出两三成。 拿 Adams.16 在讨论区的反馈说,他把矩形标记换成信号后指标跑得快了,却卡在「无法把当前信号时间定为上一信号起点的斐波终点」——这说明形态识别只是流水线第一环,后续的位置量化才是真麻烦。 开 MT5 把六个文件逐一挂上 EURUSD 的 M15,先观察两周再谈改动参数,比直接信任何现成结论都稳妥。