价格行为分析工具包开发(第十六部分):引入四分之一理论(2) 侵入探测器智能交易系统(EA)·进阶篇
📘

价格行为分析工具包开发(第十六部分):引入四分之一理论(2) 侵入探测器智能交易系统(EA)·进阶篇

第 2/3 篇

「千点区间的四分位画线逻辑」

这段 DrawQuarters 函数是把当前价格锁定在一个 1000 点(MajorStep=0.1000)区间内做水平线分割的核心。先用 MathFloor(currentPrice / MajorStep) * MajorStep 求出区间下边界,再加 MajorStep 得到上边界,两条主界线就框出了整段千点范围。 大四分位把千点区间四等分,循环 i=1 到 3 生成三个内部分割线;若开启 DrawOvershootAreas,会在每条大四分位上下各偏移 MajorStep/40.0(约 25 点)画超调/欠调参考线,用来观察价格触碰四分位后的刺穿幅度。 小四分位进一步把区间切成 10 段、每段再四等分,共 30 条细线,适合做更密的价格行为参照。外汇与贵金属波动剧烈,这类辅助线仅作结构观察,实际突破概率仍受基本面与流动性影响。 开 MT5 把 MajorStep 改成 0.0500 可切换为 500 点区间视图,肉眼对比黄金与欧美对四分位的反应差异。

MQL5 / C++
class="type">void DrawQuarters(class="type">class="kw">double currentPrice)
{
   class=class="str">"cmt">// Calculate the boundaries of the current class="num">1000-PIP Range
   class="type">class="kw">double lowerMajor = MathFloor(currentPrice / MajorStep) * MajorStep;
   class="type">class="kw">double upperMajor = lowerMajor + MajorStep;
   class=class="str">"cmt">// Draw Major Whole Number lines(defining the class="num">1000-PIP Range)
   DrawHorizontalLine("MajorLower", lowerMajor, MajorColor, MajorLineWidth, MajorLineStyle);
   DrawHorizontalLine("MajorUpper", upperMajor, MajorColor, MajorLineWidth, MajorLineStyle);
   class=class="str">"cmt">// Draw Large Quarter lines and their overshoot/undershoot areas if enabled
   if(DrawLargeQuarters)
   {
      class="type">class="kw">double LQIncrement = MajorStep / class="num">4.0;
      for(class="type">int i = class="num">1; i < class="num">4; i++)
      {
         class="type">class="kw">double level = lowerMajor + i * LQIncrement;
         class="type">class="kw">string objName = "LargeQuarter_" + IntegerToString(i);
         DrawHorizontalLine(objName, level, LargeQuarterColor, LargeQuarterLineWidth, LargeQuarterLineStyle);
         if(DrawOvershootAreas)
         {
            class="type">class="kw">double offset = MajorStep / class="num">40.0; class=class="str">"cmt">// approximately class="num">25 pips if MajorStep=class="num">0.1000
            DrawHorizontalLine("Overshoot_" + IntegerToString(i) + "_up", level + offset, OvershootColor, OvershootLineWidth, OvershootLineStyle);
            DrawHorizontalLine("Undershoot_" + IntegerToString(i) + "_down", level - offset, OvershootColor, OvershootLineWidth, OvershootLineStyle);
         }
      }
   }
   class=class="str">"cmt">// Draw Small Quarter lines if enabled(optional, finer divisions)
   if(DrawSmallQuarters)
   {
      class="type">class="kw">double segStep = MajorStep / class="num">10.0;
      class="type">class="kw">double smallQuarter = segStep / class="num">4.0;
      for(class="type">int seg = class="num">0; seg < class="num">10; seg++)
      {
         class="type">class="kw">double segStart = lowerMajor + seg * segStep;
         for(class="type">int j = class="num">1; j < class="num">4; j++)
         {
            class="type">class="kw">double level = segStart + j * smallQuarter;
            class="type">class="kw">string objName = "SmallQuarter_" + IntegerToString(seg) + "_" + IntegerToString(j);
            DrawHorizontalLine(objName, level, SmallQuarterColor, SmallQuarterLineWidth, SmallQuarterLineStyle);
         }
      }
   }
}

把价位入侵画到图表左上角

