DoEasy 函数库中的图形(第八十四部分):抽象标准图形对象的衍生后代类·进阶篇
(2/3)·抽象基类只是壳,真正决定图形对象能暴露什么属性的,是衍生后代类的组归属设计
◍ 图形对象排序枚举到底覆盖了哪些维度
在 MT5 的 ObjectsTotal / ObjectGetInteger 体系里,图形对象并不是无序堆在图表上的。系统提供了一组 SORT_BY_GRAPH_OBJ_* 枚举,用来决定你用 ObjectsTotal(0, 0, sort_type) 取对象列表时,底层按什么字段排。 这组枚举从归属关系一直细到视觉属性:SORT_BY_GRAPH_OBJ_GROUP 按对象组排,SORT_BY_GRAPH_OBJ_BELONG 按所属元素排,SORT_BY_GRAPH_OBJ_CHART_ID 按图表 ID 排,SORT_BY_GRAPH_OBJ_WND_NUM 按子窗口序号排。 时间类维度有 SORT_BY_GRAPH_OBJ_CREATETIME(创建时间)和 SORT_BY_GRAPH_OBJ_TIME(时间坐标),交互类则有 SORT_BY_GRAPH_OBJ_ZORDER(点击接收优先级)、SORT_BY_GRAPH_OBJ_SELECTED(是否被选中)、SORT_BY_GRAPH_OBJ_SELECTABLE(是否可选中)。 纯外观维度也全给了出口:COLOR / STYLE / WIDTH / FILL / LEVELCOLOR / LEVELSTYLE,分别对应颜色、线型、线宽、填充、水平线颜色和水平线型。写 EA 批量清理对象或遍历画线时,选错排序类型可能让你漏掉后台对象,开 MT5 按 F4 把下面枚举贴进调试脚本就能验证排序差异。
SORT_BY_GRAPH_OBJ_GROUP, class=class="str">"cmt">// Sort by a graphical object group SORT_BY_GRAPH_OBJ_BELONG, class=class="str">"cmt">// Sort by a graphical element affiliation SORT_BY_GRAPH_OBJ_CHART_ID, class=class="str">"cmt">// Sort by chart ID SORT_BY_GRAPH_OBJ_WND_NUM, class=class="str">"cmt">// Sort by chart subwindow index SORT_BY_GRAPH_OBJ_NUM, class=class="str">"cmt">// Sort by object index in the list SORT_BY_GRAPH_OBJ_CREATETIME, class=class="str">"cmt">// Sort by object creation time SORT_BY_GRAPH_OBJ_TIMEFRAMES, class=class="str">"cmt">// Sort by object visibility on timeframes SORT_BY_GRAPH_OBJ_BACK, class=class="str">"cmt">// Sort by the "Background object" class="kw">property SORT_BY_GRAPH_OBJ_ZORDER, class=class="str">"cmt">// Sort by the priority of a graphical object for receiving the event of clicking on a chart SORT_BY_GRAPH_OBJ_HIDDEN, class=class="str">"cmt">// Sort by a disabling display of the name of a graphical object in the terminal object list SORT_BY_GRAPH_OBJ_SELECTED, class=class="str">"cmt">// Sort by the "Object selection" class="kw">property SORT_BY_GRAPH_OBJ_SELECTABLE, class=class="str">"cmt">// Sort by the "Object availability" class="kw">property SORT_BY_GRAPH_OBJ_TIME, class=class="str">"cmt">// Sort by time coordinate SORT_BY_GRAPH_OBJ_COLOR, class=class="str">"cmt">// Sort by class="type">color SORT_BY_GRAPH_OBJ_STYLE, class=class="str">"cmt">// Sort by style SORT_BY_GRAPH_OBJ_WIDTH, class=class="str">"cmt">// Sort by line width SORT_BY_GRAPH_OBJ_FILL, class=class="str">"cmt">// Sort by the "Object class="type">color filling" class="kw">property SORT_BY_GRAPH_OBJ_READONLY, class=class="str">"cmt">// Sort by the ability to edit text in the Edit object SORT_BY_GRAPH_OBJ_LEVELS, class=class="str">"cmt">// Sort by number of levels SORT_BY_GRAPH_OBJ_LEVELCOLOR, class=class="str">"cmt">// Sort by line level class="type">color SORT_BY_GRAPH_OBJ_LEVELSTYLE class=class="str">"cmt">// Sort by line level style
图形对象排序枚举的后半段细节
在 MT5 的 ObjectsTotal / ObjectGetString 系列调用里,排序图形对象用的 ENUM_SORT_MODE 并不只有前几个常见项,后半段这组枚举专门覆盖画线宽度、对齐、字体以及各类对象专属属性。 下面这段枚举定义列出了从 SORT_BY_GRAPH_OBJ_LEVELWIDTH 到 SORT_BY_GRAPH_OBJ_YSIZE 共 23 个常量,每一个都对应一种图形对象的子属性排序依据,例如射线向左 / 向右、椭圆显示模式、箭头代码、锚点位置、像素级 X/Y 偏移等。 实盘写 EA 或指标时若要对图表上的斐波那契弧、江恩线、艾略特波浪标记做批量遍历并按特定属性归类,直接套这些枚举会比自己写字符串比较更稳。外汇与贵金属杠杆高,这类对象遍历逻辑若用在自动平仓或信号判定上,回测与实盘偏差可能放大,需自行验证。 别把正态当圣经:枚举名里的 LEVELWIDTH、RAY_LEFT 等和对象类型强绑定,用错对象类型去取属性会返回空或 0,调试时先 ObjectGetInteger 探一下再排序。
SORT_BY_GRAPH_OBJ_LEVELWIDTH, class=class="str">"cmt">// Sort by line level width SORT_BY_GRAPH_OBJ_ALIGN, class=class="str">"cmt">// Sort by the "Horizontal text alignment in the Entry field" class="kw">property SORT_BY_GRAPH_OBJ_FONTSIZE, class=class="str">"cmt">// Sort by font size SORT_BY_GRAPH_OBJ_RAY_LEFT, class=class="str">"cmt">// Sort by "Ray goes to the left" class="kw">property SORT_BY_GRAPH_OBJ_RAY_RIGHT, class=class="str">"cmt">// Sort by "Ray goes to the right" class="kw">property SORT_BY_GRAPH_OBJ_RAY, class=class="str">"cmt">// Sort by the "Vertical line goes through all windows of a chart" class="kw">property SORT_BY_GRAPH_OBJ_ELLIPSE, class=class="str">"cmt">// Sort by the "Display the full ellipse of the Fibonacci Arc object" class="kw">property SORT_BY_GRAPH_OBJ_ARROWCODE, class=class="str">"cmt">// Sort by an arrow code for the Arrow object SORT_BY_GRAPH_OBJ_ANCHOR, class=class="str">"cmt">// Sort by the position of a binding point of a graphical object SORT_BY_GRAPH_OBJ_XDISTANCE, class=class="str">"cmt">// Sort by a distance from the base corner along the X axis in pixels SORT_BY_GRAPH_OBJ_YDISTANCE, class=class="str">"cmt">// Sort by a distance from the base corner along the Y axis in pixels SORT_BY_GRAPH_OBJ_DIRECTION, class=class="str">"cmt">// Sort by the "Gann object trend" class="kw">property SORT_BY_GRAPH_OBJ_DEGREE, class=class="str">"cmt">// Sort by the "Elliott wave marking level" class="kw">property SORT_BY_GRAPH_OBJ_DRAWLINES, class=class="str">"cmt">// Sort by the "Display lines for Elliott wave marking" class="kw">property SORT_BY_GRAPH_OBJ_STATE, class=class="str">"cmt">// Sort by button state(pressed/released) SORT_BY_GRAPH_OBJ_OBJ_CHART_ID, class=class="str">"cmt">// Sort by Chart object ID. SORT_BY_GRAPH_OBJ_CHART_OBJ_PERIOD, class=class="str">"cmt">// Sort by Chart object period SORT_BY_GRAPH_OBJ_CHART_OBJ_DATE_SCALE, class=class="str">"cmt">// Sort by time scale display flag for the Chart object SORT_BY_GRAPH_OBJ_CHART_OBJ_PRICE_SCALE, class=class="str">"cmt">// Sort by price scale display flag for the Chart object SORT_BY_GRAPH_OBJ_CHART_OBJ_CHART_SCALE, class=class="str">"cmt">// Sort by Chart object scale SORT_BY_GRAPH_OBJ_XSIZE, class=class="str">"cmt">// Sort by Object width along the X axis in pixels SORT_BY_GRAPH_OBJ_YSIZE class=class="str">"cmt">// Sort by object height along the Y axis in pixels
「图形对象排序枚举与消息索引的底层定义」
在 MT5 自定义库里,图形对象的可排序属性被拆成了整型、双精度、字符串三类枚举。整型段从 X/Y 偏移量、背景色、绑定角到边框类型与颜色,覆盖了 OBJ_EDIT、OBJ_BUTTON、OBJ_RECTANGLE_LABEL 等控件的界面级特征。 双精度段以 FIRST_GRAPH_OBJ_DBL_PROP 为起点,包含价格坐标、水平值、江恩与斐波那契弧的缩放、角度以及标准差通道的偏离值——这些是会影响对象在图表上几何位置的实际数值属性。 字符串段从 FIRST_GRAPH_OBJ_STR_PROP 开始,按名称、描述、提示文本、水平文本、字体、BMP 文件名和 Chart 对象品种逐一枚举,方便在对象管理器里做字典序排列。 消息索引枚举 ENUM_MESSAGES_LIB 把 MSG_LIB_PARAMS_LIST_BEG 绑定到 ERR_USER_ERROR_FIRST,再紧接 MSG_LIB_PARAMS_LIST_END,等于给用户错误区间留出了参数列表起止的两个锚点。开 MT5 把这段枚举贴进头文件,编译后可在对象遍历函数里直接传 SORT_BY_GRAPH_OBJ_PRICE 验证排序行为。
SORT_BY_GRAPH_OBJ_XOFFSET, class=class="str">"cmt">// Sort by X coordinate of the upper-left corner of the visibility area SORT_BY_GRAPH_OBJ_YOFFSET, class=class="str">"cmt">// Sort by Y coordinate of the upper-left corner of the visibility area SORT_BY_GRAPH_OBJ_BGCOLOR, class=class="str">"cmt">// Sort by background class="type">color for OBJ_EDIT, OBJ_BUTTON and OBJ_RECTANGLE_LABEL SORT_BY_GRAPH_OBJ_CORNER, class=class="str">"cmt">// Sort by chart corner for binding a graphical object SORT_BY_GRAPH_OBJ_BORDER_TYPE, class=class="str">"cmt">// Sort by border type for the "Rectangle border" object SORT_BY_GRAPH_OBJ_BORDER_COLOR, class=class="str">"cmt">// Sort by frame class="type">color for the OBJ_EDIT and OBJ_BUTTON objects class=class="str">"cmt">//--- Sort by real properties SORT_BY_GRAPH_OBJ_PRICE = FIRST_GRAPH_OBJ_DBL_PROP, class=class="str">"cmt">// Sort by price coordinate SORT_BY_GRAPH_OBJ_LEVELVALUE, class=class="str">"cmt">// Sort by level value SORT_BY_GRAPH_OBJ_SCALE, class=class="str">"cmt">// Sort by scale(class="kw">property of Gann objects and Fibonacci Arcs objects) SORT_BY_GRAPH_OBJ_ANGLE, class=class="str">"cmt">// Sort by angle SORT_BY_GRAPH_OBJ_DEVIATION, class=class="str">"cmt">// Sort by a deviation of the standard deviation channel class=class="str">"cmt">//--- Sort by class="type">class="kw">string properties SORT_BY_GRAPH_OBJ_NAME = FIRST_GRAPH_OBJ_STR_PROP, class=class="str">"cmt">// Sort by object name SORT_BY_GRAPH_OBJ_TEXT, class=class="str">"cmt">// Sort by object description SORT_BY_GRAPH_OBJ_TOOLTIP, class=class="str">"cmt">// Sort by tooltip text SORT_BY_GRAPH_OBJ_LEVELTEXT, class=class="str">"cmt">// Sort by level description SORT_BY_GRAPH_OBJ_FONT, class=class="str">"cmt">// Sort by font SORT_BY_GRAPH_OBJ_BMPFILE, class=class="str">"cmt">// Sort by BMP file name for the "Bitmap Level" object SORT_BY_GRAPH_OBJ_CHART_OBJ_SYMBOL, class=class="str">"cmt">// Sort by Chart object period symbol }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| List of the library&class="macro">#x27;s text message indices | class=class="str">"cmt">//+------------------------------------------------------------------+ enum ENUM_MESSAGES_LIB { MSG_LIB_PARAMS_LIST_BEG=ERR_USER_ERROR_FIRST, class=class="str">"cmt">// Beginning of the parameter list MSG_LIB_PARAMS_LIST_END, class=class="str">"cmt">// End of the parameter list
◍ 库内属性与对象消息枚举的暗坑
在 MT5 标准库的消息枚举里,有一批 MSG_LIB_PROP_* 常量专门描述属性读取失败的原因。比如 MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_2155 明确指出:某些属性在 MetaTrader 5 低于 build 2155 的版本里直接不可用,老终端跑新库代码会静默返回错误。 MSG_LIB_PROP_NOT_SUPPORTED_POSITION 与 MSG_LIB_PROP_NOT_SUPPORTED_PENDING 的区分很实在:持仓对象和挂单对象支持的特性集合不同,用同一套属性接口去读就会触发不同的不支持消息。写 EA 时若不分对象类型统一调属性,日志里就会交替冒出这两条。 图形对象相关的枚举也值得盯一眼。MSG_LIB_TEXT_OBJ_NO_PERIODS 表示对象不在任何周期显示,MSG_LIB_TEXT_OBJ_ALL_PERIODS 则是全周期绘制;MSG_GRAPH_STD_OBJ_ANY 作为抽象图形对象基类标识,跟 VLINE / HLINE 这类具体类型并列定义。 下面这段枚举摘出来,黄色高亮的三条是容易在调试时漏看的关键消息:
MSG_LIB_PROP_NOT_SUPPORTED, class=class="str">"cmt">// Property not supported MSG_LIB_PROP_NOT_SUPPORTED_MQL4, class=class="str">"cmt">// Property not supported in MQL4 MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_2155, class=class="str">"cmt">// Property not supported in MetaTrader class="num">5 versions lower than class="num">2155 MSG_LIB_PROP_NOT_SUPPORTED_POSITION, class=class="str">"cmt">// Property not supported for position MSG_LIB_PROP_NOT_SUPPORTED_PENDING, class=class="str">"cmt">// Property not supported for pending order MSG_LIB_PROP_NOT_SUPPORTED_MARKET, class=class="str">"cmt">// Property not supported for market order MSG_LIB_PROP_NOT_SUPPORTED_MARKET_HIST, class=class="str">"cmt">// Property not supported for historical market order MSG_LIB_PROP_NOT_SET, class=class="str">"cmt">// Value not set MSG_LIB_PROP_EMPTY, class=class="str">"cmt">// Not set MSG_LIB_PROP_AUTO, class=class="str">"cmt">// Formed by the terminal MSG_LIB_PROP_AS_IN_ORDER, class=class="str">"cmt">// According to the order expiration mode MSG_LIB_TEXT_FAILED_ADD_TO_LIST, class=class="str">"cmt">// failed to add to list MSG_LIB_TEXT_TIME_UNTIL_THE_END_DAY, class=class="str">"cmt">// Order lifetime till the end of the current day to be used MSG_LIB_TEXT_OBJ_NO_PERIODS, class=class="str">"cmt">// Not shown on any timeframe MSG_LIB_TEXT_OBJ_ALL_PERIODS, class=class="str">"cmt">// Drawn on all timeframes MSG_LIB_TEXT_JANUARY, class=class="str">"cmt">// January MSG_LIB_TEXT_FEBRUARY, class=class="str">"cmt">// February MSG_GRAPH_OBJ_BELONG_PROGRAM, class=class="str">"cmt">// Graphical object belongs to a program MSG_GRAPH_OBJ_BELONG_NO_PROGRAM, class=class="str">"cmt">// Graphical object does not belong to a program class=class="str">"cmt">//--- MSG_GRAPH_STD_OBJ_ANY, class=class="str">"cmt">// Abstract graphical object MSG_GRAPH_STD_OBJ_VLINE, class=class="str">"cmt">// Vertical line MSG_GRAPH_STD_OBJ_HLINE, class=class="str">"cmt">// Horizontal line MSG_GRAPH_OBJ_PROP_BMPFILE, class=class="str">"cmt">// BMP file name for the "Bitmap Level" object MSG_GRAPH_OBJ_PROP_SYMBOL, class=class="str">"cmt">// Chart object symbol
对象属性分组与多语消息表的硬编码结构
在 MT5 的指标或 EA 源码里,图形对象属性面板的分组标签往往不是运行时拼出来的,而是直接写进枚举常量。下面这组常量把对象属性对话框的左侧树形菜单定死了:从 Lines、Channels 到 Gann、Fibo、Elliott,再到 Shapes、Arrows、Graphical objects,一共 9 个一级分组,终端据此渲染 UI。 MSG_GRAPH_OBJ_PROP_GROUP_LINES 对应「趋势线类」面板,MSG_GRAPH_OBJ_PROP_GROUP_FIBO 对应回撤工具集;如果你自己做 ObjectCreate 的辅助面板,直接复用这组 ID 能保证和原生右键菜单一致,避免交易者找不到开关。 多语言支持则是另一张二维表 messages_library[][TOTAL_LANG],每一行同时存俄文与英文。注意其中一条硬约束:'The property is not supported in MetaTrader5, build lower than 2155'——也就是说,部分对象属性在 2155 以下 build 的终端直接不可用,开 MT5 按 F1 查 build 号就能验证。 'Drawn on all timeframes' 与 'Not shown on any timeframe' 这两条消息也藏在表里,它们控制对象跨周期可见性描述;改 EA 的 OBJ_FIBO 显示逻辑时,若想自定义提示文案,得先覆盖这两行索引,否则终端仍吐原句。
MSG_GRAPH_OBJ_PROP_GROUP, class=class="str">"cmt">// Graphical object group MSG_GRAPH_OBJ_PROP_GROUP_LINES, class=class="str">"cmt">// Lines MSG_GRAPH_OBJ_PROP_GROUP_CHANNELS, class=class="str">"cmt">// Channels MSG_GRAPH_OBJ_PROP_GROUP_GANN, class=class="str">"cmt">// Gann MSG_GRAPH_OBJ_PROP_GROUP_FIBO, class=class="str">"cmt">// Fibo MSG_GRAPH_OBJ_PROP_GROUP_ELLIOTT, class=class="str">"cmt">// Elliott MSG_GRAPH_OBJ_PROP_GROUP_SHAPES, class=class="str">"cmt">// Shapes MSG_GRAPH_OBJ_PROP_GROUP_ARROWS, class=class="str">"cmt">// Arrows MSG_GRAPH_OBJ_PROP_GROUP_GRAPHICAL, class=class="str">"cmt">// Graphical objects MSG_GRAPH_OBJ_TEXT_CLICK_COORD, class=class="str">"cmt">// (Chart click coordinate) }; class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">string messages_library[][TOTAL_LANG]= { {"Начало списка параметров","The beginning of the parameter list"}, {"Конец списка параметров","End of parameter list"}, {"Свойство не поддерживается","Property not supported"}, {"Свойство не поддерживается в MQL4","Property not supported in MQL4"}, {"Свойство не поддерживается в MetaTrader5 версии ниже class="num">2155","The class="kw">property is not supported in MetaTrader5, build lower than class="num">2155"}, {"Свойство не поддерживается у позиции","Property not supported for position"}, {"Свойство не поддерживается у отложенного ордера","The class="kw">property is not supported for a pending order"}, {"Свойство не поддерживается у маркет-ордера","The class="kw">property is not supported for a market-order"}, {"Свойство не поддерживается у исторического маркет-ордера","The class="kw">property is not supported for a history market-order"}, {"Значение не задано","Value not set"}, {"Отсутствует","Not set"}, {"Формируется терминалом","Formed by the terminal"}, {"В соответствии с режимом истечения ордера","In accordance with the order expiration mode"}, {"не удалось добавить в список","failed to add to list"}, {"Будет использоваться время действия ордера до конца текущего дня","Order validity time until the end of the current day will be used"}, {"Не показывается ни на одном таймфрейме","Not shown on any timeframe"}, {"Рисуется на всех таймфреймах","Drawn on all timeframes"}, {"Январь","January"}, {"Февраль","February"}, {"Графический объект принадлежит программе","The graphic object belongs to the program"}, {"Графический объект не принадлежит программе","The graphic object does not belong to the program"}, {"Абстрактный графический объект","Abstract graphic object"}, {"Вертикальная линия","Vertical Line"}, {"Горизонтальная линия","Horizontal Line"}, };
「图形对象按周期显示的判定逻辑」
在 MT5 里给图表对象做多语言标签时,除了基础的 BMP 文件名、图表品种名,还要覆盖图形对象分组:线、通道、甘氏、斐波那契、艾略特、形状、箭头等,共 10 类对象组加一个图表点击坐标字段。 判定某个图形对象在指定周期是否可见,核心看 flags 位标记。若 flags 等于 OBJ_ALL_PERIODS 直接返回 true,等于 OBJ_NO_PERIODS 返回 false;否则按 timeframe 转成对应十六进制位做按位与。 M1 到 M15 的位值从 0x00000001 起每档左移一位:M1=0x1、M2=0x2、M3=0x4、M4=0x8、M5=0x10、M6=0x20、M10=0x40、M12=0x80、M15=0x100。开 MT5 把这段 switch 补完,就能在 EA 里精确控制对象只在部分周期显示,外汇与贵金属波动剧烈,对象误显可能造成误读,需自行回测确认。
class="type">bool IsVisibleOnTimeframe(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">int flags) { if(flags==OBJ_ALL_PERIODS) class="kw">return true; if(flags==OBJ_NO_PERIODS) class="kw">return false; class="type">int flag=class="num">0; class="kw">switch((class="type">int)timeframe) { case PERIOD_M1 : flag=0x00000001; class="kw">break; case PERIOD_M2 : flag=0x00000002; class="kw">break; case PERIOD_M3 : flag=0x00000004; class="kw">break; case PERIOD_M4 : flag=0x00000008; class="kw">break; case PERIOD_M5 : flag=0x00000010; class="kw">break; case PERIOD_M6 : flag=0x00000020; class="kw">break; case PERIOD_M10 : flag=0x00000040; class="kw">break; case PERIOD_M12 : flag=0x00000080; class="kw">break; case PERIOD_M15 : flag=0x00000100; class="kw">break;