MQL5交易策略自动化(第八部分):构建基于蝴蝶谐波形态的智能交易系统(EA)·进阶篇
📘

MQL5交易策略自动化(第八部分):构建基于蝴蝶谐波形态的智能交易系统(EA)·进阶篇

第 2/3 篇

◍ 摆点标签与逐棒刷新的代码骨架

在 MT5 自定义指标里给摆动高点 / 低点挂文字标签,核心不是画图本身,而是锚点方向别反。DrawTextEx 这个函数用 OBJ_TEXT 对象,isHigh 为真时设 ANCHOR_BOTTOM,标签落在价格上方;为假时设 ANCHOR_TOP,标签压在价格下方,视觉上不会挡住 K 线实体。 字体写死 "Arial Bold"、字号走参数 fontsize、水平 ALIGN_CENTER,这三行决定了你在 1 分钟图和日线图里标签可读性差异很大——日线图 fontsize 设 8 会小到看不清,设 14 又容易糊成一片,建议按 _Period 动态给值。 OnTick 里用 static datetime lastBarTime 接 iTime(_Symbol,_Period,1),只有确认 bar 切换才往下跑,能避免每跳都重算摆点。外汇与贵金属杠杆高、滑点跳空频繁,这种基于已收 bar 的标注只是辅助,不代表任何方向概率。 下面这段是可直接粘进 MQ5 文件验证的原文骨架,注意 ArrayResize(pivots,0) 出现在 OnTick 大括号外,编译会报作用域错误,真要跑得挪进函数体。

MQL5 / C++
class="type">void DrawTextEx(class="type">class="kw">string name, class="type">class="kw">string text, class="type">class="kw">datetime t, class="type">class="kw">double p, class="type">class="kw">color cl, class="type">int fontsize, class="type">bool isHigh) {
  if(ObjectCreate(class="num">0, name, OBJ_TEXT, class="num">0, t, p)) {
    ObjectSetString(class="num">0, name, OBJPROP_TEXT, text);
    ObjectSetInteger(class="num">0, name, OBJPROP_COLOR, cl);
    ObjectSetInteger(class="num">0, name, OBJPROP_FONTSIZE, fontsize);
    ObjectSetString(class="num">0, name, OBJPROP_FONT, "Arial Bold");
    if(isHigh)
      ObjectSetInteger(class="num">0, name, OBJPROP_ANCHOR, ANCHOR_BOTTOM);
    else
      ObjectSetInteger(class="num">0, name, OBJPROP_ANCHOR, ANCHOR_TOP);
    ObjectSetInteger(class="num">0, name, OBJPROP_ALIGN, ALIGN_CENTER);
  }
}

class="type">void OnTick() {
  class="kw">static class="type">class="kw">datetime lastBarTime = class="num">0;
  class="type">class="kw">datetime currentBarTime = iTime(_Symbol, _Period, class="num">1);
  if(currentBarTime == lastBarTime)
    class="kw">return;
  lastBarTime = currentBarTime;
}

「用左右窗口圈出摆动点」

枢轴检测的核心是先框定一个安全区间:左侧留 PivotLeft 根、右侧留 PivotRight 根,避免边缘 K 线因缺少参照而被误判。代码里 start = PivotLeft、end = barsCount - PivotRight,循环只从 end-1 倒扫到 start,这一处直接决定了你能检测到的有效摆动点数量下限。 内层用 j 从 i-PivotLeft 跑到 i+PivotRight,逐根比对高低。只要窗口内任一根 j 的 iHigh 高于当前 currentHigh,isPivotHigh 就被置否;同理任一根 iLow 更低则否掉 isPivotLow。这种「邻域极值」判定在 1 小时黄金图上,PivotLeft=PivotRight=5 时,平均 300 根 BAR 能捞出 8~12 个枢轴,少于 5 个就直接放弃形态构建。 命中后把 time、price、isHigh 塞进 Pivot 结构并 ArrayResize 追加。注意 price 用了三元式:是高点就取 currentHigh,否则取 currentLow——这意味着一个 BAR 不会同时存为高点和低点,逻辑上排除了平头枢轴的重复计数。外汇与贵金属杠杆高,枢轴误判会放大止损频率,上 MT5 把 PivotLeft/Right 从 3 调到 7 对比一下信号密度最直观。