想在 MT5 图表上实时盯住价格对关键位的「入侵」,第一步是把提示信息钉在固定角落。下面这段用 OBJ_LABEL 建一个持久标签,初始化时放在左上角距边 10 像素处,白色 14 号字,等宽字体保证表格列对齐不串位。 ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0); // 在图表0号子窗口建标签对象,坐标参数对LABEL无效 ObjectSetInteger(0, name, OBJPROP_CORNER, corner); // 锚定角落,如CORNER_LEFT_UPPER=0 ObjectSetInteger(0, name, OBJPROP_XDISTANCE, xdist); // 距左边界像素 ObjectSetInteger(0, name, OBJPROP_YDISTANCE, ydist); // 距上边界像素 ObjectSetString(0, name, OBJPROP_FONT, "Courier New"); // 等宽字体,数字表才不会错位 OnInit 里只调一次 CreateOrUpdateLabel("IntrusionCommentary", ... , 10, 10, clrWhite, 14),标签就常驻了。OnTick 中先取 SYMBOL_BID,若为 0 直接 return 避免假信号;随后算 lowerMajor = MathFloor(price/MajorStep)*MajorStep,上下大位差一个 MajorStep。

price - lowerMajor≤ AlertTolerance 判定 Major Support 入侵,同理上边界判 Major Resistance;若开 DrawLargeQuarters,再把 MajorStep 四等分,i=1~3 的 level 命中即记 Large Quarter。外汇与贵金属杠杆高,这类入侵只是概率性参考,真触发不代表反转。

画 overshoot 区时 offset = MajorStep/40.0,原文注释约 25 点,用来标 level 上下各一档的穿透带;价格落进 overshootUp 附近也会被捕获。复制代码后把 MajorStep、AlertTolerance 按品种波动调一调,就能在 MT5 里跑起来验证。

