DoEasy 函数库中的时间序列(第五十五部分):指标集合类(基础篇)
◍ 给指标建个统一容器
在 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 指标无输入,只按品种和时间帧找就行。
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 前务必编译验证。
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"。外汇与贵金属波动剧烈,这类文本映射只影响日志与面板显示,不改变信号逻辑,但参数填错会导致对象添加失败并触发那条错误提示。
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_ 开头的类型名压成短标识,日志打印和面板归类都依赖这套截断。外汇与贵金属指标在高波动时段可能频繁重绘,这类字符串处理只影响显示,不改变信号逻辑,但排查显示错乱时先核对偏移数能省半小时。
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">//+------------------------------------------------------------------+