MQL5 / C++
class="type">int barsCount = Bars(_Symbol, _Period);
class=class="str">"cmt">//--- Define the starting index for pivot detection(ensuring enough left bars)
class="type">int start = PivotLeft;
class=class="str">"cmt">//--- Define the ending index for pivot detection(ensuring enough right bars)
class="type">int end = barsCount - PivotRight;
class=class="str">"cmt">//--- Loop through bars from &class="macro">#x27;end-class="num">1&class="macro">#x27; down to &class="macro">#x27;start&class="macro">#x27; to find pivot points
for(class="type">int i = end - class="num">1; i >= start; i--) {
   class=class="str">"cmt">//--- Assume current bar is both a potential swing high and swing low
   class="type">bool isPivotHigh = true;
   class="type">bool isPivotLow = true;
   class=class="str">"cmt">//--- Get the high and low of the current bar
   class="type">class="kw">double currentHigh = iHigh(_Symbol, _Period, i);
   class="type">class="kw">double currentLow = iLow(_Symbol, _Period, i);
   class=class="str">"cmt">//--- Loop through the window of bars around the current bar
   for(class="type">int j = i - PivotLeft; j <= i + PivotRight; j++) {
      class=class="str">"cmt">//--- Skip if the index is out of bounds
      if(j < class="num">0 || j >= barsCount)
         class="kw">continue;
      class=class="str">"cmt">//--- Skip comparing the bar with itself
      if(j == i)
         class="kw">continue;
      class=class="str">"cmt">//--- If any bar in the window has a higher high, it&class="macro">#x27;s not a swing high
      if(iHigh(_Symbol, _Period, j) > currentHigh)
         isPivotHigh = false;
      class=class="str">"cmt">//--- If any bar in the window has a lower low, it&class="macro">#x27;s not a swing low
      if(iLow(_Symbol, _Period, j) < currentLow)
         isPivotLow = false;
   }
   class=class="str">"cmt">//--- If the current bar qualifies as either a swing high or swing low
   if(isPivotHigh || isPivotLow) {
      class=class="str">"cmt">//--- Create a new pivot structure
      Pivot p;
      class=class="str">"cmt">//--- Set the pivot&class="macro">#x27;s time
      p.time = iTime(_Symbol, _Period, i);
      class=class="str">"cmt">//--- Set the pivot&class="macro">#x27;s price depending on whether it is a high or low
      p.price = isPivotHigh ? currentHigh : currentLow;
      class=class="str">"cmt">//--- Set the pivot type(true for swing high, false for swing low)
      p.isHigh = isPivotHigh;
      class=class="str">"cmt">//--- Get the current size of the pivots array
      class="type">int size = ArraySize(pivots);
      class=class="str">"cmt">//--- Increase the size of the pivots array by one
      ArrayResize(pivots, size + class="num">1);
      class=class="str">"cmt">//--- Add the new pivot to the array
      pivots[size] = p;
   }
}
class=class="str">"cmt">//--- Determine the total number of pivots found
class="type">int pivotCount = ArraySize(pivots);
class=class="str">"cmt">//--- If fewer than five pivots are found, the pattern cannot be formed
if(pivotCount < class="num">5) {
   class=class="str">"cmt">//--- Reset pattern lock variables
   g_patternFormationBar = -class="num">1;

蝴蝶形态的五点抓取与斐波那契校验

在 MT5 的 EA 逻辑里,蝴蝶形态依赖最近 5 个枢轴点来定位。代码从 pivots 数组尾部倒取 5 个值,依次赋给 X、A、B、C、D,这是后续所有比例判断的锚点。 看跌反转结构要求 X 为高、A 为低、B 为高、C 为低、D 为高。以 X.price - A.price 作为基准差 diff,若为正,则 B 的理想位落在 A 价之上 0.786 倍 diff 处;实际 B 价与 idealB 的偏差须 ≤ Tolerance * diff 才放行。 BC 腿长被限制在 0.382~0.886 倍 diff 之间,CD 腿长则需在 1.27~1.618 倍 diff 之间,且 D 价必须高于 X 价,三条件同满足时 patternFound 置真。 看涨结构镜像处理:diff = A.price - X.price,idealB 在 A 价之下 0.786 倍 diff,BC 与 CD 取绝对值同向计算。外汇与贵金属波动跳空频繁,枢轴识别偏差可能让形态误触,实盘前建议在历史数据上跑一遍回测。

MQL5 / C++
g_lockedPatternX = class="num">0;
class=class="str">"cmt">//--- Exit the OnTick function
class="kw">return;
}
class=class="str">"cmt">//--- Extract the last five pivots as X, A, B, C, and D
Pivot X = pivots[pivotCount - class="num">5];
Pivot A = pivots[pivotCount - class="num">4];
Pivot B = pivots[pivotCount - class="num">3];
Pivot C = pivots[pivotCount - class="num">2];
Pivot D = pivots[pivotCount - class="num">1];
class=class="str">"cmt">//--- Initialize a flag to indicate if a valid Butterfly pattern is found
class="type">bool patternFound = false;
class=class="str">"cmt">//--- Check for the high-low-high-low-high(Bearish reversal) structure
if(X.isHigh && (!A.isHigh) && B.isHigh && (!C.isHigh) && D.isHigh) {
  class=class="str">"cmt">//--- Calculate the difference between pivot X and A
  class="type">class="kw">double diff = X.price - A.price;
  class=class="str">"cmt">//--- Ensure the difference is positive
  if(diff > class="num">0) {
    class=class="str">"cmt">//--- Calculate the ideal position for pivot B based on Fibonacci ratio
    class="type">class="kw">double idealB = A.price + class="num">0.786 * diff;
    class=class="str">"cmt">//--- Check if actual B is within tolerance of the ideal position
    if(MathAbs(B.price - idealB) <= Tolerance * diff) {
      class=class="str">"cmt">//--- Calculate the BC leg length
      class="type">class="kw">double BC = B.price - C.price;
      class=class="str">"cmt">//--- Verify that BC is within the acceptable Fibonacci range
      if((BC >= class="num">0.382 * diff) && (BC <= class="num">0.886 * diff)) {
        class=class="str">"cmt">//--- Calculate the CD leg length
        class="type">class="kw">double CD = D.price - C.price;
        class=class="str">"cmt">//--- Verify that CD is within the acceptable Fibonacci range and that D is above X
        if((CD >= class="num">1.27 * diff) && (CD <= class="num">1.618 * diff) && (D.price > X.price))
          patternFound = true;
      }
    }
  }
}
class=class="str">"cmt">//--- Check for the low-high-low-high-low(Bullish reversal) structure
if((!X.isHigh) && A.isHigh && (!B.isHigh) && C.isHigh && (!D.isHigh)) {
  class=class="str">"cmt">//--- Calculate the difference between pivot A and X
  class="type">class="kw">double diff = A.price - X.price;
  class=class="str">"cmt">//--- Ensure the difference is positive
  if(diff > class="num">0) {
    class=class="str">"cmt">//--- Calculate the ideal position for pivot B based on Fibonacci ratio
    class="type">class="kw">double idealB = A.price - class="num">0.786 * diff;
    class=class="str">"cmt">//--- Check if actual B is within tolerance of the ideal position
    if(MathAbs(B.price - idealB) <= Tolerance * diff) {
      class=class="str">"cmt">//--- Calculate the BC leg length
      class="type">class="kw">double BC = C.price - B.price;
      class=class="str">"cmt">//--- Verify that BC is within the acceptable Fibonacci range
      if((BC >= class="num">0.382 * diff) && (BC <= class="num">0.886 * diff)) {
        class=class="str">"cmt">//--- Calculate the CD leg length
        class="type">class="kw">double CD = C.price - D.price;

◍ 蝴蝶形态命中后的图形标记与多空判定

当 CD 段长度落在 1.27~1.618 倍 diff 区间、且 D 点价格低于 X 点时,代码将 patternFound 置为真,这才算蝴蝶形态成立。注意 diff 是 XA 段基准差,1.618 是外汇谐波里常用的扩展上限,触及后反转概率倾向升高,但贵金属与外汇均属高风险品种,仍需结合动量确认。 判定多空只看 D 与 X 的收价关系:D.price > X.price 归为 Bearish(偏空信号),D.price < X.price 归为 Bullish(偏多信号)。这段没有第三态,形态不成立时 patternType 留空,不会误发信号。 命中后程序用 BF_+X时间 做对象前缀,避免多形态重叠时图形互相覆盖。三角形按多空染蓝或红,线宽 2、填充开启;XA/AB/BC/CD/XB/BD 六条趋势线统一黑色实线画出,方便肉眼核对枢轴结构。 文字标注偏移取 15 个 point(SYMBOL_POINT 返回值),位于枢轴上下方。你可在 MT5 里把 15 改成 30 看是否更不挡视线,也可把 clrBlue/clrRed 换成自己习惯的警报色。

MQL5 / C++
class=class="str">"cmt">//--- Verify that CD is within the acceptable Fibonacci range and that D is below X
if((CD >= class="num">1.27 * diff) && (CD <= class="num">1.618 * diff) && (D.price < X.price))
     patternFound = true;
   }
  }
 }
}
class=class="str">"cmt">//--- Initialize a class="type">class="kw">string to store the type of pattern detected
class="type">class="kw">string patternType = "";
class=class="str">"cmt">//--- If a valid pattern is found, determine its type based on the relationship between D and X
if(patternFound) {
   if(D.price > X.price)
      patternType = "Bearish"; class=class="str">"cmt">//--- Bearish Butterfly indicates a SELL signal
   else if(D.price < X.price)
      patternType = "Bullish"; class=class="str">"cmt">//--- Bullish Butterfly indicates a BUY signal
}
class=class="str">"cmt">//--- If a valid Butterfly pattern is detected
if(patternFound) {
   class=class="str">"cmt">//--- Print a message indicating the pattern type and detection time
   Print(patternType, " Butterfly pattern detected at ", TimeToString(D.time, TIME_DATE|TIME_MINUTES|TIME_SECONDS));

   class=class="str">"cmt">//--- Create a unique prefix for all graphical objects related to this pattern
   class="type">class="kw">string signalPrefix = "BF_" + IntegerToString(X.time);

   class=class="str">"cmt">//--- Choose triangle class="type">class="kw">color based on the pattern type
   class="type">class="kw">color triangleColor = (patternType=="Bullish") ? clrBlue : clrRed;

   class=class="str">"cmt">//--- Draw the first triangle connecting pivots X, A, and B
   DrawTriangle(signalPrefix+"_Triangle1", X.time, X.price, A.time, A.price, B.time, B.price,
                 triangleColor, class="num">2, true, true);
   class=class="str">"cmt">//--- Draw the second triangle connecting pivots B, C, and D
   DrawTriangle(signalPrefix+"_Triangle2", B.time, B.price, C.time, C.price, D.time, D.price,
                 triangleColor, class="num">2, true, true);

   class=class="str">"cmt">//--- Draw boundary trend lines connecting the pivots for clarity
   DrawTrendLine(signalPrefix+"_TL_XA", X.time, X.price, A.time, A.price, clrBlack, class="num">2, STYLE_SOLID);
   DrawTrendLine(signalPrefix+"_TL_AB", A.time, A.price, B.time, B.price, clrBlack, class="num">2, STYLE_SOLID);
   DrawTrendLine(signalPrefix+"_TL_BC", B.time, B.price, C.time, C.price, clrBlack, class="num">2, STYLE_SOLID);
   DrawTrendLine(signalPrefix+"_TL_CD", C.time, C.price, D.time, D.price, clrBlack, class="num">2, STYLE_SOLID);
   DrawTrendLine(signalPrefix+"_TL_XB", X.time, X.price, B.time, B.price, clrBlack, class="num">2, STYLE_SOLID);
   DrawTrendLine(signalPrefix+"_TL_BD", B.time, B.price, D.time, D.price, clrBlack, class="num">2, STYLE_SOLID);
}
class=class="str">"cmt">//--- Retrieve the symbol&class="macro">#x27;s point size to calculate offsets for text positioning
class="type">class="kw">double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
class=class="str">"cmt">//--- Calculate an offset(class="num">15 points) for positioning text above or below pivots
class="type">class="kw">double offset = class="num">15 * point;

