我花了大半个周末盯着EURUSD的H4图表,一页一页地翻了几百根K线去找看涨吞没形态。眼睛都快看花了,还总在怀疑自己是不是漏掉了哪个。后来一想,与其费这个劲,不如让代码来干这活儿。
MQL5官方文档(docs.mql5.com)里有时序索引相关的章节,但并不会告诉你怎样才能搭一个真正能过滤噪音的检测系统。下面就是我最后在MetaEditor里折腾出来的东西,以及过程中踩到的几个坑。
最基础的逻辑
看涨吞没形态理论上很简单:一根阴线后面跟一根更大的阳线,阳线实体完全包住前面那根阴线的实体。写成代码就是:
``
cpp
// 检测看涨吞没形态
if( Close[2] < Open[2] && // 索引2的K线是阴线
Close[1] > Open[1] && // 索引1的K线是阳线
Open[1] < Close[2] && // 索引1的开盘价低于索引2的收盘价
Close[1] > Open[2] ) // 索引1的收盘价高于索引2的开盘价
{
// 形态成立
}
`
这样写没错,但太粗糙了。在实际跑的时候,盘整行情里各种信号满天飞,全是假突破。上面这个代码只关心条件是否成立,完全不管这根吞没阳线本身到底有没有意义。
ATR这个关键思路
实践里我碰到的问题是这样的:在H4或日线这种大周期上,如果吞没形态出现在区间中部,形态本身再标准也多半是陷阱。但官方文档里可不会告诉你该怎么过滤这个。
我最后的解决方案是用平均真实波幅(ATR)设一个动态门槛。不光是看吞没阳线实体比前一根大,而是要看它大到什么程度:
`cpp
double atrValue = iATR(_Symbol, _Period, 14, 1);
double minBodySize = atrValue 0.4; // 至少达到ATR的40%
bool isEngulfing = (prevBearish && currBullish &&
currOpen < prevClose && currClose > prevOpen &&
MathAbs(currClose - currOpen) > minBodySize);
`
就加了这一行判断,回测里的假信号直接少了六成。逻辑很简单——如果这根吞没阳线的幅度本身就不够大,说明最近波动就不强,那它大概率不值得你出手。
搭一个简易回测框架
检测器写好了之后,真正有价值的事情是搭一个回测框架,去算这个信号到底有没有用。我想知道的是:如果在吞没形态收盘时进场,止损设在形态最低点下方,止盈设在1.5倍盈亏比的位置,实际胜率能有多少?
骨架大概长这样:
`cpp
// 在OnTick()或OnCalculate()里
if(IsBullishEngulfing(1)) {
double entry = Close[1];
double stopLoss = Low[1] - 10 _Point; // 比形态低点稍低一点
double takeProfit = entry + (entry - stopLoss) 1.5;
// 记录这笔单子最后是触发了止盈还是止损
}
`
跑下来的结果让我有点意外。2023到2025年EURUSD H4的数据上,纯看涨吞没形态本身的胜率大概只有52%——跟抛硬币差不多。但当我加了两个过滤条件之后——上面那个ATR过滤,再加上要求形态出现在最近一段下跌后的低点附近——胜率直接跳到了68%。
MQL5社区文章里也提到,这种多条件叠加的过滤方式,才是专业级指标和入门脚本之间的分水岭。官方文档给的是工具,但工具的排列组合方式才是真正值钱的地方。
另一个容易踩的坑
还有一个问题是我跑实时数据的时候发现的:因为MT5处理K线索引的方式,同一个形态可能会被重复触发好几次。解决方法很简单,加个冷却标记:
`cpp
static datetime lastSignalTime = 0;
if(TimeCurrent() - lastSignalTime < PeriodSeconds(PERIOD_CURRENT) 2)
return; // 避免重复信号
``这种细节在MetaQuotes任何官方材料里都找不到,但只要你是做交易提醒功能的,就必须得加上。
参考来源:MetaQuotes MQL5文档(docs.mql5.com)关于时序索引及内置指标函数;MQL5社区文章K线形态编程相关章节。
本文首发于FXEAR.com,原创内容,未经授权禁止转载。