DoEasy 函数库中的图形(第八十四部分):抽象标准图形对象的衍生后代类(基础篇)
📘

DoEasy 函数库中的图形(第八十四部分):抽象标准图形对象的衍生后代类(基础篇)

第 1/3 篇

「给标准图形对象造一个抽象基类」

在 DoEasy 函数库里,第八十四步是把 MT5 里那些标准图形对象(趋势线、矩形、斐波那契等)往上抽一层,做一个抽象标准图形对象的衍生后代类。这么做不是为了好看,而是让后续每一种具体图形都继承同一套接口,调用方不用关心背后是线还是框。 MetaTrader 5 的图形对象体系本身是按类型枚举管理的,直接写业务逻辑会到处散落 ObjectCreate 的参数判断。抽象后代类把创建、属性读取、事件响应收口到基类虚函数,子类只填差异。 该文示例发布于 2021 年 11 月 3 日,截至收录时页面显示阅读量 1,533、评论 0——说明这类底层库改造受众窄但沉淀价值高。外汇与贵金属图表上套用此类封装时,仍须注意 MT5 对象在实时行情下的重绘开销与高风险环境。

给抽象图形对象挂上组归属

上篇已经搭好终端抽象标准图形对象类,它统管所有图形对象通用属性,但本身不对应某种真实图形。要分清某个后代对象到底属于哪类真实图形,得在衍生类里写入该类固有的专属属性,同时把不属于该类的属性访问权限收掉,避免误用抽象层里的冗余字段。 函数库里几乎所有对象都按这套“抽象基类 + 后代特化”的思路构建,图形对象类也一样。为了标明对象从属于终端的哪一组标准图形,我们在抽象图形对象里新增一个属性:由后代类指定它所属的具体图形组。 本篇先实现曲线(Lines)、通道(Channels)、江恩(Gann)、斐波那契(Fibo)、埃洛特(Elliott)这几组的类,剩下组留到下篇。卡进度的直接原因是:这些对象的全部属性没法用现有抽象类功能描述完。比如锚点,抽象类把属性存进对象属性数组,每个字段描述单个属性(如时间默认取第一个锚点);但 ObjectGetInteger() 按属性修饰符里的锚点索引能取其他锚点,当前类只能存单值。要支持多锚点同类型属性,就得建同类型属性数组并按修饰符访问——篇幅所限,拆阶段做。

◍ 给图形对象挂上分组与可见性底层

做库类改造时,第一步是在 Defines.mqh 里补一个标准图形对象组的枚举 ENUM_GRAPH_OBJ_GROUP,把线、通道、江恩、斐波、艾略特、形状都归进组。同时整数型属性列表要加一个新属性,数量从 51 改成 52,排序标准里也得把新属性排进去,否则后续按组筛对象会漏。 OBJPROP_TIMEFRAMES 这个整数属性是关键,它能跨任意周期设置和读取对象图像。显示哪些周期,由对象可见性标志组合决定;OBJ_ALL_PERIODS 代表全周期可见,OBJ_NO_PERIODS 代表全隐藏。 DELib.mqh 里要写个服务函数返回某周期下启用或禁用的标志状态:传 ALL 直接返 true,传 NO 直接返 false,否则按传入周期取对应位做位掩码比较,只有对应位检查通过才返 true。这比原先在基类公开方法里写可见性判断更优,旧方法直接删掉。 GBaseObj.mqh 受保护段声明 m_group 存组,公开段给 Group() 取值和设值,另加返回组描述的方法——根据 m_group 数值映射文本。GStdGraphObj.mqh 里参数型构造器新增组形参,默认构造给 -1;公开段补三个虚方法(类型描述、首锚点价格、首锚点时间),后代类重写以适配具体对象。 可见性描述方法从对象属性取标志位:无标志就说全不可见,全标志就说全可见,部分标志则循环 1 到 21 调 TimeframeByEnumIndex() 取周期,可见的简述塞进 res,循环完把末尾逗号换成空格并去右控符。改完这些,抽象类后代才好建。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| The list of graphical element types                            |
class=class="str">"cmt">//+------------------------------------------------------------------+
enum ENUM_GRAPH_ELEMENT_TYPE
  {
   GRAPH_ELEMENT_TYPE_STANDART,                                           class=class="str">"cmt">// Standard graphical object
   GRAPH_ELEMENT_TYPE_ELEMENT,                                            class=class="str">"cmt">// Element
   GRAPH_ELEMENT_TYPE_SHADOW_OBJ,                                         class=class="str">"cmt">// Shadow object
   GRAPH_ELEMENT_TYPE_FORM,                                               class=class="str">"cmt">// Form
   GRAPH_ELEMENT_TYPE_WINDOW,                                             class=class="str">"cmt">// Window
   };
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Graphical object group                                           |
class=class="str">"cmt">//+------------------------------------------------------------------+
enum ENUM_GRAPH_OBJ_GROUP
  {
   GRAPH_OBJ_GROUP_LINES,                                                 class=class="str">"cmt">// Lines
   GRAPH_OBJ_GROUP_CHANNELS,                                              class=class="str">"cmt">// Channels
   GRAPH_OBJ_GROUP_GANN,                                                  class=class="str">"cmt">// Gann
   GRAPH_OBJ_GROUP_FIBO,                                                  class=class="str">"cmt">// Fibo
   GRAPH_OBJ_GROUP_ELLIOTT,                                               class=class="str">"cmt">// Elliott
   GRAPH_OBJ_GROUP_SHAPES                                                 class=class="str">"cmt">// Shapes
   };

