价格行为分析工具包开发(第 24 部分):价格行为量化分析工具
内容
引言
大多数价格行为交易者依赖于特定的K线形态,例如长影线、十字星、吞没形态和光头光脚K线。这些K线用于识别市场情绪的转变,并发现潜在的反转或延续走势。手动在数十个图表中搜寻这些信号既耗时又容易遗漏。
我们开发了用于MetaTrader 5的价格行为量化分析EA,以应对这一挑战。这款 EA:
- 自动扫描最近的K线,K线数量可配置,搜寻四种被广泛认可的K线形态。
- 在图表上用箭头和标签标记每个检测到的形态,形成清晰的视觉提示。
- 发出警报并记录下一根K线的点数波动,帮助您评估信号强度。
- 通过将每个形态视为一笔“交易”并计算总体胜率,提供内置的回测统计功能。
在接下来的部分中,我们将深入探讨EA的结构,逐步介绍它的自定义设置功能,并展示其性能指标如何能提升您基于价格行为的交易方法。让我们首先从探索该EA监控的具体K线形态开始,分析每根K线的结构及其定位的计算方法。
K线形态
- 长影线
针形K线是一种实体很小、影线很长的单根K线。当您看到它时,意味着价格试图朝一个方向大幅移动,但又被推了回来。
在看跌长影线中,长长的上影线表明买家未能守住价格,卖家接管了市场。

图 1. 看跌长影线
看涨长影线具有长长的下影线,这表明买家介入并扭转了局势,推高了价格。

图 2. 看涨长影线
K线的颜色也会体现信号的权重。在看跌长影线中,红色(或黑色)实体更具说服力,因为其收盘价低于开盘价,显示了卖家的主导地位。对于看涨长影线,绿色(或白色)实体通过收盘价高于开盘价来加强信号,反映了买盘压力。然而,长影线的形状和影线长度远比颜色本身更重要。要确认该信号,请寻找长度至少是实体两三倍的影线,注意期间是否有成交量激增,并检查长影线是否出现在已知的支撑或阻力位附近。这些额外步骤有助于您挑选真正的反转形态,而非普通的影线。
逻辑步骤
- 计算 candleBody, topShadow, bottomShadow。
- 要求 candleBody > minBodyPoints * _Point。
看跌长影线:
topShadow >= wickToBodyRatio * candleBody
bottomShadow < smallWickCap * candleBody
看涨长影线:
bottomShadow >= wickToBodyRatio * candleBody
topShadow < smallWickCap * candleBody
// 1. Calculate parts double candleBody = MathAbs(closePrice - openPrice); double topShadow = highPrice - MathMax(openPrice, closePrice); double bottomShadow = MathMin(openPrice, closePrice) - lowPrice; // 2. Minimum body check if(candleBody > minBodyPoints * _Point) { // Bearish pin bar if(topShadow >= wickToBodyRatio * candleBody && bottomShadow < smallWickCap * candleBody) Print("Bearish Pin Bar detected"); // Bullish pin bar else if(bottomShadow >= wickToBodyRatio * candleBody && topShadow < smallWickCap * candleBody) Print("Bullish Pin Bar detected"); }
- 十字星
当一根K线的开盘价和收盘价几乎完全一致时,就会形成十字星(Doji)。它标志着市场处于犹豫不决的状态,其偏向取决于之前的趋势。上下影线长度的不同变化,构成了类似加号、十字或倒十字的形态。

