DoEasy 函数库中的图形(第八十四部分):抽象标准图形对象的衍生后代类(基础篇)
「给标准图形对象造一个抽象基类」
在 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,循环完把末尾逗号换成空格并去右控符。改完这些,抽象类后代才好建。
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。外汇与贵金属波动剧烈,这类对象脚本在实盘前务必在模拟盘验证,避免事件冲突引发误触。
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 文本框,能避免手动误拖。这类品种波动剧烈、杠杆风险高,对象属性设错可能让你把止损线看漏,参数务必在策略测试器里先跑一遍。
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 策略测试器用历史数据跑一遍。
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