品种对象集合:用分层列表把杂乱品种归置成可操控的数据结构(基础篇)
(1/3)· 面对几十个外汇贵金属品种,靠手工分类和硬编码判断状态,维护成本会指数级膨胀
◍ 把多个交易品种收进一个集合对象
在 MT5 里逐个处理几十个外汇或贵金属品种很麻烦。把“品种”基础抽象对象再封装一层,就能得到“品种集合”类,用同一个接口遍历 EURUSD、XAUUSD 等标的。 原文给出的示例发布于 2019-11-01,截至统计时文章浏览量 5127、评论 11 条,说明这套集合封装在实战社群里有明确需求。 品种集合类内部维护一个对象数组,对外暴露添加、查找、删除方法。测试时往集合里塞 5 个品种,循环打印点差与报价,能在 MT5 专家日志里直接看到输出。外汇与贵金属杠杆高、滑点突变频繁,集合遍历仅降低编码成本,不替代风控。
「把品种按状态拆成可操控的集合」
在 DoEasy 函数库里,品种不再是一个个孤立对象,而是按“状态”归类的集合。抽象品种类只定义骨架,真正落地要靠它的衍生类去填充数据,并用从 CArrayObj 继承来的 CListObj 存所有对象。分组优先级是:先查用户自定义品种名称数组,找不到再按 ENUM_SYMBOL_CALC_MODE 保证金计算方法来判类别。 自定义类别覆盖十几类:主要/次要/异国外汇、外汇兑 RUB、贵金属、指数、指导性、加密货币、商品、证券(期货/CFD/抵押/国债/期权等)、不可交易与自定义品种,以及兜底的一般类别。用户完全可以把 USDUSC 硬塞进“主要”类,尽管它本质是指导性——自定义数组优先级压过系统判定。 操控范围有四种模式:当前加载品种、程序预定义集合、“市场观察”窗口列表、服务器全量品种。最后一种最吃资源:在中档笔记本上,首次创建服务器全部可用品种对象约需 120 秒,必须提前警告用户初始化耗时。 集合需要两个计时器分开跑:报价数据刷新 100 毫秒一次(ID 独立),其余列表与属性操作 300 毫秒一次,用以响应市场观察窗口的增删排序事件。 CSymbol 类为此改了不少:保证金比率不再读 SYMBOL_MARGIN_* 常量(那些不涉及品种属性),改用 SymbolInfoMarginRate(),实数型属性从 47 增到 58。为 8 种订单类型 × 初始/维持两个比率 = 16 个接收变量,用双层嵌套结构存。背景色判定也弃用 clrWhite 比较(可能误判),改比 CLR_DEFAULT 和 CLR_NONE。
保证金比率刷新与品种分类清单
刷新全品种数据时,MQL5 必须给各类定单和持仓补上保证金比率的接收逻辑;MQL4 因为用不到,构造函数初始化后这些字段默认是 0,不用额外处理。 MQL5 里我们调 MarginRates() 抓比率数据。只要有一个比率没拿到,方法返回 false,把错误码写进类内变量就直接退出——不弹消息。原因是这套逻辑跑在计时器里,一旦打日志,同一错误会瞬间刷屏把终端日志灌满。错误码留在 CEngine 类统一收口处理更干净。 报价刷新方法里同样删掉日志报错代码,方法末尾把拿到的比率写回对应品种对象的属性字段。CSymbol 抽象类的改动到此基本收尾,少量拼写和语义修正没展开说,附件里有完整版。 接下来要把抽象基类派生出具体对象,按类别归好丢进品种集合。下面这段是直连 MT5 能编译的品种分组数组,主要货币对 28 个、次要货币对 21 个,复制进 Datas.mqh 就能用。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Datas.mqh | class=class="str">"cmt">//| Copyright class="num">2018, MetaQuotes Software Corp. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Copyright class="num">2018, MetaQuotes Software Corp." class="macro">#class="kw">property link "[MQL5官方文档] class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Data sets | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Major Forex symbols | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">string DataSymbolsFXMajors[]= { "AUDCAD","AUDCHF","AUDJPY","AUDNZD","AUDUSD","CADCHF","CADJPY","CHFJPY","EURAUD","EURCAD","EURCHF","EURGBP","EURJPY","EURNZD", "EURUSD","GBPAUD","GBPCAD","GBPCHF","GBPJPY","GBPNZD","GBPUSD","NZDCAD","NZDCHF","NZDJPY","NZDUSD","USDCAD","USDCHF","USDJPY" }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Minor Forex symbols | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">string DataSymbolsFXMinors[]= { "EURCZK","EURDKK","EURHKD","EURNOK","EURPLN","EURSEK","EURSGD","EURTRY","EURZAR","GBPSEK","GBPSGD" ,"NZDSGD","USDCZK","USDDKK","USDHKD","USDNOK","USDPLN","USDSEK","USDSGD","USDTRY","USDZAR" }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Exotic Forex symbols |
◍ 把品种池按资产类别拆成数组
在 MT5 里做跨品种扫描或批量下单时,最忌讳把 EURTRY 和 XAUUSD 混在同一逻辑里跑。按资产类别预定义字符串数组,能让后续的条件分支清晰很多,也方便小布这类 AIGC 工具直接读结构。 下面这段声明把外汇 exotic、卢布对、指示性报价、贵金属、商品、指数、加密货币全部分组。注意指数组里混了常规股指(如 SPX500、DAX30)和合成波动率品种(Volatility 75 Index、Crash 1000 Index),回测时流动性假设要分开对待。 外汇与贵金属杠杆高、跳空频繁,实盘接这类数组做遍历下单前,务必在策略测试器里先用单品种验证点差与库存费。代码里的品种名直接对应 MT5 市场报价窗口的名称,复制后编译即可用。
class="type">class="kw">string DataSymbolsFXExotics[]= { "EURMXN","USDCNH","USDMXN","EURTRY","USDTRY" }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Forex RUB symbols | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">string DataSymbolsFXRub[]= { "EURRUB","USDRUB" }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Indicative Forex symbols | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">string DataSymbolsFXIndicatives[]= { "EUREUC","USDEUC","USDUSC" }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Metal symbols | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">string DataSymbolsMetalls[]= { "XAGUSD","XAUUSD" }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Commodity symbols | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">string DataSymbolsCommodities[]= { "BRN","WTI","NG" }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Indices | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">string DataSymbolsIndexes[]= { "CAC40","HSI50","ASX200","STOXX50","NQ100","FTSE100","DAX30","IBEX35","SPX500","NIKK225" "Volatility class="num">10 Index","Volatility class="num">25 Index","Volatility class="num">50 Index","Volatility class="num">75 Index","Volatility class="num">100 Index", "HF Volatility class="num">10 Index","HF Volatility class="num">50 Index","Crash class="num">1000 Index","Boom class="num">1000 Index","Step Index" }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Cryptocurrency Symbols | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">string DataSymbolsCrypto[]= { "BCHUSD","BTCEUR","BTCUSD","DSHUSD","EOSUSD","ETHEUR","ETHUSD","LTCUSD","XRPUSD" };
「BO 波动率指数与实时报价字段的枚举定义」
在 MT5 里做二元期权类波动率品种的数据抓取,第一步是把品种名固化进数组。下面这段代码把 5 个 BO Volatility 指数(10/25/50/75/100)直接写死在 DataSymbolsOptions[] 里,开 MT5 后在策略测试器选对应品种就能跑,省去动态枚举全市场品种的 overhead。 真正麻烦的是实时属性的读取。MQL5 原生 SYMBOL 系列函数对 BO 品种覆盖不全,所以作者自己扩展了 ENUM_SYMBOL_PROP_DOUBLE 枚举,从 SYMBOL_PROP_BID 开始接在 SYMBOL_PROP_INTEGER_TOTAL 后面,把 Bid/Ask/Last 及其当日高低、成交量高低、期权行权价、点值、Tick 价值全列成 double 型字段。 这套枚举给实盘的意义在于:BO Volatility 100 Index 的单点值(SYMBOL_PROP_POINT)和 Tick 收益(SYMBOL_PROP_TRADE_TICK_VALUE)可能和常规外汇对差出 1~2 个数量级,不单独枚举就容易在仓位计算里直接爆仓。外汇与贵金属本身杠杆高、报价跳变快,接这类自定义结构前务必在策略测试器先用 Print() 打一遍字段值验证。
class=class="str">"cmt">//| Options | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">string DataSymbolsOptions[]= { "BO Volatility class="num">10 Index","BO Volatility class="num">25 Index","BO Volatility class="num">50 Index","BO Volatility class="num">75 Index","BO Volatility class="num">100 Index" }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Symbol real properties | class=class="str">"cmt">//+------------------------------------------------------------------+ enum ENUM_SYMBOL_PROP_DOUBLE { SYMBOL_PROP_BID = SYMBOL_PROP_INTEGER_TOTAL, class=class="str">"cmt">// Bid - the best price at which a symbol can be sold SYMBOL_PROP_BIDHIGH, class=class="str">"cmt">// The highest Bid price of the day SYMBOL_PROP_BIDLOW, class=class="str">"cmt">// The lowest Bid price of the day SYMBOL_PROP_ASK, class=class="str">"cmt">// Ask - best price, at which an instrument can be bought SYMBOL_PROP_ASKHIGH, class=class="str">"cmt">// The highest Ask price of the day SYMBOL_PROP_ASKLOW, class=class="str">"cmt">// The lowest Ask price of the day SYMBOL_PROP_LAST, class=class="str">"cmt">// The price at which the last deal was executed SYMBOL_PROP_LASTHIGH, class=class="str">"cmt">// The highest Last price of the day SYMBOL_PROP_LASTLOW, class=class="str">"cmt">// The lowest Last price of the day SYMBOL_PROP_VOLUME_REAL, class=class="str">"cmt">// Volume of the day SYMBOL_PROP_VOLUMEHIGH_REAL, class=class="str">"cmt">// Maximum Volume within a day SYMBOL_PROP_VOLUMELOW_REAL, class=class="str">"cmt">// Minimum Volume within a day SYMBOL_PROP_OPTION_STRIKE, class=class="str">"cmt">// Option execution price SYMBOL_PROP_POINT, class=class="str">"cmt">// One point value SYMBOL_PROP_TRADE_TICK_VALUE class=class="str">"cmt">// SYMBOL_TRADE_TICK_VALUE_PROFIT value };
逐类吃透交易品种属性枚举
在 MT5 的 ENUM_SYMBOL_INFO_DOUBLE / INTEGER 体系里,有一批属性专门描述品种的交易与保证金约束。下面这段枚举片段把盈利 tick 价值、亏损 tick 价值、最小价格变动、合约大小、应计利息、债券面值、流动性比率等一次性列清,开 MT5 按 F1 搜 SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT 就能对照终端数据窗口验证。 SYMBOL_PROP_VOLUME_MIN 到 SYMBOL_PROP_VOLUME_LIMIT 决定了你下单手数的边界:最小 0.01、最大由经纪商设、步长 0.01、同方向总仓含挂单不超 LIMIT。外汇与贵金属杠杆高,VOLUME_LIMIT 被触发时可能直接拒单,实盘前务必用 SymbolInfoInteger 读一遍。 SWAP_LONG / SWAP_SHORT 与 MARGIN_INITIAL / MARGIN_MAINTENANCE 是持仓成本与占用的核心。值得注意的是,针对多头和各类买入挂单,系统还细分了初始与维持保证金属性(见下方高亮枚举),这类细分在跨品种对冲时可能影响保证金占用约 5%~15%,具体以你经纪商配置为准。
SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT, class=class="str">"cmt">// Calculated tick value for a winning position SYMBOL_PROP_TRADE_TICK_VALUE_LOSS, class=class="str">"cmt">// Calculated tick value for a losing position SYMBOL_PROP_TRADE_TICK_SIZE, class=class="str">"cmt">// Minimum price change SYMBOL_PROP_TRADE_CONTRACT_SIZE, class=class="str">"cmt">// Trade contract size SYMBOL_PROP_TRADE_ACCRUED_INTEREST, class=class="str">"cmt">// Accrued interest SYMBOL_PROP_TRADE_FACE_VALUE, class=class="str">"cmt">// Face value – initial bond value set by an issuer SYMBOL_PROP_TRADE_LIQUIDITY_RATE, class=class="str">"cmt">// Liquidity rate – the share of an asset that can be used for a margin SYMBOL_PROP_VOLUME_MIN, class=class="str">"cmt">// Minimum volume for a deal SYMBOL_PROP_VOLUME_MAX, class=class="str">"cmt">// Maximum volume for a deal SYMBOL_PROP_VOLUME_STEP, class=class="str">"cmt">// Minimum volume change step for deal execution SYMBOL_PROP_VOLUME_LIMIT, class=class="str">"cmt">// The maximum allowed total volume of an open position and pending orders in one direction(either buy or sell) SYMBOL_PROP_SWAP_LONG, class=class="str">"cmt">// Long swap value SYMBOL_PROP_SWAP_SHORT, class=class="str">"cmt">// Short swap value SYMBOL_PROP_MARGIN_INITIAL, class=class="str">"cmt">// Initial margin SYMBOL_PROP_MARGIN_MAINTENANCE, class=class="str">"cmt">// Maintenance margin for an instrument SYMBOL_PROP_MARGIN_LONG_INITIAL, class=class="str">"cmt">// Initial margin requirement applicable to class="type">long positions SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL, class=class="str">"cmt">// Initial margin requirement applicable to BuyStop orders SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL, class=class="str">"cmt">// Initial margin requirement applicable to BuyLimit orders SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL, class=class="str">"cmt">// Initial margin requirement applicable to BuyStopLimit orders SYMBOL_PROP_MARGIN_LONG_MAINTENANCE, class=class="str">"cmt">// Maintenance margin requirement applicable to class="type">long positions