English Deutsch 日本語
preview
价格行为分析工具包开发(第十八部分):四分位理论(3)——四分位看板

价格行为分析工具包开发(第十八部分):四分位理论(3)——四分位看板

MetaTrader 5示例 |
425 0
Christian Benjamin
Christian Benjamin

内容


概述

在四分位理论入门中,我们首先介绍了四分位绘图脚本——这是整个体系的第一块拼图。该脚本可自动在图表上绘制四分位水平,并通过布尔开关控制每个级别的可见性。

input bool   DrawLargeQuarters  = true;     // Draw intermediate large quarter lines.
input bool   DrawSmallQuarters  = false;    // Draw small quarter lines.
input bool   DrawOvershootAreas = true;     // Mark overshoot/undershoot areas for large quarter lines.

例如,将DrawSmallQuarters设置为true可显示小四分位线,而将DrawLargeQuarters设为false则隐藏大四分位线。此逻辑同样适用于上冲/下探水平。该功能允许用户聚焦特定价位,保持图表简洁无干扰。如需查看所有水平线,只需一键启用全部开关即可。

您是否曾因反复修改代码调整设置而感到繁琐?本文介绍的四分位看板工具,可通过图表按钮直接切换布尔值开关,无需编辑代码。您无需修改DrawSmallQuarters参数,直接在图表上点击按钮即可完成调整,大幅简化操作流程。例如,如果您仅需查看大四分位线,一键即可实现。


概览

如前文所述,该工具支持通过图表按钮动态控制显示价位,无需修改布尔参数。四分位看板作为智能交易系统(EA),配备四个功能按钮:大四分位线、小四分位线、上冲/下探和趋势方向。点击任意按钮可切换对应价位:按钮文字激活时显示绿色,关闭时显示红色。

趋势方向按钮 作为附加功能,提供实时的市场分析。只需一键,即可计算50周期简单移动平均线(SMA),并与当前市场价格比较,帮助您快速判断市场是上涨、下跌还是横盘。该按钮还会变色以显示激活状态,提供清晰且用户友好的方式,让您直接在图表上监控市场趋势。请参考下一节,了解我们EA核心逻辑背后的工作原理。


逻辑

该EA兼顾易用性与高度的适应性。设置项可定制,界面简洁有序,按钮化控制流畅顺手。通过自动增删四分位线,让图表始终保持整洁,只聚焦关键价位。在实时趋势评论中添加另一层分析,助您一眼判断市场方向,而非堆砌信息。可视化与解析工具双管齐下,化繁为简,确保直观高效。

全局配置与结构

该EA首先定义核心参数,以此决定价位与图表元素的展示方式。输入设置允许交易者自定义如主要价位水平间距以及各种线条配色。这些设置提供了高度灵活性,允许用户自定义EA的界面显示效果,而无需修改其核心逻辑。代码中还定义了多个全局布尔变量作为功能开关,用于启用或禁用特定功能(如大四分位线显示、趋势分析评论等)。通过宏定义为图表对象分配统一命名,确保脚本中所有元素的引用保持一致性。集中管理相关设置后,用户可快速调整参数并排查问题,无需在代码的不同部分间反复切换查找。
#property copyright "Christian Benjamin"
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.0"
#property strict

//---- Input parameters for drawing levels ----------------------------
input double MajorStep = 0.1000;   // Difference between major whole numbers

//---- Color settings ---------------------------------------------------
input color  MajorColor         = 0x2F4F4F; // Dark Slate Gray for major lines.
input color  LargeQuarterColor  = 0x8B0000; // Dark Red for large quarter lines.
input color  SmallQuarterColor  = 0x00008B; // Dark Blue for small quarter lines.
input color  OvershootColor     = clrRed;   // Red for overshoot/undershoot lines.

//---- Line styles and thickness settings -----------------------------
input ENUM_LINE_STYLE MajorLineStyle       = STYLE_SOLID;
input int    MajorLineWidth                 = 4;
input ENUM_LINE_STYLE LargeQuarterLineStyle  = STYLE_DOT;
input int    LargeQuarterLineWidth          = 3;
input ENUM_LINE_STYLE OvershootLineStyle     = STYLE_DASH;
input int    OvershootLineWidth             = 1;
input ENUM_LINE_STYLE SmallQuarterLineStyle  = STYLE_SOLID;
input int    SmallQuarterLineWidth          = 1;

