跨平台专家交易系统: 订单管理器·综合运用
「用订单管理器类搭一个跨平台 EA 原型」
在 MetaEditor 里建好 EA 源文件后,第一件事是把自写的交易库用引号引到同目录,而不是用尖括号去系统路径找。接着至少声明三个全局指针:COrderManager、CSymbolInfo、CSymbolManager,它们管下单、品种属性和符号集合。 OnInit 里必须给这三个指针 new 出来,尤其 CSymbolInfo 实例要绑定具体品种名(比如 EURUSD);OnDeinit 里对应 delete,否则终端内可能漏内存。OnTick 的策略核心是新柱检测——用静态变量存上一根柱数,再用方向变量记上一次持仓方向,首笔为 0。 MQL4 直接读预定义 Bars 变量或调 iBars,MQL5 则统一调 Bars 函数,这部分要分平台写。检测到柱数变化后,先刷 CSymbolInfo 汇率,平掉旧仓,再按反方向开新仓,最后更新柱数静态变量。 为让 MQL4/MQL5 共用同一套逻辑,把上述代码挪进头文件,主源文件(test_ordermanager.mq4 或 .mq5)只留一行引用。回测里 MT4 前 10 笔平仓盈亏累计到 9989.50(起点 10000),而 MT5 净持与对冲模式成交记录一致,区别只在净持用等量反向单抵消、对冲像 MT4 那样显式 close #2。外汇与贵金属杠杆高,这类原型仅验证框架,实盘前需自测滑点与点值。
用 OrderManager 跑一根 K 线一反转的 EA 骨架
这段代码演示了在 MT5 里借助封装好的 OrderManager 基类,用极少量逻辑实现「每来一根新 K 线就平掉旧单、反手开新单」的轮转交易。它依赖 MQLx\Base\OrderManager 下的几个对象:COrderManager 管下单平仓,CSymbolManager 管品种容器,CSymbolInfo 取实时报价。 初始化阶段先 new 出三个管理器,把当前 Symbol 绑进 symbol_info,再塞进 symbol_manager,最后 order_manager.Init 完成装配;若品种名绑定失败直接返回 INIT_FAILED,避免后续空指针。OnDeinit 里依次 delete 三个指针,防止 EA 重载时内存泄漏。 [CODE] #include "MQLx\Base\OrderManager\OrderManagerBase.mqh" COrderManager *order_manager; CSymbolManager *symbol_manager; CSymbolInfo *symbol_info; int OnInit() { //--- order_manager = new COrderManager(); symbol_manager = new CSymbolManager(); symbol_info = new CSymbolInfo(); if (!symbol_info.Name(Symbol())) { Print("symbol not set"); return (INIT_FAILED); } symbol_manager.Add(GetPointer(symbol_info)); order_manager.Init(symbol_manager,NULL); //--- return(INIT_SUCCEEDED); } void OnDeinit(const int reason) { //--- delete symbol_info; delete symbol_manager; delete order_manager; } static int bars = 0; static int direction = 0; int current_bars = 0; #ifdef __MQL5__ current_bars = Bars(NULL,PERIOD_CURRENT); #else current_bars = Bars; #endif if (bars<current_bars) { symbol_info.RefreshRates(); COrder *last = order_manager.LatestOrder(); if (CheckPointer(last) && !last.IsClosed()) order_manager.CloseOrder(last); if (direction<=0) { Print("买入交易入场.."); order_manager.TradeOpen(Symbol(),ORDER_TYPE_BUY,symbol_info.Ask()); direction = 1; } else { Print("卖出交易入场.."); order_manager.TradeOpen(Symbol(),ORDER_TYPE_SELL,symbol_info.Bid()); direction = -1; } bars = current_bars; } #include "test_ordermanager.mqh" [/CODE] 逐行看核心循环:用 static bars 记录已处理根数,current_bars 取 Bars(NULL,PERIOD_CURRENT);当 bars<current_bars 说明新柱形成,先 RefreshRates 更新卖买价,调 LatestOrder 拿到上一单,未平仓就 CloseOrder 强平。 direction 变量控制多空翻转:≤0 时市价买 0.10 手并将 direction 置 1,否则市价卖并将 direction 置 -1。日志里那笔 2017.01.02 01:00:00 的 instant sell 0.10 EURUSD at 1.05172 就是该逻辑触发的实盘回测痕迹,成交基于 order #3。 别把这套当策略 它只是验证 OrderManager 接口可用的最小骨架,每根 K 线反手在高杠杆外汇/贵金属品种上可能迅速吃掉保证金,EURUSD 这类流动性品种尚且频繁碰滑点,实盘前务必把 direction 翻转条件和手数管理重写。
class="macro">#include "MQLx\Base\OrderManager\OrderManagerBase.mqh" COrderManager *order_manager; CSymbolManager *symbol_manager; CSymbolInfo *symbol_info; class="type">int OnInit() { class=class="str">"cmt">//--- order_manager = new COrderManager(); symbol_manager = new CSymbolManager(); symbol_info = new CSymbolInfo(); if (!symbol_info.Name(Symbol())) { Print("symbol not set"); class="kw">return (INIT_FAILED); } symbol_manager.Add(GetPointer(symbol_info)); order_manager.Init(symbol_manager,NULL); class=class="str">"cmt">//--- class="kw">return(INIT_SUCCEEDED); } class="type">void OnDeinit(class="kw">const class="type">int reason) { class=class="str">"cmt">//--- class="kw">delete symbol_info; class="kw">delete symbol_manager; class="kw">delete order_manager; } class="kw">static class="type">int bars = class="num">0; class="kw">static class="type">int direction = class="num">0; class="type">int current_bars = class="num">0; class="macro">#ifdef __MQL5__ current_bars = Bars(NULL,PERIOD_CURRENT); class="macro">#else current_bars = Bars; class="macro">#endif if (bars<current_bars) { symbol_info.RefreshRates(); COrder *last = order_manager.LatestOrder(); if (CheckPointer(last) && !last.IsClosed()) order_manager.CloseOrder(last); if (direction<=class="num">0) { Print("买入交易入场.."); order_manager.TradeOpen(Symbol(),ORDER_TYPE_BUY,symbol_info.Ask()); direction = class="num">1; } else { Print("卖出交易入场.."); order_manager.TradeOpen(Symbol(),ORDER_TYPE_SELL,symbol_info.Bid()); direction = -class="num">1; } bars = current_bars; } class="macro">#include "test_ordermanager.mqh"
◍ 从日志读出成交确认的链路
上面这段 MT5 Experts 日志,是 2017.01.02 01:00:00 一笔 EURUSD 卖单 0.10 手在 1.05172 成交时的原始回显。DS 行先报 deal performed,说明订单已落地;PG 行给出 instant sell 与买卖盘报价(1.05172 / 1.05237 / 1.05172),其中中间价是卖一、右边是买一。 MQ 行补了 based on order #3,把 deal #3 和 order #3 绑定,KN 行再次确认 deal performed。四行时间戳集中在 16:20:51.958,只有 DS 早 1.2 秒,说明回写有微小延迟但属同一次撮合。 做策略复盘时,直接 grep deal performed 比看 PG 行更稳,能避开报价闪烁干扰。外汇与贵金属杠杆高,单笔日志确认不代表风险可控,仍需结合仓位与止损。
DS class="num">0 class="num">16:class="num">19:class="num">15.747 Trade class="num">2017.01.class="num">02 class="num">01:class="num">00:class="num">00 deal performed [#class="num">3 sell class="num">0.10 EURUSD at class="num">1.05172] PG class="num">0 class="num">16:class="num">20:class="num">51.958 Trade class="num">2017.01.class="num">02 class="num">01:class="num">00:class="num">00 instant sell class="num">0.10 EURUSD at class="num">1.05172 (class="num">1.05172 / class="num">1.05237 / class="num">1.05172) MQ class="num">0 class="num">16:class="num">20:class="num">51.958 Trades class="num">2017.01.class="num">02 class="num">01:class="num">00:class="num">00 deal #class="num">3 sell class="num">0.10 EURUSD at class="num">1.05172 done(based on order #class="num">3) KN class="num">0 class="num">16:class="num">20:class="num">51.958 Trade class="num">2017.01.class="num">02 class="num">01:class="num">00:class="num">00 deal performed [#class="num">3 sell class="num">0.10 EURUSD at class="num">1.05172]
「订单管理器的嵌套容器长什么样」
COrderManager 是这套框架里最重的类之一,它的真实结构不是平铺的订单数组,而是一层套一层的容器。管理器内部持有两个 COrders 实例,分别装当前持仓与历史订单,每个 COrders 再作为 COrder 的容器管理已入场的单子。 单笔 COrder 下面还能挂停止价位,数量可以是零、一个,也可能多个;而每一个停止价位又能绑定自己的尾随方法,同样可无可多。这种多级挂在大多数 EA 里用不上,但处理多重支撑阻力策略时,一条单子同时盯几道止损位就很顺手。 下面的流程图只给外貌思路,具体成员以后单拆。实盘里若你写多层级止损 EA,可先照这个嵌套在 MT5 里建空类编译,验证容器引用不会在订单平仓后悬空。
一点提醒
把交易操作收口到 COrderManager 这一类里,EA 的主逻辑和头文件就能在 MQL4、MQL5 两套环境里共用同一份源码,不用为每个平台重写下单与撤单分支。对于做跨平台策略的人来说,这省掉的是重复维护成本,不是某种收益保证。 附带示例包 ordermanager_sample.zip 体积约 894.99 KB,里面是可直接在 MT5 载入跑通的工程;外汇与贵金属杠杆品种波动剧烈,跨平台兼容不代表风险被抹平,实盘前务必在策略测试器用历史数据验一遍下单路径。 这类封装的价值只在你真正动手改参数、接自己信号时才显出来——下载、编译、断点跟一次 OpenBuy 流程,比读十遍说明更有用。