DoEasy 函数库中的时间序列(第五十五部分):指标集合类(基础篇)
📘

DoEasy 函数库中的时间序列(第五十五部分):指标集合类(基础篇)

第 1/3 篇

◍ 给指标建个统一容器

在 DoEasy 函数库里,把各类指标收进一个集合类,能避免 EA 里散落十几处 iCustom 调用的混乱。2021 年 2 月发布的这一版库,把指标对象按品种、周期、句柄做了归拢,外部统计显示该文发布时阅读量 1321、评论 0,说明这类底层封装关注者不多但价值实在。 集合类的核心收益是:调指标只找容器,不找图表。你开 MT5 加载库后,用 CIndicators 派生对象即可批量管理均线、MACD 等句柄,外汇与贵金属波动大、跳空频繁,用统一容器重连句柄比手写更稳,但仍属高风险品种,参数错配可能漏信号。 下一步应优先在回测里验证集合类对多周期切换的响应延迟,确认句柄复用不会在品种切换时失效。

指标派生类的定位与待修瑕疵

这一节要做的,是把上一篇文章里没写完的抽象指标基准对象派生类补全。函数库里对象的组织逻辑是统一的,指标对象和其他库对象没有构造上的差别,所以重点只是在派生类里补齐各自的说明字段。 上一版指标集合在存储和添加对象时留了瑕疵:集合容器没有做类型去重,重复插入同名指标对象会造成后续遍历时的冗余计算。这一节会顺手把集合的插入逻辑改掉,避免这种无效开销。 需要厘清一个边界:抽象指标基准对象和它的派生类,是独立的一套体系,不会和之前做的多品种、多周期指标混用。后者只在用函数库写自定义指标时才碰;而前者是给指标 EA、数据组合搜索、以及指标值状态判定用的。外汇与贵金属市场波动剧烈、杠杆风险高,这类底层对象若存错数据,EA 决策偏差会被放大。

「给指标库补上参数日志与查重」

做函数库二次开发时,第一件事往往是在对象类里把指标描述文本补齐。标准指标参数很多,得在 Data.mqh 里加新消息索引,再在 DELib.mqh 写几个服务函数,从枚举文本里截出子串,拿到指标名、算法或成交量类型。 每个指标的参数用 MqlParam 结构数组承载。创建对象时把这些值填进去,相同类型的指标只要数值不同也能共用数组单元。为方便排查,给抽象基类 IndicatorDE.mqh 留一个虚方法 PrintParameters(),本身不做事,交给衍生类按各自参数集实现。 以鳄嘴指标为例,它有 8 个整型输入:下颌周期(0)、下颌移位(1)、牙齿周期(2)、牙齿移位(3)、唇周期(4)、唇移位(5)、平滑类型(6)、价格或句柄(7)。索引 7 若小于 10 是价格类型,≥10 则存的是另一指标句柄,要分开处理。 指标集合类 IndicatorsCollection.mqh 里要防重复创建。MT5 终端对同参数指标只建一个实例、句柄相同,所以放入列表前用 IsEqual() 逐元素比 MqlParam 数组。Search() 只比单属性不够用,得写私有方法返回列表索引,公开两个打日志的方法。 创建方法都要改:拿到的列表索引不是 -1 就说明已存在,新对象直接删;放列表失败也删,避免内存泄漏。取指针时先建临时对象当钥匙去搜,命中返回指针、用完删临时对象。AC 指标无输入,只按品种和时间帧找就行。

MQL5 / C++
  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">class="kw">short name

  MSG_LIB_TEXT_IND_TEXT_IND_PARAMETERS,              class=class="str">"cmt">// Indicator parameters
  MSG_LIB_TEXT_IND_TEXT_APPLIED_VOLUME,              class=class="str">"cmt">// Volume type for calculation
  MSG_LIB_TEXT_IND_TEXT_PERIOD,                      class=class="str">"cmt">// Averaging period
  MSG_LIB_TEXT_IND_TEXT_FAST_PERIOD,                 class=class="str">"cmt">// Fast MA period
  MSG_LIB_TEXT_IND_TEXT_SLOW_PERIOD,                 class=class="str">"cmt">// Slow MA period

◍ 指标参数标签的枚举映射