//---- Panel and button settings --------------------------------------
input int PanelX       = 10;
input int PanelY       = 10;
input int PanelWidth   = 250;
input int ButtonHeight = 30;
input int ButtonSpacing= 5;

//---- Global toggle variables ----------------------------------------
bool g_DrawLargeQuarters   = true;
bool g_DrawSmallQuarters   = false;
bool g_DrawOvershootAreas  = true;
bool g_DrawTrendDirection  = false;

//---- Object names for panel and buttons -----------------------------
#define PANEL_NAME       "LevelsPanel"
#define BUTTON_LARGE     "btnLargeQuarters"
#define BUTTON_SMALL     "btnSmallQuarters"
#define BUTTON_OVERSHOOT "btnOvershoot"
#define BUTTON_TREND     "btnTrendDirection"
#define TREND_LABEL      "TrendDirectionLabel"

面板与按钮初始化

完成配置后,EA开始构建用户界面。首先创建一个背景面板,用于集中容纳所有按钮,形成结构化布局。该面板通过矩形标签模拟实现,可以调整文本属性控制其尺寸。随后,按钮根据面板位置进行相对定位,确保间距合理且对齐整齐。

这些按钮支持交易者切换以下功能:大四分位线、小四分位线、上冲区域和趋势方向评论。每个按钮均采用统一宽度和高度,呈现简洁有序的视觉效果。该设计使用户可通过单次点击轻松启用或禁用特定功能,操作直观便捷。通过统一的布局,EA确保所有控件易于识别且操作路径清晰。

void CreatePanel()
  {
   if(ObjectCreate(0, PANEL_NAME, OBJ_RECTANGLE_LABEL, 0, 0, 0))
     {
      ObjectSetInteger(0, PANEL_NAME, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, PANEL_NAME, OBJPROP_XDISTANCE, PanelX);
      ObjectSetInteger(0, PANEL_NAME, OBJPROP_YDISTANCE, PanelY);
      ObjectSetInteger(0, PANEL_NAME, OBJPROP_COLOR, clrDarkGray);
      ObjectSetString(0, PANEL_NAME, OBJPROP_TEXT, "\n\n\n\n");
      ObjectSetInteger(0, PANEL_NAME, OBJPROP_BORDER_TYPE, BORDER_RAISED);
     }
  }

用户交互处理

用户交互是该EA的核心功能模块,通过事件处理系统实现动态响应。脚本持续监听图表事件,重点检测按钮点击操作。当检测到按钮被点击时,系统通过匹配按钮名称识别需触发的功能。一旦识别出,会执行对应的状态切换(开启/关闭)。例如,点击大四分位线按钮将切换该价位线的显示与隐藏状态。

为优化用户体验,按钮颜色会实时更新以提供明确的视觉反馈——激活状态的按钮显示为绿色,未激活状态的按钮保持红色。该系统确保各功能独立运行,避免操作冲突,同时保障工具对用户实时输入的快速响应。通过高效的事件处理架构,使得EA即使在市场剧烈波动时仍能保持稳定运行与易用性。

void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   if(id == CHARTEVENT_OBJECT_CLICK)
     {
      if(sparam == BUTTON_LARGE)
        {
         g_DrawLargeQuarters = !g_DrawLargeQuarters;
         UpdateButtonColors();
         DrawQuarterLines();
        }
      else if(sparam == BUTTON_TREND)
        {
         g_DrawTrendDirection = !g_DrawTrendDirection;
         UpdateButtonColors();
         if(g_DrawTrendDirection)
            UpdateTrendComment();
         else
            DeleteTrendComment();
        }
      // Similar handling for other buttons...
     }
  }

四分位线的绘制与移除

该EA的核心功能之一是在图表上绘制价格水平线。处理流程首先确定当前市场价格,并计算关键价格的边界值。主价格水平线始终显示,而大四分位线、小四分位线及上冲区域等附加水平线,仅在对应功能按钮启用时才会显示。为了保持图表清晰,EA会在绘制新线前先移除所有已存在的旧线。