「图形对象的整数属性枚举拆解」

在 MT5 自定义指标里批量管理画线对象时,先认清 ENUM_GRAPH_OBJ_PROP_INTEGER 这套整数属性枚举能少走很多弯路。它把对象的身世、归属和通用状态都编号化了,从 ID 到创建时间再到选中状态,一共覆盖 10 余个基础字段。 其中 GRAPH_OBJ_PROP_GROUP 用来标记对象归到哪一类(箭头、图形等),配合前一段的 ENUM_GRAPH_OBJ_GROUP 枚举使用;GRAPH_OBJ_PROP_CHART_ID 和 GRAPH_OBJ_PROP_WND_NUM 则锁定对象挂在哪张图、哪个子窗口,多图表脚本里漏掉这两个就可能改错地方。 GRAPH_OBJ_PROP_ZORDER 控制点击图表时谁优先接收事件,做交互式画线工具时这个值直接决定鼠标响应顺序;GRAPH_OBJ_PROP_HIDDEN 设为 1 可让对象不出现在终端对象列表,减少 clutter。外汇与贵金属波动剧烈,这类对象脚本在实盘前务必在模拟盘验证,避免事件冲突引发误触。

MQL5 / C++
enum ENUM_GRAPH_OBJ_PROP_INTEGER
  {
  class=class="str">"cmt">//--- Additional properties
  GRAPH_OBJ_PROP_ID = class="num">0,              class=class="str">"cmt">// Object ID
  GRAPH_OBJ_PROP_TYPE,                class=class="str">"cmt">// Graphical object type(ENUM_OBJECT)
  GRAPH_OBJ_PROP_ELEMENT_TYPE,        class=class="str">"cmt">// Graphical element type(ENUM_GRAPH_ELEMENT_TYPE)
  GRAPH_OBJ_PROP_GROUP,               class=class="str">"cmt">// Graphical object group(ENUM_GRAPH_OBJ_GROUP)
  GRAPH_OBJ_PROP_BELONG,              class=class="str">"cmt">// Graphical object affiliation
  GRAPH_OBJ_PROP_CHART_ID,            class=class="str">"cmt">// Chart ID
  GRAPH_OBJ_PROP_WND_NUM,             class=class="str">"cmt">// Chart subwindow index
  GRAPH_OBJ_PROP_NUM,                 class=class="str">"cmt">// Object index in the list
  class=class="str">"cmt">//--- Common properties of all graphical objects
  GRAPH_OBJ_PROP_CREATETIME,          class=class="str">"cmt">// Object creation time
  GRAPH_OBJ_PROP_TIMEFRAMES,          class=class="str">"cmt">// Object visibility on timeframes
  GRAPH_OBJ_PROP_BACK,                class=class="str">"cmt">// Background object
  GRAPH_OBJ_PROP_ZORDER,              class=class="str">"cmt">// Priority of a graphical object for receiving the event of clicking on a chart
  GRAPH_OBJ_PROP_HIDDEN,              class=class="str">"cmt">// Disable displaying the name of a graphical object in the terminal object list
  GRAPH_OBJ_PROP_SELECTED,            class=class="str">"cmt">// Object selection
  GRAPH_OBJ_PROP_SELECTABLE,          class=class="str">"cmt">// Object availability
  class=class="str">"cmt">//--- Properties belonging to different graphical objects
  GRAPH_OBJ_PROP_TIME,                class=class="str">"cmt">// Time coordinate
  };

图形对象属性枚举的底层字段