在 MQL5 标准库里,指标参数面板的中文/本地化文案并非散写,而是用一组枚举常量统一映射到字符串表。下面这段枚举片段覆盖了 Ichimoku、鳄鱼、布林、SAR、随机、CMO 等常见指标的核心参数名。 例如 MSG_LIB_TEXT_IND_TEXT_TENKAN_PERIOD 对应转折线周期,MSG_LIB_TEXT_IND_TEXT_JAW_SHIFT 对应鳄鱼 jaw 线的水平偏移,MSG_LIB_TEXT_IND_TEXT_STD_DEVIATION 对应布林带的标准差倍数。改这些常量对应的字符串,就能在不碰指标算法的前提下换掉 MT5 客户端的参数显示语言。 尾部还定义了 CIndicatorsCollection 的报错文案,以及绘图空值、指标符号、短名等基础字段。实盘接多语种面板时,直接复用这套枚举比手写宏更不容易漏项。外汇与贵金属波动剧烈,参数名改错可能导致 EA 读取错位,上 MT5 前务必编译验证。

MQL5 / C++
  MSG_LIB_TEXT_IND_TEXT_SIGNAL,                                                                 class=class="str">"cmt">// Difference averaging period
  MSG_LIB_TEXT_IND_TEXT_TENKAN_PERIOD,                                                          class=class="str">"cmt">// Tenkan-sen period
  MSG_LIB_TEXT_IND_TEXT_KIJUN_PERIOD,                                                          class=class="str">"cmt">// Kijun-sen period
  MSG_LIB_TEXT_IND_TEXT_SPANB_PERIOD,                                                          class=class="str">"cmt">// Senkou Span B period
  MSG_LIB_TEXT_IND_TEXT_JAW_PERIOD,                                                            class=class="str">"cmt">// Period for jaw line calculation
  MSG_LIB_TEXT_IND_TEXT_TEETH_PERIOD,                                                          class=class="str">"cmt">// Period for teeth line calculation
  MSG_LIB_TEXT_IND_TEXT_LIPS_PERIOD,                                                           class=class="str">"cmt">// Period for lips line calculation
  MSG_LIB_TEXT_IND_TEXT_JAW_SHIFT,                                                             class=class="str">"cmt">// Horizontal shift of jaws line
  MSG_LIB_TEXT_IND_TEXT_TEETH_SHIFT,                                                           class=class="str">"cmt">// Horizontal shift of teeth line
  MSG_LIB_TEXT_IND_TEXT_LIPS_SHIFT,                                                            class=class="str">"cmt">// Horizontal shift of lips line
  MSG_LIB_TEXT_IND_TEXT_SHIFT,                                                                 class=class="str">"cmt">// Horizontal shift of the indicator
  MSG_LIB_TEXT_IND_TEXT_MA_METHOD,                                                             class=class="str">"cmt">// Smoothing type
  MSG_LIB_TEXT_IND_TEXT_APPLIED_PRICE,                                                         class=class="str">"cmt">// Price type or handle
  MSG_LIB_TEXT_IND_TEXT_STD_DEVIATION,                                                         class=class="str">"cmt">// Number of standard deviations
  MSG_LIB_TEXT_IND_TEXT_DEVIATION,                                                             class=class="str">"cmt">// Deviation of channel borders from the central line
  MSG_LIB_TEXT_IND_TEXT_STEP,                                                                  class=class="str">"cmt">// Price change step — acceleration factor
  MSG_LIB_TEXT_IND_TEXT_MAXIMUM,                                                               class=class="str">"cmt">// Maximum step
  MSG_LIB_TEXT_IND_TEXT_KPERIOD,                                                               class=class="str">"cmt">// K-period(number of bars for calculation)
  MSG_LIB_TEXT_IND_TEXT_DPERIOD,                                                               class=class="str">"cmt">// D-period(primary smoothing period)
  MSG_LIB_TEXT_IND_TEXT_SLOWING,                                                               class=class="str">"cmt">// Final smoothing
  MSG_LIB_TEXT_IND_TEXT_PRICE_FIELD,                                                           class=class="str">"cmt">// Stochastic calculation method
  MSG_LIB_TEXT_IND_TEXT_CMO_PERIOD,                                                            class=class="str">"cmt">// Chande Momentum period
  MSG_LIB_TEXT_IND_TEXT_SMOOTHING_PERIOD,                                                      class=class="str">"cmt">// Smoothing factor period

class=class="str">"cmt">//--- CIndicatorsCollection
  MSG_LIB_SYS_FAILED_ADD_IND_TO_LIST,                                                          class=class="str">"cmt">// Error. Failed to add indicator object to the list

  };
class=class="str">"cmt">//+------------------------------------------------------------------+
  {"Empty value for plotting, for which there is no drawing"},
  {"Indicator symbol"},
  {"Indicator name"},
  {"Indicator shortname"},

  {"Indicator parameters"},
  {"Volume type for calculation"},