图 3. 十字星
逻辑步骤
- 计算 candleBody, fullRange, topShadow, bottomShadow。
- 要求 candleBody ≤ maxDojiRatio * fullRange。
- 要求 opShadow > candleBody 及 bottomShadow > candleBody。
// 1. Calculate body and range double candleBody = MathAbs(closePrice - openPrice); double fullRange = highPrice - lowPrice; double topShadow = highPrice - MathMax(openPrice, closePrice); double bottomShadow = MathMin(openPrice, closePrice) - lowPrice; // 2. Tiny body test if(candleBody <= fullRange * maxDojiRatio) { // 3. Both shadows must extend beyond the body if(topShadow > candleBody && bottomShadow > candleBody) Print("Doji detected"); }
- 吞没形态K线
有两种吞没形态K线:看涨吞没和看跌吞没。
看涨吞没
这种双K线反转形态出现在下跌趋势或盘整结束时。一根较小的看跌K线之后,紧接着出现一根较大的看涨K线,该K线完全覆盖了前一根K线的实体。第二根K线的尺寸表明买家已压倒卖家,通常标志着强劲上涨行情的开始。

图 4. 看涨吞没
看跌吞没
这是与看涨吞没相反的形态。一根较小的看涨K线之后,紧接着出现一根较大的看跌K线,该K线完全吞没了前一根K线的实体。该形态表明卖方已掌控局面,可能预示着强劲下跌行情的开始。

图 5. 看跌吞没
逻辑步骤
计算 prevBody = |prevClose – prevOpen|, currBody = |close – open|。
要求 currBody > prevBody。
看涨吞没:
- prevClose < prevOpen
- openPrice ≤ prevClose
- closePrice ≥ prevOpen
看跌吞没:
- prevClose > prevOpen
- openPrice ≥ prevClose
- closePrice ≤ prevOpen
// 1. Compute body sizes double prevBody = MathAbs(prevClose - prevOpen); double currBody = MathAbs(closePrice - openPrice); // 2. Must be larger than previous if(currBody > prevBody) { // Bullish engulfing if(prevClose < prevOpen && openPrice <= prevClose && closePrice >= prevOpen) Print("Bullish Engulfing detected"); // Bearish engulfing else if(prevClose > prevOpen && openPrice >= prevClose && closePrice <= prevOpen) Print("Bearish Engulfing detected"); }
- 光头光脚K线