此操作可避免重叠或过期的线条干扰图表显示。每种四分位计算方法均遵循标准化算法,确保价格水平精准对齐。当某功能被关闭时,脚本会自动移除相关线条,使交易者能完全控制图表的显示内容。该方法确保图表始终保持整洁,并且仅根据用户偏好展示最相关的市场信息。

void DrawQuarterLines()
  {
   DeleteQuarterLines();
   double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double lowerMajor = MathFloor(currentPrice / MajorStep) * MajorStep;
   DrawHorizontalLine("MajorLower", lowerMajor, MajorColor, MajorLineWidth, MajorLineStyle);
   if(g_DrawLargeQuarters)
     {
      double LQIncrement = MajorStep / 4.0;
      for(int i = 1; i < 4; i++)
        {
         double level = lowerMajor + i * LQIncrement;
         DrawHorizontalLine("LargeQuarter_" + IntegerToString(i), level, LargeQuarterColor, LargeQuarterLineWidth, LargeQuarterLineStyle);
         // Overshoot/Undershoot handling...
        }
     }
   // Additional code for small quarters...
  }

趋势分析评论显示

除图形元素外,该EA还为交易者提供市场趋势的文字分析功能。其会计算指定周期的简单移动平均线(SMA),并将其与当前价格进行对比。当价格高于SMA时,判定为看涨趋势;而当价格低于SMA时,判定为看跌趋势。如果价格在SMA附近波动较小,则判定为横盘市场。分析结果以文本标签形式显示在图表上,位置紧贴趋势方向按钮下方,既保证可见性又不干扰其他图表元素。该文本会随市场变化动态更新,为交易者提供实时的市场情况分析。此功能通过增加文字分析维度,与图形化四分位系统形成互补,帮助交易者做出更全面的决策。

void UpdateTrendComment()
  {
   double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double smaValue = 0.0;
   int handle = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_SMA, PRICE_CLOSE);
   if(handle != INVALID_HANDLE)
     {
      double buffer[];
      if(CopyBuffer(handle, 0, 1, 1, buffer) > 0)
         smaValue = buffer[0];
      IndicatorRelease(handle);
     }
   string trendComment = (currentPrice > smaValue) ? "Uptrend" :
                         (currentPrice < smaValue) ? "Downtrend" : "Sideways";
                         
   int trendLabelY = PanelY + 10 + 3 * (ButtonHeight + ButtonSpacing) + ButtonHeight + ButtonSpacing;
   if(ObjectFind(0, TREND_LABEL) == -1)
     {
      ObjectCreate(0, TREND_LABEL, OBJ_LABEL, 0, 0, 0);
      ObjectSetInteger(0, TREND_LABEL, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, TREND_LABEL, OBJPROP_XDISTANCE, PanelX + 10);
      ObjectSetInteger(0, TREND_LABEL, OBJPROP_YDISTANCE, trendLabelY);
      ObjectSetInteger(0, TREND_LABEL, OBJPROP_COLOR, clrWhite);
      ObjectSetInteger(0, TREND_LABEL, OBJPROP_FONTSIZE, 14);
     }
   ObjectSetString(0, TREND_LABEL, OBJPROP_TEXT, "Trend Direction: " + trendComment);
  }

完整的EA代码

//+------------------------------------------------------------------+
//|                                             Quarters Board EA.mq5|
//|                                Copyright 2025, Christian Benjamin|
//|                           https://www.mql5.com/en/users/lynnchris|
//+------------------------------------------------------------------+
#property copyright "Christian Benjamin"
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.0"
#property strict

//---- Input parameters for drawing levels ----------------------------
input double MajorStep = 0.1000;   // Difference between major whole numbers

//---- Color settings ---------------------------------------------------
input color  MajorColor         = 0x2F4F4F; // Dark Slate Gray for major lines.
input color  LargeQuarterColor  = 0x8B0000; // Dark Red for large quarter lines.
input color  SmallQuarterColor  = 0x00008B; // Dark Blue for small quarter lines.
input color  OvershootColor     = clrRed;   // Red for overshoot/undershoot lines.

