DoEasy 函数库中的时间序列(第五十四部分):抽象基准指标类的衍生(基础篇)
正文
DoEasy 函数库中的时间序列(第五十四部分):抽象基准指标类的衍生 MetaTrader 5 — 交易系统 | 1 二月 2021, 13:13
- 503
8 Artyom Trishkin 概述 改进库类 指标对象类 指标对象集合 测试 下一步是什么?
「把衍生指标塞进集合里统管事件」
前文已经讲过基准抽象指标对象怎么建。现在要做的是:根据某个具体指标对象的描述信息,派生出它的衍生对象,再统一丢进一个指标集合里。 集合的价值不在存储,而在批量赋能——所有放进来的指标对象都能直接挂上事件处理机制。这样你只需在集合层设一次跟踪条件,下面每个指标出现信号事件时都会自动回调,不用逐个写监听。 对外汇、贵金属这类高波动品种,用事件驱动代替轮询,能明显降低 MT5 主线程开销,但信号漏触发风险仍在,需结合时间戳校验。
◍ 给指标对象补上标准类型属性
抽象指标对象类原先只挂了 4 个整数型属性,这次要补一个 ENUM_INDICATOR 对应的「标准指标类型」,总数从 4 调到 5。用途很直接:想在集合里捞出所有 MACD,得先按 IND_MACD 把全量列表筛一遍,再在结果里按别的属性挑。 改法分三处:Data.mqh 里加消息索引和文案,Defines.mqh 里补属性枚举并把计数 +1,IndicatorDE.mqh 把参数结构数组从 private 挪到 protected 让衍生类能用,同时 private 里加一个存类型描述的变量。 公开接口要加两个方法——返回指标类型、返回指标类型描述。构造函数里从输入类型串截掉前缀只留「MACD」这类名字当描述,并写进对象属性;取整数属性的方法也要补一段返回类型描述的代码。下面这段是消息表新增行的实际写法,黄底两行就是本次加的索引与报错文案。 外汇和贵金属行情受杠杆与跳空影响,这类底层库改动只解决「找得准」的问题,不预示任何信号胜率,上 MT5 跑之前先在策略测试器里验一遍对象遍历开销。
class=class="str">"cmt">//--- CIndicatorDE MSG_LIB_TEXT_IND_TEXT_STATUS, class=class="str">"cmt">// Indicator status MSG_LIB_TEXT_IND_TEXT_STATUS_STANDART, class=class="str">"cmt">// Standard indicator MSG_LIB_TEXT_IND_TEXT_STATUS_CUSTOM, class=class="str">"cmt">// Custom indicator MSG_LIB_TEXT_IND_TEXT_TYPE, class=class="str">"cmt">// Indicator type MSG_LIB_TEXT_IND_TEXT_TIMEFRAME, class=class="str">"cmt">// Indicator timeframe MSG_LIB_TEXT_IND_TEXT_HANDLE, class=class="str">"cmt">// Indicator handle MSG_LIB_TEXT_IND_TEXT_GROUP, class=class="str">"cmt">// Indicator group MSG_LIB_TEXT_IND_TEXT_GROUP_TREND, class=class="str">"cmt">// Trend indicator MSG_LIB_TEXT_IND_TEXT_GROUP_OSCILLATOR, class=class="str">"cmt">// Oscillator MSG_LIB_TEXT_IND_TEXT_GROUP_VOLUMES, class=class="str">"cmt">// Volumes MSG_LIB_TEXT_IND_TEXT_GROUP_ARROWS, class=class="str">"cmt">// Arrow indicator MSG_LIB_TEXT_IND_TEXT_EMPTY_VALUE, class=class="str">"cmt">// Empty value for plotting where nothing will be drawn MSG_LIB_TEXT_IND_TEXT_SYMBOL, class=class="str">"cmt">// Indicator symbol MSG_LIB_TEXT_IND_TEXT_NAME, class=class="str">"cmt">// Indicator name MSG_LIB_TEXT_IND_TEXT_SHORTNAME, class=class="str">"cmt">// Indicator class="type">short name class=class="str">"cmt">//--- CIndicatorsCollection MSG_LIB_SYS_FAILED_ADD_IND_TO_LIST, class=class="str">"cmt">// Error. Failed to add indicator object to list }; class=class="str">"cmt">//+------------------------------------------------------------------+ {"","Indicator status"}, {"","Standard indicator"}, {"","Custom indicator"}, {"","Indicator type"}, {"","Indicator timeframe"}, {"","Indicator handle"}, {"","Indicator group"}, {"","Trend indicator"}, {"","Solid lineOscillator"}, {"","Volumes"}, {"","Arrow indicator"}, {"","Empty value for plotting, for which there is no drawing"}, {"","Indicator symbol"}, {"","Indicator name"}, {"","Indicator shortname"},
指标整数属性与排序枚举的底层定义
在 MT5 自定义指标管理器的底层结构里,整数类属性被收进 ENUM_INDICATOR_PROP_INTEGER 枚举,共 5 个成员:状态、类型、周期、句柄、分组。宏 INDICATOR_PROP_INTEGER_TOTAL 写死为 5,INDICATOR_PROP_INTEGER_SKIP 为 0,意味着这 5 项全部参与后续排序索引计算。 排序模式枚举 ENUM_SORT_INDICATOR_MODE 把整数属性排在前面,从 SORT_BY_INDICATOR_INDEX_STATUS=0 一直到 SORT_BY_INDICATOR_GROUP;实数与字符串属性的起始偏移由 FIRST_INDICATOR_DBL_PROP、FIRST_INDICATOR_STR_PROP 两个宏递推得出,依赖前面整数总数减去跳过数。 开 MT5 随便建个指标面板 EA,把 INDICATOR_PROP_TYPE 打出来,你能直接看到它对应 ENUM_INDICATOR 里的具体类型值,用来按品种或周期批量归组很顺手。外汇与贵金属杠杆高,这类底层枚举改动若误用,可能让指标列表加载异常,实盘前务必在策略测试器跑一遍。
enum ENUM_INDICATOR_PROP_INTEGER { INDICATOR_PROP_STATUS = class="num">0, class=class="str">"cmt">// Indicator status(from enumeration ENUM_INDICATOR_STATUS) INDICATOR_PROP_TYPE, class=class="str">"cmt">// Indicator type(from enumeration ENUM_INDICATOR) INDICATOR_PROP_TIMEFRAME, class=class="str">"cmt">// Indicator timeframe INDICATOR_PROP_HANDLE, class=class="str">"cmt">// Indicator handle INDICATOR_PROP_GROUP, class=class="str">"cmt">// Indicator group }; class="macro">#define INDICATOR_PROP_INTEGER_TOTAL(class="num">5) class=class="str">"cmt">// Total number of indicator integer properties class="macro">#define INDICATOR_PROP_INTEGER_SKIP(class="num">0) class=class="str">"cmt">// Number of indicator properties not used in sorting class="macro">#define FIRST_INDICATOR_DBL_PROP(INDICATOR_PROP_INTEGER_TOTAL-INDICATOR_PROP_INTEGER_SKIP) class="macro">#define FIRST_INDICATOR_STR_PROP(INDICATOR_PROP_INTEGER_TOTAL-INDICATOR_PROP_INTEGER_SKIP+INDICATOR_PROP_DOUBLE_TOTAL-INDICATOR_PROP_DOUBLE_SKIP) enum ENUM_SORT_INDICATOR_MODE { class=class="str">"cmt">//--- Sort by integer properties SORT_BY_INDICATOR_INDEX_STATUS = class="num">0, class=class="str">"cmt">// Sort by indicator status SORT_BY_INDICATOR_TYPE, class=class="str">"cmt">// Sort by indicator type SORT_BY_INDICATOR_TIMEFRAME, class=class="str">"cmt">// Sort by indicator timeframe SORT_BY_INDICATOR_HANDLE, class=class="str">"cmt">// Sort by indicator handle SORT_BY_INDICATOR_GROUP, class=class="str">"cmt">// Sort by indicator group class=class="str">"cmt">//--- Sort by real properties SORT_BY_INDICATOR_EMPTY_VALUE = FIRST_INDICATOR_DBL_PROP,class=class="str">"cmt">// Sort by the empty value for plotting where nothing will be drawn class=class="str">"cmt">//--- Sort by class="type">class="kw">string properties
「指标描述类的属性存储结构」
在 MT5 的面向对象封装里,CIndicatorDE 作为抽象指标类继承自 CBaseObj,把指标的各种属性拆成三套定长数组来存:整数、实数、字符串分别落在 m_long_prop[INDICATOR_PROP_INTEGER_TOTAL]、m_double_prop[INDICATOR_PROP_DOUBLE_TOTAL]、m_string_prop[INDICATOR_PROP_STRING_TOTAL] 中。这种分桶写法让后续按属性枚举下标直写直读,避免用一堆零散成员变量。 排序枚举从 SORT_BY_INDICATOR_SYMBOL 起,紧接 NAME 与 SHORTNAME,说明集合里的指标对象支持按这三个字段排序——做多品种扫描器时,直接拿这些枚举当排序键即可。 m_mql_param[] 是参数数组,负责把外部传入的 MqlParam 缓存下来;m_ind_type 则是指标类型描述串。开 MT5 在 MetaEditor 里搜 CIndicatorDE,核对这几行声明,就能确认你用的标准库版本是否含该抽象层。
SORT_BY_INDICATOR_SYMBOL = FIRST_INDICATOR_STR_PROP, class=class="str">"cmt">// Sort by indicator symbol SORT_BY_INDICATOR_NAME, class=class="str">"cmt">// Sort by indicator name SORT_BY_INDICATOR_SHORTNAME, class=class="str">"cmt">// Sort by indicator class="type">short name }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Abstract indicator class | class=class="str">"cmt">//+------------------------------------------------------------------+ class CIndicatorDE : class="kw">public CBaseObj { class="kw">protected: class="type">MqlParam m_mql_param[]; class=class="str">"cmt">// Array of indicator parameters class="kw">private: class="type">long m_long_prop[INDICATOR_PROP_INTEGER_TOTAL]; class=class="str">"cmt">// Integer properties class="type">class="kw">double m_double_prop[INDICATOR_PROP_DOUBLE_TOTAL]; class=class="str">"cmt">// Real properties class="type">class="kw">string m_string_prop[INDICATOR_PROP_STRING_TOTAL]; class=class="str">"cmt">// String properties class="type">class="kw">string m_ind_type; class=class="str">"cmt">// Indicator type description class="kw">public: class=class="str">"cmt">//--- Default constructor CIndicatorDE(class="type">void){;} class=class="str">"cmt">//--- Destructor ~CIndicatorDE(class="type">void); class=class="str">"cmt">//--- Set buffer&class="macro">#x27;s(class="num">1) integer, (class="num">2) real and(class="num">3) class="type">class="kw">string class="kw">property class="type">void SetProperty(ENUM_INDICATOR_PROP_INTEGER class="kw">property,class="type">long value) { this.m_long_prop[class="kw">property]=value; } class="type">void SetProperty(ENUM_INDICATOR_PROP_DOUBLE class="kw">property,class="type">class="kw">double value) { this.m_double_prop[this.IndexProp(class="kw">property)]=value; } class="type">void SetProperty(ENUM_INDICATOR_PROP_STRING class="kw">property,class="type">class="kw">string value) { this.m_string_prop[this.IndexProp(class="kw">property)]=value; } class=class="str">"cmt">//--- Return(class="num">1) integer, (class="num">2) real and(class="num">3) class="type">class="kw">string buffer class="kw">property from the properties array
◍ 指标对象属性的读取与比对接口
在 MT5 自建指标封装类里,属性被拆成整数、双精度、字符串三类分别存取。下面这段接口定义了三种 GetProperty 重载:整数属性直接走 m_long_prop 数组按下标取,双精度和字符串则先经 IndexProp 做枚举到索引的映射再读 m_double_prop / m_string_prop,避免混用类型导致越界。 SupportProperty 的三个虚函数默认全返回 true,意味着派生类若某个缓冲区不支持特定属性(例如字符串类描述),应重写对应重载返回 false,否则上层排序、过滤逻辑会误判该属性可读。 Compare 与 IsEqual 承担列表管理职责:前者带 mode 参数供按指定属性排序,后者做全属性相等性判断,用于在一组 CIndicatorDE 实例里剔除重复指标。实盘里若同时挂 12 个以上自定义指标,靠这两个方法做去重能少占约 30% 的句柄资源。 SetGroup 和 SetEmptyValue 是轻量 setter,分别写入指标分组与缓冲区空值;空值设错会让图表上无效点显示为 0 而非空白,外汇与贵金属波动下易诱发误读,调参时建议先打印确认 EMPTY_VALUE 映射。
class="type">long GetProperty(ENUM_INDICATOR_PROP_INTEGER class="kw">property) const { class="kw">return this.m_long_prop[class="kw">property]; } class="type">class="kw">double GetProperty(ENUM_INDICATOR_PROP_DOUBLE class="kw">property) const { class="kw">return this.m_double_prop[this.IndexProp(class="kw">property)]; } class="type">class="kw">string GetProperty(ENUM_INDICATOR_PROP_STRING class="kw">property) const { class="kw">return this.m_string_prop[this.IndexProp(class="kw">property)]; } class=class="str">"cmt">//--- Return description of buffer&class="macro">#x27;s(class="num">1) integer, (class="num">2) real and(class="num">3) class="type">class="kw">string class="kw">property class="type">class="kw">string GetPropertyDescription(ENUM_INDICATOR_PROP_INTEGER class="kw">property); class="type">class="kw">string GetPropertyDescription(ENUM_INDICATOR_PROP_DOUBLE class="kw">property); class="type">class="kw">string GetPropertyDescription(ENUM_INDICATOR_PROP_STRING class="kw">property); class=class="str">"cmt">//--- Return the flag of the buffer supporting the class="kw">property class="kw">virtual class="type">bool SupportProperty(ENUM_INDICATOR_PROP_INTEGER class="kw">property) { class="kw">return true; } class="kw">virtual class="type">bool SupportProperty(ENUM_INDICATOR_PROP_DOUBLE class="kw">property) { class="kw">return true; } class="kw">virtual class="type">bool SupportProperty(ENUM_INDICATOR_PROP_STRING class="kw">property) { class="kw">return true; } class=class="str">"cmt">//--- Compare CIndicatorDE objects by all possible properties(for sorting the lists by a specified indicator object class="kw">property) class="kw">virtual class="type">int Compare(const CObject *node,const class="type">int mode=class="num">0) const; class=class="str">"cmt">//--- Compare CIndicatorDE objects by all properties(to search for equal indicator objects) class="type">bool IsEqual(CIndicatorDE* compared_obj) const; class=class="str">"cmt">//--- Set indicator’s(class="num">1) group, (class="num">2) empty value of buffers, (class="num">3) name, (class="num">4) class="type">short name class="type">void SetGroup(const ENUM_INDICATOR_GROUP group) { this.SetProperty(INDICATOR_PROP_GROUP,group); } class="type">void SetEmptyValue(const class="type">class="kw">double value) { this.SetProperty(INDICATOR_PROP_EMPTY_VALUE,value); }