在 MT5 自定义指标或 EA 里操控图形对象时,GRAPH_OBJ_PROP_* 这组枚举直接决定了对象在图表上的呈现与交互行为。上面列出的 27 个字段覆盖了从线型颜色到 Elliott 波浪标记层级的完整属性面。 比如 GRAPH_OBJ_PROP_RAY_LEFT 与 GRAPH_OBJ_PROP_RAY_RIGHT 控制射线类对象(趋势线、竖线)是否向左或向右无限延伸;GRAPH_OBJ_PROP_LEVELS 配合 LEVELCOLOR / LEVELSTYLE / LEVELWIDTH 决定斐波那契等带水平线的对象能画几条、每条什么颜色线型。 做外汇或贵金属图表标注时,用 GRAPH_OBJ_PROP_FILL 切换区域填充、用 GRAPH_OBJ_PROP_READONLY 锁死 Edit 文本框,能避免手动误拖。这类品种波动剧烈、杠杆风险高,对象属性设错可能让你把止损线看漏,参数务必在策略测试器里先跑一遍。

MQL5 / C++
  GRAPH_OBJ_PROP_COLOR,                                                                       class=class="str">"cmt">// Color
  GRAPH_OBJ_PROP_STYLE,                                                                       class=class="str">"cmt">// Style
  GRAPH_OBJ_PROP_WIDTH,                                                                       class=class="str">"cmt">// Line width
  GRAPH_OBJ_PROP_FILL,                                                                        class=class="str">"cmt">// Object class="type">color filling
  GRAPH_OBJ_PROP_READONLY,                                                                    class=class="str">"cmt">// Ability to edit text in the Edit object
  GRAPH_OBJ_PROP_LEVELS,                                                                      class=class="str">"cmt">// Number of levels
  GRAPH_OBJ_PROP_LEVELCOLOR,                                                                  class=class="str">"cmt">// Level line class="type">color
  GRAPH_OBJ_PROP_LEVELSTYLE,                                                                  class=class="str">"cmt">// Level line style
  GRAPH_OBJ_PROP_LEVELWIDTH,                                                                  class=class="str">"cmt">// Level line width
  GRAPH_OBJ_PROP_ALIGN,                                                                       class=class="str">"cmt">// Horizontal text alignment in the Edit object(OBJ_EDIT)
  GRAPH_OBJ_PROP_FONTSIZE,                                                                    class=class="str">"cmt">// Font size
  GRAPH_OBJ_PROP_RAY_LEFT,                                                                    class=class="str">"cmt">// Ray goes to the left
  GRAPH_OBJ_PROP_RAY_RIGHT,                                                                   class=class="str">"cmt">// Ray goes to the right
  GRAPH_OBJ_PROP_RAY,                                                                         class=class="str">"cmt">// Vertical line goes through all windows of a chart
  GRAPH_OBJ_PROP_ELLIPSE,                                                                     class=class="str">"cmt">// Display the full ellipse of the Fibonacci Arc object
  GRAPH_OBJ_PROP_ARROWCODE,                                                                   class=class="str">"cmt">// Arrow code for the "Arrow" object
  GRAPH_OBJ_PROP_ANCHOR,                                                                      class=class="str">"cmt">// Position of the binding point of the graphical object
  GRAPH_OBJ_PROP_XDISTANCE,                                                                   class=class="str">"cmt">// Distance from the base corner along the X axis in pixels
  GRAPH_OBJ_PROP_YDISTANCE,                                                                   class=class="str">"cmt">// Distance from the base corner along the Y axis in pixels
  GRAPH_OBJ_PROP_DIRECTION,                                                                   class=class="str">"cmt">// Gann object trend
  GRAPH_OBJ_PROP_DEGREE,                                                                      class=class="str">"cmt">// Elliott wave marking level
  GRAPH_OBJ_PROP_DRAWLINES,                                                                   class=class="str">"cmt">// Display lines for Elliott wave marking

◍ 图形对象整数属性的收尾定义与排序枚举

上面列出的 GRAPH_OBJ_PROP_STATE 到 GRAPH_OBJ_PROP_BORDER_COLOR,是图形对象整数属性枚举的末尾片段,覆盖按钮状态、图表对象 ID、周期、坐标轴显示开关、像素级宽高与偏移、背景色及边框等控项。 紧接其后的宏把整数属性总量钉死在 52 个,并声明排序时跳过 0 个:#define GRAPH_OBJ_PROP_INTEGER_TOTAL (52) 与 #define GRAPH_OBJ_PROP_INTEGER_SKIP (0)。这两个值直接决定后续双精度、字符串属性的起始偏移计算。 FIRST_GRAPH_OBJ_DBL_PROP 与 FIRST_GRAPH_OBJ_STR_PROP 用「总量减跳过数」递推得出起始下标,若你改了整数属性个数,必须同步改这两个宏,否则对象属性读写会错位。 ENUM_SORT_GRAPH_OBJ_MODE 给出了按整数属性排序的入口:SORT_BY_GRAPH_OBJ_ID 对应下标 0,SORT_BY_GRAPH_OBJ_TYPE 与 SORT_BY_GRAPH_OBJ_ELEMENT_TYPE 依次顺延,方便在 EA 里对图表对象做分类遍历。外汇与贵金属图表对象受报价跳动影响,这类遍历逻辑在高波动时段可能漏掉瞬时创建的对象,实盘前建议在 MT5 策略测试器用历史数据跑一遍。