//---- Line styles and thickness settings -----------------------------
input ENUM_LINE_STYLE MajorLineStyle       = STYLE_SOLID;
input int    MajorLineWidth                 = 4;
input ENUM_LINE_STYLE LargeQuarterLineStyle  = STYLE_DOT;
input int    LargeQuarterLineWidth          = 3;
input ENUM_LINE_STYLE OvershootLineStyle     = STYLE_DASH;
input int    OvershootLineWidth             = 1;
input ENUM_LINE_STYLE SmallQuarterLineStyle  = STYLE_SOLID;
input int    SmallQuarterLineWidth          = 1;

//---- Panel and button settings --------------------------------------
input int PanelX       = 10;
input int PanelY       = 10;
input int PanelWidth   = 250;
input int ButtonHeight = 30;
input int ButtonSpacing= 5;

//---- Global toggle variables ----------------------------------------
bool g_DrawLargeQuarters   = true;
bool g_DrawSmallQuarters   = false;
bool g_DrawOvershootAreas  = true;
bool g_DrawTrendDirection  = false;

//---- Object names for panel and buttons -----------------------------
#define PANEL_NAME       "LevelsPanel"
#define BUTTON_LARGE     "btnLargeQuarters"
#define BUTTON_SMALL     "btnSmallQuarters"
#define BUTTON_OVERSHOOT "btnOvershoot"
#define BUTTON_TREND     "btnTrendDirection"
#define TREND_LABEL      "TrendDirectionLabel"

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
// Create panel background and buttons
   CreatePanel();
   CreateButtons();
// Draw quarter lines initially
   DrawQuarterLines();
// If trend commentary is toggled on, update it
   if(g_DrawTrendDirection)
      UpdateTrendComment();
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
// Delete panel, buttons, quarter lines, and trend commentary
   ObjectDelete(0, PANEL_NAME);
   ObjectDelete(0, BUTTON_LARGE);
   ObjectDelete(0, BUTTON_SMALL);
   ObjectDelete(0, BUTTON_OVERSHOOT);
   ObjectDelete(0, BUTTON_TREND);
   DeleteQuarterLines();
   DeleteTrendComment();
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
// Redraw quarter lines on every tick
   DrawQuarterLines();
// Update trend commentary if enabled
   if(g_DrawTrendDirection)
      UpdateTrendComment();
  }
//+------------------------------------------------------------------+
//| Chart event function to catch button clicks                      |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   if(id == CHARTEVENT_OBJECT_CLICK)
     {
      if(sparam == BUTTON_LARGE)
        {
         g_DrawLargeQuarters = !g_DrawLargeQuarters;
         UpdateButtonColors();
         DrawQuarterLines();
        }
      else
         if(sparam == BUTTON_SMALL)
           {
            g_DrawSmallQuarters = !g_DrawSmallQuarters;
            UpdateButtonColors();
            DrawQuarterLines();
           }
         else
            if(sparam == BUTTON_OVERSHOOT)
              {
               g_DrawOvershootAreas = !g_DrawOvershootAreas;
               UpdateButtonColors();
               DrawQuarterLines();
              }
            else
               if(sparam == BUTTON_TREND)
                 {
                  g_DrawTrendDirection = !g_DrawTrendDirection;
                  UpdateButtonColors();
                  if(g_DrawTrendDirection)
                     UpdateTrendComment();
                  else
                     DeleteTrendComment();
                 }
     }
  }
//+------------------------------------------------------------------+
//| Create panel background                                          |
//+------------------------------------------------------------------+
void CreatePanel()
  {
   if(ObjectCreate(0, PANEL_NAME, OBJ_RECTANGLE_LABEL, 0, 0, 0))
     {
      ObjectSetInteger(0, PANEL_NAME, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, PANEL_NAME, OBJPROP_XDISTANCE, PanelX);
      ObjectSetInteger(0, PANEL_NAME, OBJPROP_YDISTANCE, PanelY);
      ObjectSetInteger(0, PANEL_NAME, OBJPROP_COLOR, clrDarkGray);
      // Simulate a larger panel using newlines in the text.
      string panelText = "\n\n\n\n";
      ObjectSetString(0, PANEL_NAME, OBJPROP_TEXT, panelText);
      ObjectSetInteger(0, PANEL_NAME, OBJPROP_BORDER_TYPE, BORDER_RAISED);
     }
  }
