对象在时间范围内的可见性

MetaTrader 5 用户了解对象特性对话框中的“显示”选项卡,在该选项卡中可以使用开关选择对象将在哪些时间范围显示或隐藏。特别是,可以临时在所有时间范围上完全隐藏对象。

MQL5 具有类似的程序特性 OBJPROP_TIMEFRAMES,该特性可控制对象在某个时间范围上的可见性。该特性值可以是特殊整型标志的任意组合:每个标志(常量)包含对应一个时间范围的位(见下表)。要设置/获取 OBJPROP_TIMEFRAMES 特性,请使用 ObjectSetInteger/ObjectGetInteger函数。

常量

在时间范围中的可见性

OBJ_NO_PERIODS

0

对象在所有时间范围中隐藏

OBJ_PERIOD_M1

0x00000001

M1

OBJ_PERIOD_M2

0x00000002

M2

OBJ_PERIOD_M3

0x00000004

M3

OBJ_PERIOD_M4

0x00000008

M4

OBJ_PERIOD_M5

0x00000010

M5

OBJ_PERIOD_M6

0x00000020

M6

OBJ_PERIOD_M10

0x00000040

M10

OBJ_PERIOD_M12

0x00000080

M12

OBJ_PERIOD_M15

0x00000100

M15

OBJ_PERIOD_M20

0x00000200

M20

OBJ_PERIOD_M30

0x00000400

M30

OBJ_PERIOD_H1

0x00000800

H1

OBJ_PERIOD_H2

0x00001000

H2

OBJ_PERIOD_H3

0x00002000

H3

OBJ_PERIOD_H4

0x00004000

H4

OBJ_PERIOD_H6

0x00008000

H6

OBJ_PERIOD_H8

0x00010000

H8

OBJ_PERIOD_H12

0x00020000

H12

OBJ_PERIOD_D1

0x00040000

D1

OBJ_PERIOD_W1

0x00080000

W1

OBJ_PERIOD_MN1

0x00100000

MN1

OBJ_ALL_PERIODS

0x001fffff

所有时间范围

这些标志可使用按位或运算符("|")进行组合,例如,标志 OBJ_PERIOD_M15 | OBJ_PERIOD_H4 的叠加表示对象将在 15 分钟和 4 小时时间范围上可见。

请注意,每个标志可通过如下方式来获得:左移 1,左移的位数等于常量在表中的编号。这样,当算法在多个时间范围而非特定某个时间范围下运行时,可以更轻松地动态生成标志。

我们将在测试脚本ObjectTimeframes.mq5中使用这一功能。该脚本的任务是在图表上创建大量带有时间范围名称的大型文本标签,且每个标题仅在对应的时间范围中显示。例如,大型标签 "D1" 将仅在日线图上可见,而切换到 H4 时,我们会看到 "H4"。

还实现了一个简单的辅助函数,用于获取不带 "PERIOD_" 前缀的时间范围简称。

string GetPeriodName(const int tf)
{
   const static int PERIOD_ = StringLen("PERIOD_");
   return StringSubstr(EnumToString((ENUM_TIMEFRAMES)tf), PERIOD_);
}

要从 ENUM_TIMEFRAMES 枚举中获取所有时间范围的列表,我们将使用 枚举转换章节介绍的 EnumToArray 函数。

#include "ObjectPrefix.mqh"
#include <MQL5Book/EnumToArray.mqh>
 
void OnStart()
{
   ENUM_TIMEFRAMES tf = 0;
   int values[];
   const int n = EnumToArray(tfvalues0USHORT_MAX);
   ...

所有标签将在脚本启动时显示在窗口中央。脚本执行完毕后调整窗口大小,会导致已创建的标题不再居中。这是因为 MQL5 仅支持将对象锚定至窗口角点,不支持锚定到中心位置。如果希望自动保持对象的位置,应当在指标中实现类似算法,并对 窗口大小调整事件做出响应。或者,我们可以将标签显示在某个角落,例如右下角。

   const int centerX = (int)ChartGetInteger(0CHART_WIDTH_IN_PIXELS) / 2;
   const int centerY = (int)ChartGetInteger(0CHART_HEIGHT_IN_PIXELS) / 2;
   ...

在遍历时间范围的循环中,我们将每个时间范围创建一个 OBJ_LABEL 对象,并将其放置在窗口中央并以对象中心为锚点。

   for(int i = 1i < n; ++i)
   {
      // create and setup text label for each timeframe
      const string name = ObjNamePrefix + (string)i;
      ObjectCreate(0nameOBJ_LABEL000);
      ObjectSetInteger(0nameOBJPROP_XDISTANCEcenterX);
      ObjectSetInteger(0nameOBJPROP_YDISTANCEcenterY);
      ObjectSetInteger(0nameOBJPROP_ANCHORANCHOR_CENTER);
      ...

接下来,设置文本(时间范围名称)、大号字体大小、灰色以及背景显示特性。

      ObjectSetString(0nameOBJPROP_TEXTGetPeriodName(values[i]));
      ObjectSetInteger(0nameOBJPROP_FONTSIZEfmin(centerYcenterX));
      ObjectSetInteger(0nameOBJPROP_COLORclrLightGray);
      ObjectSetInteger(0nameOBJPROP_BACKtrue);
      ...

最后,为第 i个时间范围生成正确的可见性标志,并将其写入 OBJPROP_TIMEFRAMES 特性。

      const int flag = 1 << (i - 1);
      ObjectSetInteger(0nameOBJPROP_TIMEFRAMESflag);
   }

查看切换时间范围时图表上的变化。

带时间范围名称的标签

带时间范围名称的标签

如果打开Object List对话框并在列表中启用All对象,可以轻松确认已为所有时间范围生成标签,并检查其可见性标志。

要移除对象,可运行 ObjectCleanup1.mq5脚本。