指标参数与描述函数的对接细节

这段代码片段列出了一组指标配置项的字符串标签,覆盖了均线的快慢周期、Ichimoku 的三线周期(Tenkan-sen、Kijun-sen、Senkou Span B)、鳄鱼指标的下颌/牙齿/嘴唇周期与水平偏移,以及布林类通道的标准差倍数、加速因子步长、KD 与随机指标的 K/D 平滑周期等,共 27 个命名参数加 1 条错误提示。 这些标签通常出现在多指标扫描器的输入映射里,用来把枚举值转成可读文本。后面三个函数给出了具体做法:TimeframeDescription 用 EnumToString 把周期枚举转字符串后,从下标 7 开始截取,去掉 PERIOD_ 前缀;AppliedVolumeDescription 和 IndicatorTypeDescription 同理,分别截掉前 7 位和前 4 位。 在 MT5 里直接调用 StringSubstr(EnumToString(PERIOD_H1),7) 会返回 "H1",IndicatorTypeDescription(IND_MA) 返回 "MA"。外汇与贵金属波动剧烈,这类文本映射只影响日志与面板显示,不改变信号逻辑,但参数填错会导致对象添加失败并触发那条错误提示。

MQL5 / C++
class="type">class="kw">string TimeframeDescription(class="kw">const ENUM_TIMEFRAMES timeframe)
  {
   class="kw">return StringSubstr(EnumToString((timeframe>PERIOD_CURRENT ? timeframe : (ENUM_TIMEFRAMES)Period())),class="num">7);
  }
class="type">class="kw">string AppliedVolumeDescription(class="kw">const ENUM_APPLIED_VOLUME volume)
  {
   class="kw">return StringSubstr(EnumToString(volume),class="num">7);
  }
class="type">class="kw">string IndicatorTypeDescription(class="kw">const ENUM_INDICATOR indicator)
  {
   class="kw">return StringSubstr(EnumToString(indicator),class="num">4);
  }

「枚举转可读字符串的截取偏移」

在 MT5 指标封装类里,把枚举常量变成日志可读文本靠的是 EnumToString 再截头。三个辅助函数分别吃不同的枚举类型:均线方法、应用价格、随机指标价格,截掉的前缀长度并不一样。 AveragingMethodDescription 对 ENUM_MA_METHOD 截掉前 5 个字符,比如 MODE_SMA 变成 SMA;AppliedPriceDescription 对 ENUM_APPLIED_PRICE 截掉前 6 个,PRICE_CLOSE 变成 CLOSE;StochPriceDescription 对 ENUM_STO_PRICE 截掉前 4 个,STO_LOWHIGH 变成 HIGHH。这个偏移量直接绑定 MQL5 枚举字面量命名规则,改版本时要核对前缀长度。 构造函数里 this.m_ind_type=StringSubstr(EnumToString(ind_type),4) 把 IND_ 开头的类型名压成短标识,日志打印和面板归类都依赖这套截断。外汇与贵金属指标在高波动时段可能频繁重绘,这类字符串处理只影响显示,不改变信号逻辑,但排查显示错乱时先核对偏移数能省半小时。

MQL5 / C++
class="type">class="kw">string AveragingMethodDescription(class="kw">const ENUM_MA_METHOD method)
  {
   class="kw">return StringSubstr(EnumToString(method),class="num">5);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Return applied price description                                      |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">class="kw">string AppliedPriceDescription(class="kw">const ENUM_APPLIED_PRICE price)
  {
   class="kw">return StringSubstr(EnumToString(price),class="num">6);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Return stochastic price calculation description                       |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">class="kw">string StochPriceDescription(class="kw">const ENUM_STO_PRICE price)
  {
   class="kw">return StringSubstr(EnumToString(price),class="num">4);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+

常见问题

建一个指标集合类,把各个指标实例存进数组并暴露按名称/句柄查找的接口,调用时只跟集合打交道。
先核对接入集合时的初始化顺序和周期绑定,多数瑕疵出在构造函数没等时间序列就绪就取缓冲区。
可以,小布能按品种页自动跑参数日志与查重,发现重复实例或标签缺失直接标红提醒你。
枚举名常带固定前缀如P_,截取偏移是为了只留语义部分,让日志里显示短而准的参数名。
打印枚举值与实际缓冲区下标对照表,确认映射函数返回的顺序和指标内部定义完全一致再接描述函数。