//+------------------------------------------------------------------+
//| Create buttons on the panel                                      |
//+------------------------------------------------------------------+
void CreateButtons()
  {
   int x = PanelX + 10;
   int y = PanelY + 10;
   int btnWidth = PanelWidth - 20;
// Button for Large Quarters
   if(!ObjectCreate(0, BUTTON_LARGE, OBJ_BUTTON, 0, 0, 0))
      Print("Failed to create button ", BUTTON_LARGE);
   else
     {
      ObjectSetInteger(0, BUTTON_LARGE, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, BUTTON_LARGE, OBJPROP_XDISTANCE, x);
      ObjectSetInteger(0, BUTTON_LARGE, OBJPROP_YDISTANCE, y);
      ObjectSetInteger(0, BUTTON_LARGE, OBJPROP_XSIZE, btnWidth);
      ObjectSetInteger(0, BUTTON_LARGE, OBJPROP_YSIZE, ButtonHeight);
      ObjectSetString(0, BUTTON_LARGE, OBJPROP_TEXT, "Large Quarters");
     }
// Button for Smaller Quarters
   y += ButtonHeight + ButtonSpacing;
   if(!ObjectCreate(0, BUTTON_SMALL, OBJ_BUTTON, 0, 0, 0))
      Print("Failed to create button ", BUTTON_SMALL);
   else
     {
      ObjectSetInteger(0, BUTTON_SMALL, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, BUTTON_SMALL, OBJPROP_XDISTANCE, x);
      ObjectSetInteger(0, BUTTON_SMALL, OBJPROP_YDISTANCE, y);
      ObjectSetInteger(0, BUTTON_SMALL, OBJPROP_XSIZE, btnWidth);
      ObjectSetInteger(0, BUTTON_SMALL, OBJPROP_YSIZE, ButtonHeight);
      ObjectSetString(0, BUTTON_SMALL, OBJPROP_TEXT, "Smaller Quarters");
     }
// Button for Overshoot/Undershoot
   y += ButtonHeight + ButtonSpacing;
   if(!ObjectCreate(0, BUTTON_OVERSHOOT, OBJ_BUTTON, 0, 0, 0))
      Print("Failed to create button ", BUTTON_OVERSHOOT);
   else
     {
      ObjectSetInteger(0, BUTTON_OVERSHOOT, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, BUTTON_OVERSHOOT, OBJPROP_XDISTANCE, x);
      ObjectSetInteger(0, BUTTON_OVERSHOOT, OBJPROP_YDISTANCE, y);
      ObjectSetInteger(0, BUTTON_OVERSHOOT, OBJPROP_XSIZE, btnWidth);
      ObjectSetInteger(0, BUTTON_OVERSHOOT, OBJPROP_YSIZE, ButtonHeight);
      ObjectSetString(0, BUTTON_OVERSHOOT, OBJPROP_TEXT, "Overshoot/Undershoot");
     }
// Button for Trend Direction
   y += ButtonHeight + ButtonSpacing;
   if(!ObjectCreate(0, BUTTON_TREND, OBJ_BUTTON, 0, 0, 0))
      Print("Failed to create button ", BUTTON_TREND);
   else
     {
      ObjectSetInteger(0, BUTTON_TREND, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, BUTTON_TREND, OBJPROP_XDISTANCE, x);
      ObjectSetInteger(0, BUTTON_TREND, OBJPROP_YDISTANCE, y);
      ObjectSetInteger(0, BUTTON_TREND, OBJPROP_XSIZE, btnWidth);
      ObjectSetInteger(0, BUTTON_TREND, OBJPROP_YSIZE, ButtonHeight);
      ObjectSetString(0, BUTTON_TREND, OBJPROP_TEXT, "Trend Direction");
     }
   UpdateButtonColors();
  }
//+------------------------------------------------------------------+
//| Update button colors based on toggle state                       |
//+------------------------------------------------------------------+
void UpdateButtonColors()
  {
   color onColor  = clrGreen;
   color offColor = clrRed;
   ObjectSetInteger(0, BUTTON_LARGE,     OBJPROP_COLOR, g_DrawLargeQuarters  ? onColor : offColor);
   ObjectSetInteger(0, BUTTON_SMALL,     OBJPROP_COLOR, g_DrawSmallQuarters  ? onColor : offColor);
   ObjectSetInteger(0, BUTTON_OVERSHOOT, OBJPROP_COLOR, g_DrawOvershootAreas ? onColor : offColor);
   ObjectSetInteger(0, BUTTON_TREND,     OBJPROP_COLOR, g_DrawTrendDirection ? onColor : offColor);
  }