图 6. 光头光脚K线
光头光脚K线以其长实体和几乎没有影线而著称。其开盘价和收盘价几乎涵盖了整个波动区间,标志着市场走势果断明确。光头光脚K线有三种变体,每种都包括看涨和看跌版本:
全光头光脚
看涨:开盘于最低价,收盘于最高价。买方从头到尾推动价格。
看跌: 开盘于最高价,收盘于最低价。卖方在整个交易时段占据主导。
开盘光头光脚
看涨:开盘于最低价,收盘价略低于最高价(有一根小上影线)。买方立即掌控局面。
看跌:开盘于最高价,收盘价略高于最低价(有一根小下影线)。卖方从一开始就主导着交易时段。
收盘光头光脚
看涨:收盘于最高价,开盘价略高于最低价(有一根小下影线)。买盘压力持续到收盘。
看跌:收盘于最低价,开盘价略低于最高价(有一根小上影线)。卖盘压力在收盘时加速。
逻辑步骤
- 计算 candleBody, fullRange, topShadow, bottomShadow。
- 要求:candleBody ≥ marubozuRatio * fullRange。
- 要求 opShadow ≤ (1 – marubozuRatio) * fullRange 及 bottomShadow ≤ (1 – marubozuRatio) * fullRange
- 如果 closePrice > openPrice 作为看涨形态,否则为看跌形态。
// 1. Calculate parts double candleBody = MathAbs(closePrice - openPrice); double fullRange = highPrice - lowPrice; double topShadow = highPrice - MathMax(openPrice, closePrice); double bottomShadow = MathMin(openPrice, closePrice) - lowPrice; // 2. Body covers most of the range if(candleBody >= marubozuRatio * fullRange) { // 3. Shadows must be small double maxWick = (1 - marubozuRatio) * fullRange; if(topShadow <= maxWick && bottomShadow <= maxWick) { // 4. Bullish or bearish if(closePrice > openPrice) Print("Bullish Marubozu detected"); else Print("Bearish Marubozu detected"); } }
MQL5 EA 解析
上图是EA在 MetaTrader 5 图表上运行后的示意图。下面,我们将结果制成表格——每个值代表一个百分比变化。当我们着手开发这款EA时,主要目标是自动化检测交易者常用于决策的关键K线形态,例如 长影线、十字星、吞没形态和 光头光脚K线。我们希望EA能客观地分析最近的价格行为,准确识别这些形态,并在图表上提供清晰的视觉提示,同时反馈有关形态有效性的统计数据。
为了实现这一点,我们首先定义了允许灵活分析的输入参数。这些参数包括回溯的K线数量 (InpLookbackBars)、用于过滤微不足道K线最小实体大小的点数 (InpMinBodySizePts) ,以及用于检测 Pin Bar 的影线与实体比率 (InpWickBodyRatio)。我们还包含了一个ATR周期参数来衡量市场波动性,因为这可能会影响形态识别规则。
// Input parameters for customization input int InpLookbackBars = 200; // Bars to scan input int InpMinBodySizePts = 10; // Min body size (points) input double InpWickBodyRatio = 2.0; // Min wick-to-body ratio input int InpATRPeriod = 14; // ATR period
在初始化阶段(OnInit)中,我们设置了数组来存储每根K线的计算数据,例如实体大小、上下影线、总波动区间以及ATR数值。我们确保这些数组是基于时间序列的,以便能高效处理最近的K线。此外,我们还准备了一个小型缓冲区来跟踪最近的信号,这有助于提升后续形态分析的成功率。
int OnInit() { ArraySetAsSeries(Body,true); ArraySetAsSeries(UpperWick,true); ArraySetAsSeries(LowerWick,true); ArraySetAsSeries(TotalRange,true); ArraySetAsSeries(ATR,true); ArrayResize(Body, InpLookbackBars+2); ArrayResize(UpperWick, InpLookbackBars+2); ArrayResize(LowerWick, InpLookbackBars+2); ArrayResize(TotalRange, InpLookbackBars+2); ArrayResize(ATR, InpLookbackBars+2); for(int i=0;i<5;i++) g_history[i]=""; return(INIT_SUCCEEDED); }核心逻辑位于 OnTick 函数中,该函数在每一个新的市场行情跳动时运行。为了防止不必要的计算,我们添加了一个时间戳对比检查处理程序,确保每根新K线只运行一次。当检测到新K线时,我们会调用 AnalyzeAndDraw,由它执行主要的分析工作。
void OnTick() { static datetime lastTime=0; datetime current = iTime(_Symbol, _Period, 0); if(current == lastTime) return; // Only process once per new bar lastTime = current; AnalyzeAndDraw(); }
在 AnalyzeAndDraw 函数中,我们首先清除之前的绘图对象,以保持图表整洁。然后,我们遍历最近的K线来计算关键的K线指标:实体大小(开盘价与收盘价的绝对差值)、上影线(最高价减去开盘价和收盘价中的较大值)、下影线(开盘价和收盘价中的较小值减去最低价)以及总波动区间(最高价减去最低价)。此外,我们还复制ATR(平均真实波幅)数值,以便将波动性因素纳入形态检测中。
void AnalyzeAndDraw() { int bars = MathMin(InpLookbackBars, (int)SeriesInfoInteger(_Symbol,_Period,SERIES_BARS_COUNT)); ObjectsDeleteAll(0,0,OBJ_ARROW); ObjectsDeleteAll(0,0,OBJ_LABEL); for(int i=0; i<bars; i++) { double op = iOpen(_Symbol,_Period,i); double cl = iClose(_Symbol,_Period,i); double hi = iHigh(_Symbol,_Period,i); double lo = iLow(_Symbol,_Period,i); // Calculate candlestick components Body[i] = MathAbs(cl-op); UpperWick[i] = hi - MathMax(op,cl); LowerWick[i] = MathMin(op,cl) - lo; TotalRange[i] = hi - lo; } // Copy ATR buffer if(CopyBuffer(iATR(_Symbol,_Period,InpATRPeriod),0,0,bars,ATR)<=0) return; // Exit if ATR data not available
接下来,我们应用形态识别规则。例如,要识别长影线,我们会检查K线是否具有小实体和长影线,且影线与实体的比例超过我们的设定阈值。
- 看跌长影线:长上影线 >= 比例 × 实体,短下影线
- 看涨长影线:长下影线 >= 比例 × 实体,短上影线
首先,我们过滤掉过小的实体(Body > minPts)。然后,我们强制要求一条影线至少是实体的 InpWickBodyRatio 倍,而另一条影线保持在实体大小的 50% 以下。
// assume Body[i], UpperWick[i], LowerWick[i] already computed if(InpShowPinBar && Body[i] > InpMinBodySizePts*_Point) { // Bearish: towering upper wick, stubby lower wick if( UpperWick[i] > Body[i]*InpWickBodyRatio && LowerWick[i] < Body[i]*0.5 ) type = "Bearish Pin Bar"; // Bullish: towering lower wick, stubby upper wick else if( LowerWick[i] > Body[i]*InpWickBodyRatio && UpperWick[i] < Body[i]*0.5 ) type = "Bullish Pin Bar"; }
对于 十字星,我们寻找相对于基于点的阈值实体极小、且影线表明潜在犹豫不决的K线。
- 实体(Body) <= DojiBodyRatio × totalRange
- 两条影线都 > 实体(确认存在影线)
我们将实体上限设为总波动的 10%(即 InpDojiBodyRatio)。要求每条影线都超过实体,可以过滤掉几乎没有影线的“纺锤线”。
// TotalRange[i] = high – low if(InpShowDoji && Body[i] <= TotalRange[i] * InpDojiBodyRatio // body tiny vs full range && UpperWick[i] > Body[i] // upper shadow present && LowerWick[i] > Body[i]) // lower shadow present type = "Doji";
吞没形态涉及将当前K线与前一根K线进行比较,检查前一根K线的开盘价和收盘价是否处于相反方向,以及当前K线是否完全吞没了前一根K线。
- 看涨吞没:前一根K线为看跌,当前开盘价 ≤ 前一根收盘价,当前收盘价 ≥ 前一根开盘价,且 currBody > prevBody。
- 看跌吞没:前一根K线为看涨,当前开盘价 ≥ 前一根收盘价,当前收盘价 ≤ 前一根开盘价,且 currBody > prevBody。
double po = iOpen(_Symbol,_Period,i+1), pc = iClose(_Symbol,_Period,i+1); double prevBody = MathAbs(pc - po), currBody = Body[i]; if(InpShowEngulfing && currBody > prevBody) { // Bullish: current body engulfs prior’s if(pc < po && op <= pc && cl >= po) type = "Bullish Engulfing"; // Bearish: current body engulfs prior’s else if(pc > po && op >= pc && cl <= po) type = "Bearish Engulfing"; }
对于光头光脚K线,我们会检查实体是否占据了绝大部分波动区间,这表明动能强劲。
- 实体(Body) >= MarubozuBodyRatio × totalRange(例如 >= 90%)
- 两条影线均<= (1 – MarubozuBodyRatio) × totalRange
if(InpShowMarubozu
&& Body[i] >= TotalRange[i] * InpMarubozuBodyRatio
&& UpperWick[i] <= TotalRange[i] * (1 - InpMarubozuBodyRatio)
&& LowerWick[i] <= TotalRange[i] * (1 - InpMarubozuBodyRatio))
{
type = (cl > op) ? "Bullish Marubozu" : "Bearish Marubozu";
}
每当发现一个形态,我们就会向计数器中增加总信号数和获胜次数。我们根据下一根K线是否按预期方向移动来定义“胜”,以此来衡量形态的可靠性。
if(type!="") { lastIdx = i; lastCl = cl; lastIsBuy = (StringFind(type,"Bullish")>=0); latestSignal = type; g_totalSignals++; double nextC = iClose(_Symbol,_Period,i-1); if(lastIsBuy && nextC>cl) g_totalWins++; if(!lastIsBuy && nextC<cl) g_totalWins++; DrawPattern(i, type, lastIsBuy); break; }
为了直观地展示这些信号,我们使用 DrawPattern 函数在图表上绘制向上或向下的箭头,并标注形态类型。此外,还会在形态出现时立即生成警报并通知我们。
void DrawPattern(int idx, const string type, bool isBuy) { datetime t = iTime(_Symbol,_Period,idx); double y = iHigh(_Symbol,_Period,idx) + 15*_Point; string an = StringFormat("PAQ_%s_%d",type,idx); ObjectCreate(0,an,OBJ_ARROW,0,t,y); ObjectSetInteger(0,an,OBJPROP_ARROWCODE,isBuy?233:234); ObjectSetInteger(0,an,OBJPROP_COLOR,isBuy?clrLime:clrRed); string lbl = an+"_lbl"; ObjectCreate(0,lbl,OBJ_LABEL,0,t,y-25*_Point); ObjectSetString(0,lbl,OBJPROP_TEXT,type); ObjectSetInteger(0,lbl,OBJPROP_COLOR,isBuy?clrLime:clrRed); }在整个开发过程中,我们致力于让EA既灵活又具备丰富的信息量。因此,我们加入了一个形态历史缓冲区来保存最近的信号,并在回测结束或移除EA时,输出总信号数、获胜次数和胜率等性能统计数据。这有助于我们评估形态识别逻辑随时间推移的有效性。
void OnDeinit(const int reason) { double rate = g_totalSignals>0 ? 100.0*g_totalWins/g_totalSignals : 0.0; PrintFormat("[PAQ] Backtest completed: Signals=%I64d Wins=%I64d WinRate=%.1f%%", g_totalSignals, g_totalWins, rate); }
总之,这款EA集成了K线形态识别逻辑、视觉指标以及性能追踪功能。我们的目标是打造一个自动化系统,既能简化耗时的形态识别工作,又能提供清晰的视觉信号和性能统计,从而支持更明智的交易决策。
结果
让我们来看看EA在实时行情和回测中的表现。首先,我们观察下图中的形态,这是EA在实时市场中检测到的看跌吞没形态。我们可以清楚地看到,这是一个真正的看跌吞没形态,因为那根阴线完全包裹了前一根阳线。
图 7. 看跌吞没
接着,我们成功检测到一根带看跌影线的K线。这是一个有效的带看跌影线的K线,证明了该工具在识别K线形态方面的准确性。

图 8. 看跌长影线
最后,我们得到了回测结果。EA 正在正确识别形态,并将每个检测到的形态名称记录到日志中。

图 9. 回测
结论
从前文概述的结果来看,我们的EA显然能够可靠地识别这四种关键K线形态。这一成果将帮助新手和经验丰富的交易员发现肉眼难以捕捉的形态。在我进行的回测和实盘试验中,EA都准确地标记出了每一种形态。没有任何系统能做到百分百完美,有时信号也会失效,不过本EA并不追求过滤掉所有的假信号。相反,它提供了一个额外的、精准的价格行为分析工具。交易者随后可以在决定做多或做空之前,结合采用自己的信号确认技术。
总体而言,EA在其核心任务——模式识别方面表现出色。我强烈推荐它,因为它能精准发现它所针对的四种形态。欢迎大家根据自身策略调整输入参数。如果您认为有任何方面可以进一步改进,欢迎随时反馈。
| 日期 | 工具名称 | 说明 | 版本 | 更新 | 提示 |
|---|---|---|---|---|---|
| 01/10/24 | 图表投影仪 | 用于叠加前一天价格走势(带“幽灵”效果)的脚本。 | 1.0 | 首次发布 | 工具1 |
| 18/11/24 | 分析评论 | 它以表格形式提供前一日的市场信息,并预测市场的未来走向。 | 1.0 | 首次发布 | 工具2 |
| 27/11/24 | 分析大师 | 市场指标每两小时定期更新 | 1.01 | 第二版 | 工具3 |
| 02/12/24 | 分析预测器 | 每两小时定期更新市场指标,并集成Telegram推送功能。 | 1.1 | 第三版 | 工具4 |
| 09/12/24 | 波动性导航工具 | 该EA使用布林带、RSI和ATR指标分析市场状况。 | 1.0 | 首次发布 | 工具5 |
| 19/12/24 | 均值回归信号收割器 | 使用均值回归策略分析市场并提供信号 | 1.0 | 首次发布 | 工具6 |
| 9/01/25 | 信号脉冲 | 多时间框架分析器 | 1.0 | 首次发布 | 工具7 |
| 17/01/25 | 指标看板 | 带按钮的分析面板 | 1.0 | 首次发布 | 工具8 |
| 21/01/25 | 外部资金流 | 通过外部库进行分析 | 1.0 | 首次发布 | 工具9 |
| 27/01/25 | VWAP | 成交量加权平均价格 | 1.3 | 首次发布 | 工具10 |
| 02/02/25 | Heikin Ashi | 势平滑与反转信号识别 | 1.0 | 首次发布 | 工具11 |
| 04/02/25 | FibVWAP | 通过 Python 分析生成信号 | 1.0 | 首次发布 | 工具12 |
| 14/02/25 | RSI 背离 | 价格走势与 RSI 背离的对比 | 1.0 | 首次发布 | 工具13 |
| 17/02/25 | 抛物线转向与反转 (PSAR) | 自动化PSAR策略 | 1.0 | 首次发布 | 工具14 |
| 20/02/25 | 四分位绘制脚本 | 在图表上绘制四分位水平线 | 1.0 | 首次发布 | 工具15 |
| 27/02/25 | 侵入检测器 | 当价格触及四分位水平时进行检测和警报 | 1.0 | 首次发布 | 工具16 |
| 27/02/25 | TrendLoom工具 | 多时间周期分析面板 | 1.0 | 首次发布 | 工具17 |
| 11/03/25 | 四分位看板 | 带有可激活或禁用四分位的面板 | 1.0 | 首次发布 | 工具18 |
| 26/03/25 | ZigZag 分析器 | 使用ZigZag指标绘制趋势线 | 1.0 | 首次发布 | 工具19 |
| 10/04/25 | 相关性检测器 | 使用Python库绘制货币对的相关性。 | 1.0 | 首次发布 | 工具20 |
| 23/04/25 | 市场结构反转检测工具 | 市场结构反转检测 | 1.0 | 首次发布 | 工具21 |
| 08/05/25 | 相关性仪表盘 | 不同货币对之间的相关性 | 1.0 | 首次发布 | 工具22 |
| 13/05/25 | 货币强弱指标 | 衡量货币对中每种货币的强弱 | 1.0 | 首次发布 | 工具23 |
| 21/05/25 | PAQ 分析工具 | K线形态检测器 | 1.0 | 首次发布 | 工具24 |
本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/18207
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
本文由网站的一位用户撰写,反映了他们的个人观点。MetaQuotes Ltd 不对所提供信息的准确性负责,也不对因使用所述解决方案、策略或建议而产生的任何后果负责。
您应当知道的 MQL5 向导技术(第 58 部分):配以移动平均和随机振荡器形态的强化学习(DDPG)
MQL5经济日历交易指南(第九部分):通过动态滚动条与界面优化提升新闻交互体验
市场模拟(第九部分):套接字(三)
价格行为分析工具包开发(第 23 部分):货币强弱指标