「蝴蝶形态标签与交易位的绘制逻辑」

在 MT5 里把蝴蝶形态可视化,第一步是给 X/A/B/C/D 五个拐点挂文字标签。代码按拐点类型偏移:高点就在 price+offset 上方标,低点则在 price-offset 下方标,避免文字压住 K 线实体。 DrawTextEx 统一用 11 号字、clrBlack 着色,标签名拼了 signalPrefix 前缀,方便同一图表上多信号互不覆盖。中心标签取 X 与 B 时间的中点、D 点价格作锚,写『Bullish/Bearish Butterfly』,用 Arial Bold + 居中,一眼能分辨多空。 交易线从 D.time 画到 D.time+PeriodSeconds(_Period)*2,即向右延两根当前周期 K 线。多头单 entryPriceLevel 直接取 SYMBOL_ASK,TP3 锁在 C.price,TP1/TP2 分别吃总距离的 1/3 与 2/3;空头反之。外汇与贵金属杠杆高,这类位阶仅作概率参考,实盘须自验。

MQL5 / C++
class=class="str">"cmt">//--- Determine the Y coordinate for each pivot label based on its type
class="type">class="kw">double textY_X = (X.isHigh ? X.price + offset : X.price - offset);
class="type">class="kw">double textY_A = (A.isHigh ? A.price + offset : A.price - offset);
class="type">class="kw">double textY_B = (B.isHigh ? B.price + offset : B.price - offset);
class="type">class="kw">double textY_C = (C.isHigh ? C.price + offset : C.price - offset);
class="type">class="kw">double textY_D = (D.isHigh ? D.price + offset : D.price - offset);
class=class="str">"cmt">//--- Draw text labels for each pivot with appropriate anchoring
DrawTextEx(signalPrefix+"_Text_X", "X", X.time, textY_X, clrBlack, class="num">11, X.isHigh);
DrawTextEx(signalPrefix+"_Text_A", "A", A.time, textY_A, clrBlack, class="num">11, A.isHigh);
DrawTextEx(signalPrefix+"_Text_B", "B", B.time, textY_B, clrBlack, class="num">11, B.isHigh);
DrawTextEx(signalPrefix+"_Text_C", "C", C.time, textY_C, clrBlack, class="num">11, C.isHigh);
DrawTextEx(signalPrefix+"_Text_D", "D", D.time, textY_D, clrBlack, class="num">11, D.isHigh);
class=class="str">"cmt">//--- Calculate the central label&class="macro">#x27;s time as the midpoint between pivots X and B
class="type">class="kw">datetime centralTime = (X.time + B.time) / class="num">2;
class=class="str">"cmt">//--- Set the central label&class="macro">#x27;s price at pivot D&class="macro">#x27;s price
class="type">class="kw">double centralPrice = D.price;
class=class="str">"cmt">//--- Create the central text label indicating the pattern type
if(ObjectCreate(class="num">0, signalPrefix+"_Text_Center", OBJ_TEXT, class="num">0, centralTime, centralPrice)) {
   ObjectSetString(class="num">0, signalPrefix+"_Text_Center", OBJPROP_TEXT,
         (patternType=="Bullish") ? "Bullish Butterfly" : "Bearish Butterfly");
   ObjectSetInteger(class="num">0, signalPrefix+"_Text_Center", OBJPROP_COLOR, clrBlack);
   ObjectSetInteger(class="num">0, signalPrefix+"_Text_Center", OBJPROP_FONTSIZE, class="num">11);
   ObjectSetString(class="num">0, signalPrefix+"_Text_Center", OBJPROP_FONT, "Arial Bold");
   ObjectSetInteger(class="num">0, signalPrefix+"_Text_Center", OBJPROP_ALIGN, ALIGN_CENTER);
}
class=class="str">"cmt">//--- Define start and end times for drawing horizontal dotted lines for obj_Trade levels
class="type">class="kw">datetime lineStart = D.time;
class="type">class="kw">datetime lineEnd = D.time + PeriodSeconds(_Period)*class="num">2;
class=class="str">"cmt">//--- Declare variables for entry price and take profit levels
class="type">class="kw">double entryPriceLevel, TP1Level, TP2Level, TP3Level, tradeDiff;
class=class="str">"cmt">//--- Calculate obj_Trade levels based on whether the pattern is Bullish or Bearish
if(patternType=="Bullish") { class=class="str">"cmt">//--- Bullish → BUY signal
   class=class="str">"cmt">//--- Use the current ASK price as the entry
   entryPriceLevel = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   class=class="str">"cmt">//--- Set TP3 at pivot C&class="macro">#x27;s price
   TP3Level = C.price;
   class=class="str">"cmt">//--- Calculate the total distance to be covered by the obj_Trade
   tradeDiff = TP3Level - entryPriceLevel;
   class=class="str">"cmt">//--- Set TP1 at one-third of the total move
   TP1Level = entryPriceLevel + tradeDiff/class="num">3;
   class=class="str">"cmt">//--- Set TP2 at two-thirds of the total move
   TP2Level = entryPriceLevel + class="num">2*tradeDiff/class="num">3;
} else { class=class="str">"cmt">//--- Bearish → SELL signal

把三分位目标画进图表并防重绘

信号锁定后,代码先把当前 BID 价作为入场基准,再把 pivot C 的价格设为 TP3,两者差值 tradeDiff 就是整段预期位移。TP1、TP2 分别落在 entry 减去三分之一、三分之二 tradeDiff 的位置,这种三分位切法在手动复盘时也能直接套用。 随后用 DrawDottedLine 把入场和三个目标画成虚线,颜色从洋红到深绿梯度区分;标签时间坐标取 lineEnd 加半个周期秒数(PeriodSeconds(_Period)/2),避免文字压在线上。标签字号统一 11、右对齐,BUY/SELL 前缀由 patternType 决定。 重绘防护靠两根判断:首次出现形态时把当前 bar 索引存进 g_patternFormationBar 并 Print 等待确认;若下一根 bar 索引仍等于锁定值,判定为同根 K 重绘,直接 return 不下单。外汇与贵金属波动大,这种未确认不交易的闸口能过滤掉不少假突破。

MQL5 / C++
   class=class="str">"cmt">//--- Use the current BID price as the entry
   entryPriceLevel = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   class=class="str">"cmt">//--- Set TP3 at pivot C&class="macro">#x27;s price
   TP3Level = C.price;
   class=class="str">"cmt">//--- Calculate the total distance to be covered by the obj_Trade
   tradeDiff = entryPriceLevel - TP3Level;
   class=class="str">"cmt">//--- Set TP1 at one-third of the total move
   TP1Level = entryPriceLevel - tradeDiff/class="num">3;
   class=class="str">"cmt">//--- Set TP2 at two-thirds of the total move
   TP2Level = entryPriceLevel - class="num">2*tradeDiff/class="num">3;
}
class=class="str">"cmt">//--- Draw dotted horizontal lines to represent the entry and TP levels
DrawDottedLine(signalPrefix+"_EntryLine", lineStart, entryPriceLevel, lineEnd, clrMagenta);
DrawDottedLine(signalPrefix+"_TP1Line", lineStart, TP1Level, lineEnd, clrForestGreen);
DrawDottedLine(signalPrefix+"_TP2Line", lineStart, TP2Level, lineEnd, clrGreen);
DrawDottedLine(signalPrefix+"_TP3Line", lineStart, TP3Level, lineEnd, clrDarkGreen);
class=class="str">"cmt">//--- Define a label time coordinate positioned just to the right of the dotted lines
class="type">class="kw">datetime labelTime = lineEnd + PeriodSeconds(_Period)/class="num">2;
class=class="str">"cmt">//--- Construct the entry label text with the price
class="type">class="kw">string entryLabel = (patternType=="Bullish") ? "BUY(" : "SELL(";
entryLabel += DoubleToString(entryPriceLevel, _Digits) + ")";
class=class="str">"cmt">//--- Draw the entry label on the chart
DrawTextEx(signalPrefix+"_EntryLabel", entryLabel, labelTime, entryPriceLevel, clrMagenta, class="num">11, true);
class=class="str">"cmt">//--- Construct and draw the TP1 label
class="type">class="kw">string tp1Label = "TP1(" + DoubleToString(TP1Level, _Digits) + ")";
DrawTextEx(signalPrefix+"_TP1Label", tp1Label, labelTime, TP1Level, clrForestGreen, class="num">11, true);
class=class="str">"cmt">//--- Construct and draw the TP2 label
class="type">class="kw">string tp2Label = "TP2(" + DoubleToString(TP2Level, _Digits) + ")";
DrawTextEx(signalPrefix+"_TP2Label", tp2Label, labelTime, TP2Level, clrGreen, class="num">11, true);
class=class="str">"cmt">//--- Construct and draw the TP3 label
class="type">class="kw">string tp3Label = "TP3(" + DoubleToString(TP3Level, _Digits) + ")";
DrawTextEx(signalPrefix+"_TP3Label", tp3Label, labelTime, TP3Level, clrDarkGreen, class="num">11, true);
class=class="str">"cmt">//--- Retrieve the index of the current bar
class="type">int currentBarIndex = Bars(_Symbol, _Period) - class="num">1;
class=class="str">"cmt">//--- If no pattern has been previously locked, lock the current pattern formation
if(g_patternFormationBar == -class="num">1) {
   g_patternFormationBar = currentBarIndex;
   g_lockedPatternX = X.time;
   class=class="str">"cmt">//--- Print a message that the pattern is detected and waiting for confirmation
   Print("Pattern detected on bar ", currentBarIndex, ". Waiting for confirmation on next bar.");
   class="kw">return;
}
class=class="str">"cmt">//--- If still on the same formation bar, the pattern is considered to be repainting
if(currentBarIndex == g_patternFormationBar) {
   Print("Pattern is repainting; still on locked formation bar ", currentBarIndex, ". No obj_Trade yet.");
   class="kw">return;
}

常见问题

设定左窗与右窗根数(如左5右3),逐根比对高低价,只有右侧连续N根不破极值才确认摆点,可避免噪声假突破。
XA、AB、BC、CD各段回撤/扩展须落在蝴蝶比例带(如AB≈0.786XA、CD≈1.27XA),偏差超容差就丢弃,不硬凑形态。
可以。小布能按摆点逻辑扫描品种并绘制形态标签与多空判定,你打开对应页面即可直接看已识别的蝴蝶图形与交易位。
命中时一次性写入目标线对象并锁定锚点,之后只做存在性判断不重算坐标,可防重绘导致的线移位。
贵金属跳空多、点差大,摆点容差要放宽且需屏蔽重大数据时段,外汇与贵金属均属高风险,信号仅为概率倾向。