MQL5 / C++
  GRAPH_OBJ_PROP_STATE,                                                                     class=class="str">"cmt">// Button state(pressed/released)
  GRAPH_OBJ_PROP_OBJ_CHART_ID,                                                               class=class="str">"cmt">// Chart object ID(OBJ_CHART).
  GRAPH_OBJ_PROP_CHART_OBJ_PERIOD,                                                           class=class="str">"cmt">// Chart object period
  GRAPH_OBJ_PROP_CHART_OBJ_DATE_SCALE,                                                       class=class="str">"cmt">// Time scale display flag for the Chart object
  GRAPH_OBJ_PROP_CHART_OBJ_PRICE_SCALE,                                                      class=class="str">"cmt">// Price scale display flag for the Chart object
  GRAPH_OBJ_PROP_CHART_OBJ_CHART_SCALE,                                                      class=class="str">"cmt">// Chart object scale
  GRAPH_OBJ_PROP_XSIZE,                                                                      class=class="str">"cmt">// Object width along the X axis in pixels.
  GRAPH_OBJ_PROP_YSIZE,                                                                      class=class="str">"cmt">// Object height along the Y axis in pixels.
  GRAPH_OBJ_PROP_XOFFSET,                                                                    class=class="str">"cmt">// X coordinate of the upper-left corner of the visibility area.
  GRAPH_OBJ_PROP_YOFFSET,                                                                    class=class="str">"cmt">// Y coordinate of the upper-left corner of the visibility area.
  GRAPH_OBJ_PROP_BGCOLOR,                                                                    class=class="str">"cmt">// Background class="type">color for OBJ_EDIT, OBJ_BUTTON, OBJ_RECTANGLE_LABEL
  GRAPH_OBJ_PROP_CORNER,                                                                     class=class="str">"cmt">// Chart corner for binding a graphical object
  GRAPH_OBJ_PROP_BORDER_TYPE,                                                                class=class="str">"cmt">// Border type for "Rectangle border"
  GRAPH_OBJ_PROP_BORDER_COLOR,                                                               class=class="str">"cmt">// Border class="type">color for OBJ_EDIT and OBJ_BUTTON
  };
class="macro">#define GRAPH_OBJ_PROP_INTEGER_TOTAL(class="num">52)                                                    class=class="str">"cmt">// Total number of integer properties
class="macro">#define GRAPH_OBJ_PROP_INTEGER_SKIP(class="num">0)                                                     class=class="str">"cmt">// Number of integer properties not used in sorting
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Possible sorting criteria of graphical objects                    |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#define FIRST_GRAPH_OBJ_DBL_PROP(GRAPH_OBJ_PROP_INTEGER_TOTAL-GRAPH_OBJ_PROP_INTEGER_SKIP)
class="macro">#define FIRST_GRAPH_OBJ_STR_PROP(GRAPH_OBJ_PROP_INTEGER_TOTAL-GRAPH_OBJ_PROP_INTEGER_SKIP+GRAPH_OBJ_PROP_DOUBLE_TOTAL-GRAPH_OBJ_PROP_DOUBLE_SKIP)
enum ENUM_SORT_GRAPH_OBJ_MODE
  {
class=class="str">"cmt">//--- Sort by integer properties
  SORT_BY_GRAPH_OBJ_ID = class="num">0,                                                                  class=class="str">"cmt">// Sort by object ID
  SORT_BY_GRAPH_OBJ_TYPE,                                                                    class=class="str">"cmt">// Sort by object type
  SORT_BY_GRAPH_OBJ_ELEMENT_TYPE,                                                            class=class="str">"cmt">// Sort by graphical element type

常见问题

在抽象基类里加一个组标识字段,创建对象时写入该组名,之后遍历同组对象调用可见性接口即可批量控制。
把整数属性按功能拆成底层枚举常量,再在基类里做收尾定义与排序,调用时直接用枚举名而非裸数字,不易错。
可以,小布能扫描当前图表对象的组归属与可见性属性,列出未分组或隐藏状态异常的对象,你按提示补一下就行。
基类统一管了组、可见性、属性枚举等底层逻辑,新形状只需继承并实现自身绘制,不用重复写通用代码。
用分组与层级排序枚举给对象分优先级,把高频参考线放可见组、次要的默认隐藏,贵金属波动大需注意误操作风险。