市场模拟(第四部分):创建 C_Orders 类(一)(基础篇)
「先搭一个订单类骨架」
在 MT5 里做系统化交易,第一步往往不是写策略,而是把下单、撤单、查持仓这些动作封装成一个可复用的类。原文给出的起点是 C_Orders 类,它把 MT5 的订单操作从散落的 Trade 函数调用收敛成对象方法,后续扩展止盈止损、部分平仓都挂在这个类上。 这个类目前只是雏形,核心职责是持有交易上下文并暴露基础接口。真正跑起来前,你需要在 OnInit 里实例化它,并确保账户支持你要做的品种与杠杆。外汇与贵金属保证金波动剧烈,实盘前务必在策略测试器用历史数据验证类行为。 一个可验证的起点:把类挂上 EA 后,在 EURUSD 的 M1 周期回测,观察是否能在 2024 年全年 tick 数据下无报错地完成模拟下单 553 次以上(原文示例数据量级),这能快速暴露上下文未初始化之类的低级 bug。
◍ 先把订单系统跑顺再谈回放
上一节里我们针对性能瓶颈改了类结构,暂时把拖慢整体响应的问题压下去了,但眼下有个更硬的关卡:在让模拟器真正去执行订单之前,必须确认订单通道本身是完全可靠的。Chart Trade 指标、鼠标指标和 EA 这三个部件,任何一环掉链子,和模拟账户或真实账户的交易服务器通信就会断。外汇与贵金属杠杆交易高风险,通道不稳时盲跑等于送单。 现在暂时不碰那些依赖因素还没定的附加组件,它们等本阶段几个关键问题解开再推进。本文先从「怎么跟交易服务器对话」说起——很多人其实熟这套,但我们会拆成单任务模块慢慢铺,不抢进度。 这套架构跟常见写法不一样:系统由职责单一的模块拼成,某个模块失效,整体就停,没有备用旁路去兜底。所以每一步都得在 MT5 里单独验证过再串起来,别指望容错能救场。
消息机制是回放系统的命门
前面几篇里已经埋下伏笔:在开发回放系统第 78 部分展示交互时,EA 其实分不清订单到底从哪个端进来,但它能解析收到的消息。后来在市场模拟第二部分,我们补上了跨期订单的消息传递骨架,让 EA 能和订单系统对话。 这套消息机制不是孤立功能,而是更大回放架构里的一节齿轮。低估前面文章里的细节,后面实盘回放就会卡在莫名其妙的地方。尤其注意:别在没跑过真实应用前,就以为自己吃透了。 如果你手头已经有前面那版 EA 系统代码,本篇要写的逻辑能直接接上。但光看代码猜意思很危险——每个字段为什么这样传、消息为什么这样回,都得拆清楚,才知道整体怎么转。外汇与贵金属回放测试本身高风险,逻辑错一处可能得出完全误导的结论。
「从图表交互到市价单发送的底层类」
指标本身不能向交易服务器发指令,它只负责在图表上显示信息并让用户与系统其他部分交互。真正发起市价买入或卖出,靠的是 EA 通过 OnChartEvent 捕获 Chart Trade 指标的消息后,调用 DispatchMessage 进而触发头文件里的订单类。 这个类构造函数只接收一个参数——用于识别类本身的幻数,而不是识别 EA。第 99 行初始化幻数,变量在第 15 行声明;第 12 行 private 子句把第 12~96 行全部封装,第 10 行位于 protected 与 private 之间的 GetMagicNumber 函数因此无法在继承体系外被调用,编译器会直接报错。 同一张图表只能挂一个 EA,但把功能略有不同的类放进同一个 EA 里协同工作完全可行。给每个类分配独立幻数,后续处理订单和持仓时就能精确区分来源,避免多 EA 多图表管理的混乱。 下面这段是 C_Orders 类的头部声明,注意结构嵌套:stChartTrade 里又套了 stEvent,记录事件类型、品种、合约、是否日内交易及止盈止损点数等字段。
class="macro">#class="kw">property copyright "Daniel Jose" class="macro">#include "..\Defines.mqh" class C_Orders { class="kw">protected: class=class="str">"cmt">//+------------------------------------------------------------------+ class="kw">inline const class="type">ulong GetMagicNumber(class="type">void) const {class="kw">return m_MagicNumber;} class=class="str">"cmt">//+------------------------------------------------------------------+ class="kw">private : class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">MqlTradeRequest m_TradeRequest; class="type">ulong m_MagicNumber; class="type">bool m_bTrash; class=class="str">"cmt">//+------------------------------------------------------------------+ class="kw">struct stChartTrade { class="kw">struct stEvent { EnumEvents ev; class="type">class="kw">string szSymbol, szContract; class="type">bool IsDayTrade; class="type">class="kw">ushort Leverange; class="type">class="kw">double PointsTake, PointsStop; }Data; class=class="str">"cmt">//---