English Deutsch 日本語
preview
价格行为分析工具包开发(第 24 部分):价格行为量化分析工具

价格行为分析工具包开发(第 24 部分):价格行为量化分析工具

MetaTrader 5交易系统 |
25 0
Christian Benjamin
Christian Benjamin

内容



引言

大多数价格行为交易者依赖于特定的K线形态,例如长影线十字星吞没形态光头光脚K线。这些K线用于识别市场情绪的转变,并发现潜在的反转或延续走势。手动在数十个图表中搜寻这些信号既耗时又容易遗漏。

我们开发了用于MetaTrader 5的价格行为量化分析EA,以应对这一挑战。这款 EA:

  1. 自动扫描最近的K线,K线数量可配置,搜寻四种被广泛认可的K线形态。
  2. 在图表上用箭头和标签标记每个检测到的形态,形成清晰的视觉提示。
  3. 发出警报并记录下一根K线的点数波动,帮助您评估信号强度。
  4. 通过将每个形态视为一笔“交易”并计算总体胜率,提供内置的回测统计功能。

在接下来的部分中,我们将深入探讨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. 十字星

逻辑步骤

  1. 计算 candleBody, fullRange, topShadow, bottomShadow。
  2. 要求 candleBody ≤ maxDojiRatio * fullRange。
  3. 要求 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
  • openPriceprevClose
  • closePriceprevOpen

看跌吞没:

  • 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

您应当知道的 MQL5 向导技术(第 58 部分):配以移动平均和随机振荡器形态的强化学习(DDPG) 您应当知道的 MQL5 向导技术(第 58 部分):配以移动平均和随机振荡器形态的强化学习(DDPG)
移动平均线和随机振荡器是十分常用的指标,我们在前一篇文章中探讨了它们的共通形态,并通过监督学习网络,见识了哪些“形态能粘附”。我们自该文加以分析,进一步研究当使用该已训练网络时,强化学习的效能。读者应当注意,我们的测试时间窗口非常有限。无论如何,我们在展示这一点时,会继续追求由 MQL5 向导提供最低编码需求。
MQL5经济日历交易指南(第九部分):通过动态滚动条与界面优化提升新闻交互体验 MQL5经济日历交易指南(第九部分):通过动态滚动条与界面优化提升新闻交互体验
本文中,我们为MQL5经济日历添加了动态滚动条功能,使用户直观快速浏览新闻事件。确保事件展示界面无卡顿且数据更新高效。并通过测试验证滚动条的响应性与仪表盘的美观度。
市场模拟(第九部分):套接字(三) 市场模拟(第九部分):套接字(三)
今天的文章是上一篇文章的延续。我们将研究 EA 交易的实现,主要关注服务器代码的执行方式。上一篇文章中给出的代码不足以使一切按预期工作,因此我们需要更深入地挖掘它。因此,有必要阅读这两篇文章,以便更好地了解会发生什么。
价格行为分析工具包开发(第 23 部分):货币强弱指标 价格行为分析工具包开发(第 23 部分):货币强弱指标
你知道真正推动货币对走势的是什么吗?正是每种单一货币的强弱。在本文中,我们将通过遍历包含该货币的所有货币对,来衡量其强弱。这使我们能够根据它们的相对强弱来预测这些货币对可能的走势。请继续阅读以了解更多详情。