MQL5 / C++
ObjectCreate(class="num">0, name, OBJ_LABEL, class="num">0, class="num">0, class="num">0);
ObjectSetInteger(class="num">0, name, OBJPROP_CORNER, corner);
ObjectSetInteger(class="num">0, name, OBJPROP_XDISTANCE, xdist);
ObjectSetInteger(class="num">0, name, OBJPROP_YDISTANCE, ydist);
class=class="str">"cmt">// Set a monospaced font for tabular display(Courier New)
ObjectSetString(class="num">0, name, OBJPROP_FONT, "Courier New");
}
ObjectSetString(class="num">0, name, OBJPROP_TEXT, text);
ObjectSetInteger(class="num">0, name, OBJPROP_COLOR, txtColor);
ObjectSetInteger(class="num">0, name, OBJPROP_FONTSIZE, fontSize);
}
class="type">int OnInit()
{
  class=class="str">"cmt">// Create a persistent commentary label in the top-left corner
  CreateOrUpdateLabel("IntrusionCommentary", "Intrusion Detector Initialized", CORNER_LEFT_UPPER, class="num">10, class="num">10, clrWhite, class="num">14);
  class="kw">return(INIT_SUCCEEDED);
}
class="type">void OnTick()
{
  class="type">bool intrusionDetected = false;
  class="type">class="kw">double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
  if(currentPrice == class="num">0)
    class="kw">return;
  class=class="str">"cmt">// Draw the quarter lines first
  DrawQuarters(currentPrice);
  class="type">class="kw">double lowerMajor = MathFloor(currentPrice / MajorStep) * MajorStep;
  class="type">class="kw">double upperMajor = lowerMajor + MajorStep;
class=class="str">"cmt">// Check for Major Support
if(MathAbs(currentPrice - lowerMajor) <= AlertTolerance)
{
  table += StringFormat("%-18s | %-8s | %s\n", "Major Support", DoubleToString(lowerMajor,class="num">4), MajorSupportReason);
  intrusionDetected = true;
}
class=class="str">"cmt">// Check for Major Resistance
if(MathAbs(currentPrice - upperMajor) <= AlertTolerance)
{
  table += StringFormat("%-18s | %-8s | %s\n", "Major Resistance", DoubleToString(upperMajor,class="num">4), MajorResistanceReason);
  intrusionDetected = true;
}
if(DrawLargeQuarters)
{
  class="type">class="kw">double LQIncrement = MajorStep / class="num">4.0;
  for(class="type">int i = class="num">1; i < class="num">4; i++)
  {
    class="type">class="kw">double level = lowerMajor + i * LQIncrement;
    if(MathAbs(currentPrice - level) <= AlertTolerance)
    {
      table += StringFormat("%-18s | %-8s | %s\n", "Large Quarter", DoubleToString(level,class="num">4), LargeQuarterReason);
      intrusionDetected = true;
    }
    if(DrawOvershootAreas)
    {
      class="type">class="kw">double offset = MajorStep / class="num">40.0; class=class="str">"cmt">// ~class="num">25 pips
      class="type">class="kw">double overshootUp = level + offset;
      class="type">class="kw">double undershootDown = level - offset;
      if(MathAbs(currentPrice - overshootUp) <= AlertTolerance)

◍ 侵入判定与提示标签的收口逻辑

上面这段收尾代码负责把价格对四分位区间的侵入结果汇总成表,并控制 alert 只响一次。外汇与贵金属波动大,AlertTolerance 设太小会频繁误报,设太大则漏掉有效刺穿,实盘里建议先在 XAUUSD 的 M15 上用 0.0003~0.0008 试。 当价格落在 overshootUp 或 undershootDown 的容差内,代码把对应行写进 table 并置 intrusionDetected=true;小四分位则用 MajorStep/10 再除 4 得到 smallQuarter,遍历 10 段每段 3 个内点做同样判定。若一轮下来没有任何触发,table 会被替换成「No significant intrusion detected」并提示当前价与盘整状态。 最后 CreateOrUpdateLabel 把 table 画在左上角(偏移 10,10,白色 14 号字),Alert 仅在 intrusionDetected 由 false 变 true 时发一次,价格退出容差后 intrusionAlerted 复位。这样你开 MT5 挂上 EA,就能在图上直接读侵入 commentary,不用自己算四分位边界。

MQL5 / C++
    {
      table += StringFormat("%-18s | %-8s | %s\n", "Overshoot", DoubleToString(overshootUp,class="num">4), OvershootReason);
      intrusionDetected = true;
    }
    if(MathAbs(currentPrice - undershootDown) <= AlertTolerance)
    {
      table += StringFormat("%-18s | %-8s | %s\n", "Undershoot", DoubleToString(undershootDown,class="num">4), UndershootReason);
      intrusionDetected = true;
    }
  }
}
if(DrawSmallQuarters)
{
  class="type">class="kw">double segStep = MajorStep / class="num">10.0;
  class="type">class="kw">double smallQuarter = segStep / class="num">4.0;
  for(class="type">int seg = class="num">0; seg < class="num">10; seg++)
  {
    class="type">class="kw">double segStart = lowerMajor + seg * segStep;
    for(class="type">int j = class="num">1; j < class="num">4; j++)
    {
      class="type">class="kw">double level = segStart + j * smallQuarter;
      if(MathAbs(currentPrice - level) <= AlertTolerance)
      {
        table += StringFormat("%-18s | %-8s | %s\n", "Small Quarter", DoubleToString(level,class="num">4), SmallQuarterReason);
        intrusionDetected = true;
      }
    }
  }
}
  class=class="str">"cmt">// If no zones were triggered, still provide full information
  if(!intrusionDetected)
  {
    table = StringFormat("No significant intrusion detected.\nCurrent Price: %s\nMarket consolidating within established quarters.\n", DoubleToString(currentPrice,class="num">4));
  }
  class=class="str">"cmt">// Update the label with the commentary table.
  CreateOrUpdateLabel("IntrusionCommentary", table, CORNER_LEFT_UPPER, class="num">10, class="num">10, clrWhite, class="num">14);
  class=class="str">"cmt">// Trigger an alert only once per intrusion event.
  if(intrusionDetected && !intrusionAlerted)
  {
    Alert(table);
    intrusionAlerted = true;
  }
  if(!intrusionDetected)
    intrusionAlerted = false;
  ChartRedraw();
}

「把整数位网格的参数和配色先钉死」

这套 MT5 指标把「大整数区间」切成可配置的网格:MajorStep 默认 0.1000,也就是每 1000 点画一条主整数线,框出所谓的 1000-PIP Range。 LargeQuarter 和 SmallQuarter 是主区间里的细分线,前者默认开、后者默认关;OvershootAreas 默认开,用来标出大四分位线被刺穿但没站住的上下影区。AlertTolerance 设 0.0025,对常规 1 点=0.0001 的货币对约等于 25 点容差,价格蹭到线就触发判定。 配色和线型也全暴露成 input:主线和字色用暗石板灰(0x2F4F4F)实线宽 4;大四分位暗红点线宽 3;刺穿区红虚线宽 1。注释文本也能改,比如 LargeQuarterReason 写的是「决断性破位可能引出后续 250 点波动」——外汇和贵金属波动随机,这类表述只描述概率倾向,实操高风险。 全局布尔 intrusionAlerted 用来防重复报警:价格赖在线上不走时,不会每 tick 都刷提示,这点直接决定你手机会不会被 alert 轰爆。

MQL5 / C++
class="macro">#class="kw">property strict
class=class="str">"cmt">//---- Input parameters -------------------------------------------------
input class="type">class="kw">double MajorStep           = class="num">0.1000;   class=class="str">"cmt">// Difference between Major Whole Numbers(defines the class="num">1000-PIP Range)
input class="type">bool   DrawLargeQuarters   = true;     class=class="str">"cmt">// Draw intermediate Large Quarter lines.
input class="type">bool   DrawSmallQuarters   = false;    class=class="str">"cmt">// Draw Small Quarter lines.
input class="type">bool   DrawOvershootAreas = true;     class=class="str">"cmt">// Mark overshoot/undershoot areas for Large Quarter lines.
input class="type">class="kw">double AlertTolerance      = class="num">0.0025;   class=class="str">"cmt">// Tolerance for detecting a "touch" (e.g., ~class="num">25 pips for a pair where class="num">1 pip=class="num">0.0001)
class=class="str">"cmt">//---- Color settings ---------------------------------------------------
input class="type">class="kw">color  MajorColor          = 0x2F4F4F; class=class="str">"cmt">// Dark Slate Gray for Major lines.
input class="type">class="kw">color  LargeQuarterColor   = 0x8B0000; class=class="str">"cmt">// Dark Red for Large Quarter lines.
input class="type">class="kw">color  SmallQuarterColor   = 0x00008B; class=class="str">"cmt">// Dark Blue for Small Quarter lines.
input class="type">class="kw">color  OvershootColor      = clrRed;   class=class="str">"cmt">// Red for overshoot/undershoot lines.
class=class="str">"cmt">//---- Line style and thickness settings -------------------------------
input ENUM_LINE_STYLE MajorLineStyle         = STYLE_SOLID;
input class="type">int    MajorLineWidth                 = class="num">4;
input ENUM_LINE_STYLE LargeQuarterLineStyle = STYLE_DOT;
input class="type">int    LargeQuarterLineWidth          = class="num">3;
input ENUM_LINE_STYLE OvershootLineStyle    = STYLE_DASH;
input class="type">int    OvershootLineWidth             = class="num">1;
input ENUM_LINE_STYLE SmallQuarterLineStyle = STYLE_SOLID;
input class="type">int    SmallQuarterLineWidth          = class="num">1;
class=class="str">"cmt">//---- Commentary Messages(customizable) -----------------------------
input class="type">class="kw">string MajorSupportReason    = "Key support level. Break below signals range shift.";
input class="type">class="kw">string MajorResistanceReason = "Pivotal resistance. Breakout above may start new range.";
input class="type">class="kw">string LargeQuarterReason    = "Decisive break could trigger next class="num">250-PIP move.";
input class="type">class="kw">string OvershootReason       = "Test of breakout; reversal likely if momentum fails.";
input class="type">class="kw">string UndershootReason      = "Insufficient bullish force; possible bearish reversal.";
input class="type">class="kw">string SmallQuarterReason    = "Minor fluctuation.";
class=class="str">"cmt">// Global flag to avoid repeated alerts class="kw">while price lingers at a level
class="type">bool intrusionAlerted = false;
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| DrawHorizontalLine: Creates or replaces a horizontal line          |
class=class="str">"cmt">//+------------------------------------------------------------------+

把千点区间拆成可交易的四分位线

千点整数区(MajorStep=0.1000 这类跨度)只是个容器,真正能拿来挂单的是它内部的四分位。下面这段逻辑先按 MathFloor 把现价落到下边界,再 +MajorStep 得出上边界,两个边界线框出当前千点区间。 大四分位用 MajorStep/4.0 做步长,循环 i=1 到 3 画出三条内部水平线;若开启 DrawOvershootAreas,会在每条线上下各偏移 MajorStep/40.0(约 25 点)画穿透/跌破参考线,外汇与贵金属波动下这些区域常出现假突破,概率上更值得警惕。 小四分位进一步把每段再十等分后取四分之一,粒度更细但画线数量陡增;MT5 里对象过多会拖慢刷新,实盘前建议先用策略测试器跑一遍确认卡顿情况。 DrawHorizontalLine 每次先 ObjectFind 删旧再建新,避免重复对象名报错,这是挂 EA 时最容易忽略的清理动作。

MQL5 / C++
class="type">void DrawHorizontalLine(class="type">class="kw">string name, class="type">class="kw">double price, class="type">class="kw">color lineColor, class="type">int width, ENUM_LINE_STYLE style)
  {
  if(ObjectFind(class="num">0, name) != -class="num">1)
      ObjectDelete(class="num">0, name);
  if(!ObjectCreate(class="num">0, name, OBJ_HLINE, class="num">0, class="num">0, price))
     {
       Print("Failed to create line: ", name);
       class="kw">return;
     }
  ObjectSetInteger(class="num">0, name, OBJPROP_COLOR, lineColor);
  ObjectSetInteger(class="num">0, name, OBJPROP_STYLE, style);
  ObjectSetInteger(class="num">0, name, OBJPROP_WIDTH, width);
  ObjectSetInteger(class="num">0, name, OBJPROP_RAY_RIGHT, true);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| DrawQuarters: Draws all quarter lines based on the current price |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void DrawQuarters(class="type">class="kw">double currentPrice)
  {
class=class="str">"cmt">// Calculate the boundaries of the current class="num">1000-PIP Range
  class="type">class="kw">double lowerMajor = MathFloor(currentPrice / MajorStep) * MajorStep;
  class="type">class="kw">double upperMajor = lowerMajor + MajorStep;
class=class="str">"cmt">// Draw Major Whole Number lines(defining the class="num">1000-PIP Range)
  DrawHorizontalLine("MajorLower", lowerMajor, MajorColor, MajorLineWidth, MajorLineStyle);
  DrawHorizontalLine("MajorUpper", upperMajor, MajorColor, MajorLineWidth, MajorLineStyle);
class=class="str">"cmt">// Draw Large Quarter lines and their overshoot/undershoot areas if enabled
  if(DrawLargeQuarters)
    {
      class="type">class="kw">double LQIncrement = MajorStep / class="num">4.0;
      for(class="type">int i = class="num">1; i < class="num">4; i++)
        {
         class="type">class="kw">double level = lowerMajor + i * LQIncrement;
         class="type">class="kw">string objName = "LargeQuarter_" + IntegerToString(i);
         DrawHorizontalLine(objName, level, LargeQuarterColor, LargeQuarterLineWidth, LargeQuarterLineStyle);
         if(DrawOvershootAreas)
           {
            class="type">class="kw">double offset = MajorStep / class="num">40.0; class=class="str">"cmt">// approximately class="num">25 pips if MajorStep=class="num">0.1000
            DrawHorizontalLine("Overshoot_" + IntegerToString(i) + "_up", level + offset, OvershootColor, OvershootLineWidth, OvershootLineStyle);
            DrawHorizontalLine("Undershoot_" + IntegerToString(i) + "_down", level - offset, OvershootColor, OvershootLineWidth, OvershootLineStyle);
           }
        }
     }
class=class="str">"cmt">// Draw Small Quarter lines if enabled(optional, finer divisions)
  if(DrawSmallQuarters)
    {
      class="type">class="kw">double segStep = MajorStep / class="num">10.0;
      class="type">class="kw">double smallQuarter = segStep / class="num">4.0;
      for(class="type">int seg = class="num">0; seg < class="num">10; seg++)
        {
         class="type">class="kw">double segStart = lowerMajor + seg * segStep;
         for(class="type">int j = class="num">1; j < class="num">4; j++)
           {

常见问题

以区间最高最低价差为基准,除以4得到步长,依次画出25%、50%、75%三条线,配合整数位网格可快速定位潜在反转区。
用TextCreate或Label在左上角坐标创建标签,绑定最新入侵价位与方向,设置背景透明即可避免遮挡。
小布盯盘已内置AIGC诊断,打开对应品种页就能看到四分位入侵标记与概率提示,不用自己写EA。
设定仅在价格首次穿越四分位线时触发,之后用冷却计时或状态变量锁死标签,直到退出区间再复位。
把网格间距、线宽、颜色写进输入参数面板,主图用低饱和灰蓝、入侵线用橙红,回测时一眼可辨。