DoEasy 函数库中的图形(第九十三部分):准备创建复合图形对象的功能(基础篇)
「给复合图形对象打从属坐标的底子」
在 DoEasy 函数库里做复合图形对象,第一步不是画形状,而是先把“从属坐标”这套类结构搭稳。对象如果只挂绝对坐标,后面做多元素联动会反复踩坑。 这一版改动集中在库类的坐标描述层:新增用于指定对象从属坐标的类,让子对象能相对父对象定位。MT5 里这类结构若缺失,拖一个主控图形时子图形容易脱节。 原文示例发布于 2022-04-08 13:01,截至收录时页面阅读量 1,023,说明这套底层改造关注者不多但够硬核。外汇与贵金属图表用复合对象做层级标记时波动风险高,坐标从属逻辑错了会误读价位。 开 MT5 把库里坐标类先单测一遍:建一个父矩形、挂两个从属标签,移动父体看子体是否跟随。能跟,再往下写复合创建功能。
把 44 个原生图形对象拼成复合工具
MT5 终端自带 44 种分析工具,但不少老用户仍觉得不够用。MQL5 的突破口在于:允许把这些原生图形对象捆绑成多层嵌套的复合对象,而不是局限于单一画线。 一个复合对象由一个基准图形对象打底,再挂一组从属图形对象。基准对象负责统管从属对象的属性,而从属对象在加载时只记录相对基准的 X/Y 坐标。关键点在于,从属坐标不一定取基准的某个锚点——比如一条趋势线,从属对象可以拿点 0 和点 1 的 X 坐标做平均来定位,基准对象的整张属性表都能拿去算坐标。 嵌套还能继续往下走:某个从属对象自身也能当别的图形的基准。这样不同组合可以一层层叠出自定义分析结构。更实用的是,除了在代码里写死挂载关系,还能在图表上把一个对象拖到另一个上面,按视觉吸附点实时附着,之后随时改锚点。 本篇先落地两件事:给标准图形对象加一个「已扩展」标记属性,再写一个专门存基准坐标关系、算从属坐标的类。外汇和贵金属波动剧烈,这类自定义结构只降低绘图成本,不替代风控。
◍ 改进库类
在 \MQL5\Include\DoEasy\ Defines.mqh 中的图形元素类型枚举里, 添加另一个种类 — 扩展标准图形对象: 在图形对象整数型属性的枚举中, 添加属性 (基准图形对象 ID),并 将整数型属性的数量从 54 增加到 55 : 在每个从属对象中设置基准对象 ID(从 1 开始)。 属性为零值表示该对象未附于到任何其它对象,且不是从属对象。 在图形对象的字符串型属性枚举中, 添加属性 — 基准图形对象的名称, 将字符串型属性的数量从 7 增加到 8 : 在可能的图形对象排序标准的枚举中 加入新常量 (对应于上面添加的新图形对象属性): 现在我们可以根据相应的属性选择对象,按它们排序,并创建拥有类似属性的对象列表。 在 \MQL5\Include\DoEasy\ Data.mqh 中, 添加函数库新消息索引 : ... ... ... ... 及 与新增索引相对应的消息 : ... ... ... ... 扩展的标准图形对象基于标准图形对象。 为了让对象能够扩展,为其设置扩展图形对象属性。 它将调用为处理扩展的标准图形对象而创建的功能,方法是将从属对象添加到其列表中,并对其进行管控。 我们已拥有所有标准图形对象的类,它们是抽象标准图形对象类的衍生后代。 在此,我们需要做的就是指定一个标志,标记正在创建的是扩展图形对象,而非常规图形对象。 这样的一个对象是以编程方式创建的,故此对象的从属属性应设置为“对象属于程序”(手动创建对象的属性默认设置)。 标准扩展图形对象类型的设置方式相同。 所有这些都是根据图形对象的构造函数在创建期间传递给它的标志值来完成的。 除了这些改进,我们还需要在返回表示支持该对象属性标志的方法里设置新的图形对象属性。 由于所有这些变更对于位于 \MQL5\Include\DoEasy\Objects\Graph\ Standard\ 中的所有标准图形对象类都相同,那么我考虑只修改 GStdArrowBuyObj.mqh 的实现作为一个例子。 类构造函数会 接收扩展标准图形对象的标志 。 依赖标志值 , 我们应该明确这是否是一个标准图形对象 , 或是标准扩展图形对象 ,以及 对象是否由手动创建 , 或由程序生成 : 在返回指示对象可支持的 整数型 和 字符串型 属性标志的方法中, 添加上面实现的新属性 : 这些更改应在 \MQL5\Include\DoEasy\Objects\Graph\ Standard\ 中的所有文件中实现。 这项工作已经完成。 您可以在文后附件中看到所有的改进。 在实现了这些改进之后,新属性可由标准图形对象类的所有对象进行处理,因此我们能够以最高的效率处理这些属性,因为每个这样的对象现在都拥有支持这些新属性的标志。 在 \MQL5\Include\DoEasy\Objects\Graph\ GBaseObj.mqh 基准图形对象类文件里,也就是说,在返回图形元素类型描述的方法中, 添加“扩展标准图形对象”图形元素类型的验证,从而我们能够正确显示图形对象描述: [CODE] <span class="comment">//+------------------------------------------------------------------+</span> <span class="comment">//| The list of graphical element types &nb
「图形对象属性的枚举切片」
在 MT5 的图表对象体系里,属性并非零散常量,而是被收进一组连续枚举值。下面这段枚举切片,覆盖了从对象索引、变更历史到分组标识的基础字段,以及所有图形对象共有的创建时间、 timeframe 可见性、背景层级等通用属性。 通用部分里有几个容易被忽略但影响交互的:GRAPH_OBJ_PROP_ZORDER 决定图表点击事件优先派发给哪个对象,GRAPH_OBJ_PROP_HIDDEN 控制是否在终端对象列表暴露名称,GRAPH_OBJ_PROP_SELECTABLE 与 SELECTED 则分别管“能否选中”和“当前是否被选中”。 再往下是跨类型对象各自持有的属性,例如 TIME 坐标、COLOR、STYLE、WIDTH,以及填充 FILL、文本编辑 READONLY、多水平线 LEVELS 系列(颜色/样式/宽度)、EDIT 控件的 ALIGN 与 FONTSIZE。写 EA 或指标时,按这组枚举去 ObjectGetInteger/ObjectGetDouble 取参,能少踩很多“属性不存在”的坑。 外汇与贵金属市场波动剧烈、杠杆风险高,用代码批量管理图形对象时,建议先在模拟盘验证属性读写逻辑。
GRAPH_OBJ_PROP_NUM, class=class="str">"cmt">// Object index in the list GRAPH_OBJ_PROP_CHANGE_HISTORY, class=class="str">"cmt">// Flag of storing the change history GRAPH_OBJ_PROP_GROUP, class=class="str">"cmt">// Group of objects the graphical object belongs to 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 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">class="kw">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">class="kw">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
图形对象属性枚举的关键片段
在 MT5 的 MQL5 图形对象体系里,GRAPH_OBJ_PROP_* 这组枚举决定了对象能调哪些属性。上面这段截取了从射线延伸到内嵌图表控件的一批属性常量,覆盖了射线方向、斐波那契弧椭圆显示、箭头代码、锚点像素偏移等。 比如 GRAPH_OBJ_PROP_RAY_LEFT 和 GRAPH_OBJ_PROP_RAY_RIGHT 分别控制射线向左或向右无限延伸;GRAPH_OBJ_PROP_XDISTANCE / YDISTANCE 则是以像素为单位、从基准角沿 X/Y 轴量出的距离,做标签定位时很实用。 到了 OBJ_CHART 类对象,GRAPH_OBJ_PROP_CHART_OBJ_PERIOD 能单独设内嵌图表周期,GRAPH_OBJ_PROP_CHART_OBJ_DATE_SCALE 控制时间轴是否显示。最后 GRAPH_OBJ_PROP_XSIZE / YSIZE 直接以像素定宽高,GRAPH_OBJ_PROP_BGCOLOR 管编辑框、按钮、矩形标签的底色。 开 MT5 按 F4 进 MetaEditor,搜 GRAPH_OBJ_PROP_BGCOLOR 就能看到完整枚举定义,复制下面片段可对照各常量注释。
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, class=class="str">"cmt">// Button state(pressed/released) GRAPH_OBJ_PROP_CHART_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">class="kw">color for OBJ_EDIT, OBJ_BUTTON, OBJ_RECTANGLE_LABEL
◍ 图形对象的属性枚举与排序基准
在 MT5 自定义指标里批量管理画线对象时,先把属性归类能少写很多判断分支。源码把图形对象属性拆成整数、双精度、字符串三组枚举,字符串组起点靠偏移量算出来:GRAPH_OBJ_PROP_NAME 的值 = 整数属性总数(55) + 双精度属性总数,后面再顺排 BASE_NAME、TEXT、TOOLTIP 等 8 个成员,GRAPH_OBJ_PROP_STRING_TOTAL 宏固定为 8。 整数属性里 GRAPH_OBJ_PROP_CORNER 决定对象锚定哪个图角,GRAPH_OBJ_PROP_BORDER_TYPE 和 BORDER_COLOR 分别管矩形边框类型与按钮/编辑框边框色,这些在拖拽面板控件时直接影响交互位置。 排序对象用 ENUM_SORT_GRAPH_OBJ_MODE 枚举,FIRST_GRAPH_OBJ_STR_PROP 宏 = 55 - 0 + 双精度总数 - 跳过数,以此把字符串属性排到整数、双精度之后;SORT_BY_GRAPH_OBJ_ID 与 SORT_BY_GRAPH_OBJ_BASE_ID 都按 ID 归序,前者用对象自身 ID,后者用基类 ID,外汇和贵金属图表上对象一多(可能超百个),靠这两种模式能稳定避免重叠错乱。开 MT5 把这段枚举贴进 EA 头文件,改 GRAPH_OBJ_PROP_STRING_TOTAL 看编译器报错位置,就能验证偏移算法是否如预期。
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">class="kw">color for OBJ_EDIT and OBJ_BUTTON }; class="macro">#define GRAPH_OBJ_PROP_INTEGER_TOTAL(class="num">55) 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">//| String properties of a standard graphical object | class=class="str">"cmt">//+------------------------------------------------------------------+ enum ENUM_GRAPH_OBJ_PROP_STRING { GRAPH_OBJ_PROP_NAME = (GRAPH_OBJ_PROP_INTEGER_TOTAL+GRAPH_OBJ_PROP_DOUBLE_TOTAL), class=class="str">"cmt">// Object name GRAPH_OBJ_PROP_BASE_NAME, class=class="str">"cmt">// Base object name GRAPH_OBJ_PROP_TEXT, class=class="str">"cmt">// Object description(text contained in the object) GRAPH_OBJ_PROP_TOOLTIP, class=class="str">"cmt">// Tooltip text GRAPH_OBJ_PROP_LEVELTEXT, class=class="str">"cmt">// Level description GRAPH_OBJ_PROP_FONT, class=class="str">"cmt">// Font GRAPH_OBJ_PROP_BMPFILE, class=class="str">"cmt">// BMP file name for the "Bitmap Level" object GRAPH_OBJ_PROP_CHART_OBJ_SYMBOL, class=class="str">"cmt">// Symbol for the Chart object }; class="macro">#define GRAPH_OBJ_PROP_STRING_TOTAL(class="num">8) class=class="str">"cmt">// Total number of class="type">class="kw">string properties 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_BASE_ID, class=class="str">"cmt">// Sort by object ID SORT_BY_GRAPH_OBJ_TYPE, class=class="str">"cmt">// Sort by object type