//+------------------------------------------------------------------+
//| Delete quarter lines                                             |
//+------------------------------------------------------------------+
void DeleteQuarterLines()
  {
   ObjectDelete(0, "MajorLower");
   ObjectDelete(0, "MajorUpper");
   for(int i = 1; i < 4; i++)
     {
      ObjectDelete(0, "LargeQuarter_" + IntegerToString(i));
      ObjectDelete(0, "Overshoot_" + IntegerToString(i) + "_up");
      ObjectDelete(0, "Undershoot_" + IntegerToString(i) + "_down");
     }
   for(int seg = 0; seg < 10; seg++)
     {
      for(int j = 1; j < 4; j++)
        {
         ObjectDelete(0, "SmallQuarter_" + IntegerToString(seg) + "_" + IntegerToString(j));
        }
     }
  }
//+------------------------------------------------------------------+
//| Delete trend commentary                                          |
//+------------------------------------------------------------------+
void DeleteTrendComment()
  {
   ObjectDelete(0, TREND_LABEL);
  }
//+------------------------------------------------------------------+
//| Update trend commentary                                          |
//+------------------------------------------------------------------+
void UpdateTrendComment()
  {
   double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   if(currentPrice == 0)
      return;
   double smaValue = 0.0;
   double buffer[];
   int handle = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_SMA, PRICE_CLOSE);
   if(handle != INVALID_HANDLE)
     {
      if(CopyBuffer(handle, 0, 1, 1, buffer) > 0)
         smaValue = buffer[0];
      IndicatorRelease(handle);
     }
   string trendComment;
   if(currentPrice > smaValue)
      trendComment = "Uptrend";
   else
      if(currentPrice < smaValue)
         trendComment = "Downtrend";
      else
         trendComment = "Sideways";

// Calculate the position for the commentary label below the Trend Direction button
   int trendButtonY = PanelY + 10 + 3 * (ButtonHeight + ButtonSpacing);
   int trendLabelY = trendButtonY + ButtonHeight + ButtonSpacing;
   int trendLabelX = PanelX + 10;

   if(ObjectFind(0, TREND_LABEL) == -1)
     {
      ObjectCreate(0, TREND_LABEL, OBJ_LABEL, 0, 0, 0);
      ObjectSetInteger(0, TREND_LABEL, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, TREND_LABEL, OBJPROP_XDISTANCE, trendLabelX);
      ObjectSetInteger(0, TREND_LABEL, OBJPROP_YDISTANCE, trendLabelY);
      ObjectSetInteger(0, TREND_LABEL, OBJPROP_COLOR, clrWhite);
      ObjectSetInteger(0, TREND_LABEL, OBJPROP_FONTSIZE, 14);
     }
   string txt = "Trend Direction: " + trendComment;
   ObjectSetString(0, TREND_LABEL, OBJPROP_TEXT, txt);
  }
//+------------------------------------------------------------------+
//| Draw horizontal line utility                                     |
//+------------------------------------------------------------------+
void DrawHorizontalLine(string name, double price, color lineColor, int width, ENUM_LINE_STYLE style)
  {
   if(ObjectFind(0, name) != -1)
      ObjectDelete(0, name);
   if(!ObjectCreate(0, name, OBJ_HLINE, 0, 0, price))
     {
      Print("Failed to create line: ", name);
      return;
     }
   ObjectSetInteger(0, name, OBJPROP_COLOR, lineColor);
   ObjectSetInteger(0, name, OBJPROP_STYLE, style);
   ObjectSetInteger(0, name, OBJPROP_WIDTH, width);
   ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, true);
  }
