DoEasy 价格库第六十五部分:DOM 集合与 MQL5 信号类的底层铺垫(基础篇)
(1/3)· 从零搭起市场深度快照序列仓库,并接通 MQL5 信号数据源的第一块砖
◍ 给 DoEasy 套上市场深度与信号对象
在 DoEasy 函数库第六十五次迭代里,核心改动是新增了 DOM(市场深度)集合类,以及专门封装 MQL5 信号对象的类。这两块原本散落在脚本层,现在收进库体系,意味着后续 EA 可以直接用统一接口去读盘口挂单和订阅信号源。 从工程角度看,把 DOM 集合和信号对象做成独立类,好处是调用方不用关心底层报价刷新逻辑。MetaTrader 5 的 Market Book 事件和 SignalBase 接口都被包了一层,库使用者只需声明对象、调方法。 这一版发布于 2021 年 5 月 10 日,原文示例在终端内累计被查看 1736 次。外汇与贵金属品种用这套类做深度监控时,仍要清楚盘口薄时滑点风险偏高,信号跟单也可能因流动性断裂而偏离。
从抽象对象到快照序列集合
到目前为止,DOM 的底层结构已经搭好:抽象订单对象、它的派生类、DOM 快照类以及 DOM 快照序列类都已在前面实现。现在缺的只是最后一块拼图——一个能统管所有快照序列的容器。 这个容器叫 DOM 快照序列集合类,它把多个序列收进同一张列表,可以随时按索引或标识捞取任意一条历史快照。类内部会按预设的序列长度自动滚动:新快照进队,超出尺寸的旧快照出队,省去手动维护缓冲区。 顺带提一句,函数库要开新支线了——「其他库类」板块。第一刀落在 MQL5 信号服务上:建一个信号对象类,把信号广播里单个信号的全部字段(收益曲线、持仓、杠杆等)原样收进实例,后面做信号横向比对时直接读对象就行。 外汇与贵金属市场杠杆高、滑点突兀,这类 DOM 与信号数据只反映过往盘口与广播状态,据此交易仍可能触发超预期回撤,务必在 MT5 策略测试器里先跑一遍再上实盘。
「给 DOM 快照序列补上连字符描述开关」
要在 DoEasy 框架里新增 DOM 快照序列集合,先得把消息索引和文本补进 \MQL5\Include\DoEasy\Data.mqh,并在 Defines.mqh 的 ID 段给集合分配一个唯一标识。这一步不做,后面编译对象类时会直接报未定义符号。 MBookSeries.mqh 里有个实际痛点:单个序列描述有时要单独打印,有时要把整列快照序列一次性列出来。如果在每条描述前加个连字符,整块列表在终端里读起来层次更清楚。 做法是在类方法的声明和实现里都加一个布尔标志,用来控制「描述前是否显示连字符」。该标志默认 false,也就是平时单条描述干净输出,只有显式置 true 时才批量带前缀。 下方代码是 Data.mqh 中实际落地的消息枚举片段,高亮行为本次新增的 DOM 系列与信号扩展项。注意 MSG_MBOOK_SERIES_ERR_ADD_TO_LIST 和 CMBookSeriesCollection 文本都是这次配套加的,漏掉其一都会导致集合类日志报错。
class=class="str">"cmt">//--- CMBookSeries MSG_MBOOK_SERIES_TEXT_MBOOKSERIES, class=class="str">"cmt">// DOM snapshot series MSG_MBOOK_SERIES_ERR_ADD_TO_LIST, class=class="str">"cmt">// Error. Failed to add DOM snapshot series to the list class=class="str">"cmt">//--- CMBookSeriesCollection MSG_MB_COLLECTION_TEXT_MBCOLLECTION, class=class="str">"cmt">// DOM snapshot series collection class=class="str">"cmt">//--- CMQLSignal MSG_SIGNAL_MQL5_TEXT_SIGNAL, class=class="str">"cmt">// Signal MSG_SIGNAL_MQL5_TEXT_SIGNAL_MQL5, class=class="str">"cmt">// MQL5.com Signals service signal MSG_SIGNAL_MQL5_TRADE_MODE, class=class="str">"cmt">// Account type MSG_SIGNAL_MQL5_DATE_PUBLISHED, class=class="str">"cmt">// Publication date MSG_SIGNAL_MQL5_DATE_STARTED, class=class="str">"cmt">// Monitoring start date MSG_SIGNAL_MQL5_DATE_UPDATED, class=class="str">"cmt">// Date of the latest update of the trading statistics MSG_SIGNAL_MQL5_ID, class=class="str">"cmt">// ID MSG_SIGNAL_MQL5_LEVERAGE, class=class="str">"cmt">// Trading account leverage MSG_SIGNAL_MQL5_PIPS, class=class="str">"cmt">// Trading result in pips MSG_SIGNAL_MQL5_RATING, class=class="str">"cmt">// Position in the signal rating MSG_SIGNAL_MQL5_SUBSCRIBERS, class=class="str">"cmt">// Number of subscribers MSG_SIGNAL_MQL5_TRADES, class=class="str">"cmt">// Number of trades MSG_SIGNAL_MQL5_SUBSCRIPTION_STATUS, class=class="str">"cmt">// Status of account subscription to a signal MSG_SIGNAL_MQL5_EQUITY, class=class="str">"cmt">// Account equity MSG_SIGNAL_MQL5_GAIN, class=class="str">"cmt">// Account growth in % MSG_SIGNAL_MQL5_MAX_DRAWDOWN, class=class="str">"cmt">// Maximum drawdown MSG_SIGNAL_MQL5_PRICE, class=class="str">"cmt">// Signal subscription price MSG_SIGNAL_MQL5_ROI, class=class="str">"cmt">// Signal ROI(Return on Investment) in %
◍ 信号与DOM快照的多语言枚举映射
在 MQL5 的本地化消息结构里,信号服务相关的字段用一组枚举常量做索引,俄文与英文成对出现,方便终端内部做界面语言切换。从 MSG_SIGNAL_MQL5_AUTHOR_LOGIN 到 MSG_SIGNAL_MQL5_CURRENCY,覆盖了作者登录名、经纪商名称、服务器、信号名和账户币种这 5 个基础维度。
紧接着的 MSG_SIGNAL_MQL5_TEXT_GAIN 与 MSG_SIGNAL_MQL5_TEXT_DRAWDOWN 单独成组,对应增长和回撤的文本标签,说明这两者在前端展示时被当作独立指标处理,而非合并进通用信号属性。
往下翻到 CMQLSignal 的本地化块,字段密度明显更高:除基础信息外,还包含 Profit in pips( pip 收益)、Position in rating(评级位置)、Number of subscribers(订阅者数)、Account maximum drawdown(最大回撤)和 Return on Investment (%)(ROI%)。如果你要写跟单信号过滤器,直接复用这组枚举就能拿到 20 个以上的结构化字段。
外汇与贵金属信号跟单自带高杠杆与滑点风险,订阅前应当把 Account maximum drawdown 与 Number of trades 拉出来核对,避免被短期增益误导。
MSG_SIGNAL_MQL5_AUTHOR_LOGIN, class=class="str">"cmt">// Author login MSG_SIGNAL_MQL5_BROKER, class=class="str">"cmt">// Broker(company) name MSG_SIGNAL_MQL5_BROKER_SERVER, class=class="str">"cmt">// Broker server MSG_SIGNAL_MQL5_NAME, class=class="str">"cmt">// Name MSG_SIGNAL_MQL5_CURRENCY, class=class="str">"cmt">// Account currency MSG_SIGNAL_MQL5_TEXT_GAIN, class=class="str">"cmt">// Growth MSG_SIGNAL_MQL5_TEXT_DRAWDOWN, class=class="str">"cmt">// Drawdown }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//--- CMBookSeries {"Серия снимков стакана цен","Series of shots of the Depth of Market"}, {"Ошибка. Не удалось добавить серию снимков стакана цен в список","Error. Failed to add a shots series of the Depth of Market to the list"}, class=class="str">"cmt">//--- CMBookSeriesCollection {"Коллекция серий снимков стакана цен","Collection of series of the Depth of Market shot"}, class=class="str">"cmt">//--- CMQLSignal {"Сигнал","Signal"}, {"Сигнал сервиса сигналов MQL5.com","Signal from MQL5.com signal service"}, {"Тип счета","Account type"}, {"Дата публикации","Publication date"}, {"Дата начала мониторинга","Monitoring starting date"}, {"Дата последнего обновления торговой статистики","The date of the last update of the signal&class="macro">#x27;s trading statistics"}, {"ID","ID"}, {"Плечо торгового счета","Account leverage"}, {"Результат торговли в пипсах","Profit in pips"}, {"Позиция в рейтинге сигналов","Position in rating"}, {"Количество подписчиков","Number of subscribers"}, {"Количество трейдов","Number of trades"}, {"Состояние подписки счёта на этот сигнал","Account subscription status for this signal"}, {"Средства на счете","Account equity"}, {"Прирост счета в процентах","Account gain"}, {"Максимальная просадка","Account maximum drawdown"}, {"Цена подписки на сигнал","Signal subscription price"}, {"Значение ROI(Return on Investment) сигнала в %","Return on Investment(%)"}, {"Логин автора","Author login"}, {"Наименование брокера (компании)","Broker name(company)"}, {"Сервер брокера","Broker server"}, {"Имя","Name"}, {"Валюта счета","Base currency"}, {"Прирост","Gain"}, {"Просадка","Drawdown"}, };
DOM 快照序列的标识与日志输出
在 MT5 的行情深度(DOM)处理框架里,各类数据集合都用 16 进制常量做唯一 ID。DOM 快照序列被定为 0x7784,紧挨着 tick 序列的 0x7783,这种连续编号方便在调试时快速区分数组边界。 CMBookSeries 类提供了两个日志方法:Print 与 PrintShort,区别只在于输出详略。Print 会拼出「所需历史天数 + 实际深度」两段信息,调用 RequiredUsedDays() 和 DataTotal() 取数,再经 Header() 加前缀。 下面这段是 Print 的核心实现,dash 参数控制是否在前方补「- 」做缩进。外汇与贵金属的 DOM 数据受流动性影响极大,盘口深度可能在秒级剧烈变化,这类日志仅用于本地排查,不代表任何方向判断。
class="macro">#define COLLECTION_MBOOKSERIES_ID(0x7784) class=class="str">"cmt">// DOM series collection list ID class=class="str">"cmt">//--- Display(class="num">1) description and(class="num">2) class="type">class="kw">short description of a DOM snapshot series class="type">void Print(class="kw">const class="type">bool dash=class="kw">false); class="type">void PrintShort(class="kw">const class="type">bool dash=class="kw">false); class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Display the description of the DOM snapshot series in the journal| class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CMBookSeries::Print(class="kw">const class="type">bool dash=class="kw">false) { class="type">class="kw">string txt= ( CMessage::Text(MSG_TICKSERIES_REQUIRED_HISTORY_DAYS)+(class="type">class="kw">string)this.RequiredUsedDays()+", "+ CMessage::Text(MSG_LIB_TEXT_TS_ACTUAL_DEPTH)+(class="type">class="kw">string)this.DataTotal() ); ::Print((dash ? "- " : ""),this.Header(),": ",txt); }
「给深度簿打印加个短横开关」
CMBookSeries 的 PrintShort 方法提供了一个轻量打印入口,适合在日志里快速扫一眼市场深度表头而不刷屏。 它接收一个 bool 参数 dash,默认 false;当传 true 时,输出前会拼一个 "- " 前缀,方便和多行日志做视觉分隔。 代码里用三元表达式 (dash ? "- " : "") 决定前缀,再叠 this.Header() 输出表头字符串,逻辑只有两行,开 MT5 把这类对象接进 OnTick 打印即可验证效果。 外汇与贵金属市场流动性瞬变,深度数据仅反映瞬时挂单,用于观察可能比用于下单依据更稳妥。
class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CMBookSeries::PrintShort(class="kw">const class="type">bool dash=class="kw">false) { ::Print((dash ? "- " : ""),this.Header()); } class=class="str">"cmt">//+------------------------------------------------------------------+