//+------------------------------------------------------------------+
//| Draw quarter lines based on toggle settings                      |
//+------------------------------------------------------------------+
void DrawQuarterLines()
  {
   DeleteQuarterLines();
   double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   if(currentPrice == 0)
      return;
   double lowerMajor = MathFloor(currentPrice / MajorStep) * MajorStep;
   double upperMajor = lowerMajor + MajorStep;
   DrawHorizontalLine("MajorLower", lowerMajor, MajorColor, MajorLineWidth, MajorLineStyle);
   DrawHorizontalLine("MajorUpper", upperMajor, MajorColor, MajorLineWidth, MajorLineStyle);
   if(g_DrawLargeQuarters)
     {
      double LQIncrement = MajorStep / 4.0;
      for(int i = 1; i < 4; i++)
        {
         double level = lowerMajor + i * LQIncrement;
         string objName = "LargeQuarter_" + IntegerToString(i);
         DrawHorizontalLine(objName, level, LargeQuarterColor, LargeQuarterLineWidth, LargeQuarterLineStyle);
         if(g_DrawOvershootAreas)
           {
            double smallQuarter = MajorStep / 40.0;
            DrawHorizontalLine("Overshoot_" + IntegerToString(i) + "_up", level + smallQuarter, OvershootColor, OvershootLineWidth, OvershootLineStyle);
            DrawHorizontalLine("Undershoot_" + IntegerToString(i) + "_down", level - smallQuarter, OvershootColor, OvershootLineWidth, OvershootLineStyle);
           }
        }
     }
   if(g_DrawSmallQuarters)
     {
      double segStep = MajorStep / 10.0;
      double smallQuarter = segStep / 4.0;
      for(int seg = 0; seg < 10; seg++)
        {
         double segStart = lowerMajor + seg * segStep;
         for(int j = 1; j < 4; j++)
           {
            double level = segStart + j * smallQuarter;
            string objName = "SmallQuarter_" + IntegerToString(seg) + "_" + IntegerToString(j);
            DrawHorizontalLine(objName, level, SmallQuarterColor, SmallQuarterLineWidth, SmallQuarterLineStyle);
           }
        }
     }
  }
//+------------------------------------------------------------------+


成果

本节将探讨该EA的实际运行效果与性能表现。以下GIF动图直观展示了其操作流程。当您将EA拖拽至欧元兑美元(EURUSD)图表时,会出现一个带按钮的控制面板。初始状态下,“大四分位线"与“上冲/下探”按钮文字呈现绿色,表示它们处于禁用状态。相反,“小四分位线" 与“趋势方向”按钮文字呈现红色,说明它们处于启用状态。点击任一按钮时,可以观察到对应价位线随激活状态在图表上显示或隐藏。需要注意的是,激活"趋势方向"按钮后,趋势评论会实时更新为"上涨趋势",准确反映当前市场状态。

四分位看板

下图清晰地展示了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

本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/17442

附加的文件 |
Quarters_Board.mq5 (14.84 KB)
时间演化旅行算法(TETA) 时间演化旅行算法(TETA)
这是我自己的算法。本文表阐述受平行宇宙和时间流概念启发的时间演化旅行算法(TETA)。该算法的基本思路是,尽管传统意义上的时间旅行是不可能的,但我们能够选择一系列事件来导致不同的现实。
MQL5自动化交易策略(第十一部分):开发多层级网格交易系统 MQL5自动化交易策略(第十一部分):开发多层级网格交易系统
在本文中,我们将使用MQL5开发一款多层级网格交易系统EA,重点探讨网格交易策略背后的架构与算法设计。我们将研究多层网格逻辑的实现方式以及应对不同市场状况的风险管理技术。最后,我们将提供详尽的解释和实用技巧,指导您完成自动化交易系统的构建、测试与优化。
开发多币种 EA 交易(第 21 部分):准备重要实验并优化代码 开发多币种 EA 交易(第 21 部分):准备重要实验并优化代码
为了取得进一步的进展,最好看看我们是否可以通过定期重新运行自动优化并生成新的 EA 来改进结果。关于使用参数优化的许多争论中的绊脚石是,在将盈利能力和回撤保持在指定水平的同时,所获得的参数在未来一段时间内可用于交易的时间有多长。有可能做到这一点吗?
市场模拟(第三部分):性能问题 市场模拟(第三部分):性能问题
我们经常需要后退一步,然后继续前进。在本文中,我们将展示所有必要的更改,以确保鼠标和 Chart Trade 指标不会中断。作为奖励,我们还将介绍未来将广泛使用的其他头文件中发生的其他更改。