MetaTrader 5 中的交易事件(基础篇)
◍ MT5 交易事件到底从哪来
MT5 客户端把每一笔挂单、成交、改仓都封装成交易事件,推给 EA 的 OnTradeTransaction 钩子,而不是靠轮询账户历史去猜。2013 年 9 月官方文档给出的事件类型里,已包含 TRADE_TRANSACTION_ORDER_ADD、DEAL_ADD 等基础枚举,覆盖从下单到成交的全链路。 很多老脚本还在用 OrderSelect 扫历史,延迟高且容易漏掉瞬时撤单。直接监听交易事务,能在几十毫秒内拿到结构化的交易记录,对做高频风控或同步信号到「小布盯盘」很有用。 外汇与贵金属杠杆品种波动剧烈,事件触发频繁,实盘使用前建议在策略测试器用真实 tick 回放验证事件顺序,避免把部分成交误判为全部成交。
请求怎么变成你账户里的持仓
在 MT5 里,任何下单动作都不是客户端本地生效,而是先以「请求」形式发往交易服务器。请求若字段或操作类型不对,会在初步验证阶段被直接打回,根本进不了撮合队列。 过了验证的请求,会在服务器端落地成两种形态:一种是挂单(pending order),等价格条件触发;另一种是市价单,按当时报价立即尝试执行。它们都驻留在服务器,直到成交或撤单,不会因你关电脑而消失。 订单一旦被撮合,产出物叫「成交(deal)」。成交直接改写指定品种的头寸——开仓、平仓、加仓、减仓或反手都靠它。换句话说,你终端里看到的任何未平仓位,背后必然链着至少一笔成交记录。 这套从发请求到最终进交易历史的处理链路,是后续写 EA 和风控逻辑的底图。开 MT5 按 F8 调出「交易」标签,手动发一单市价单,能在日志里看到 request → order → deal 的三段式流转。
「订单请求从终端到服务器的真实路径」
任何交易动作在 MT5 里都不是直接成交,而是先由客户端构造一个请求结构体再发往交易服务器。手动按 F9 填单和用 MQL5 的 OrderSend() 发单,底层走的是同一套请求机制,区别只在填写方式。 自动交易时别直接甩 OrderSend(),先用 OrderCheck() 做本地预审,结果写进 MqlTradeCheckResult 变量。像买几百万手、负价买入这种明显畸形的请求,客户端就拦下不再外发,目的是避免程序 bug 把垃圾请求灌爆服务器。 请求真到了服务器还要过一轮初审:资产够不够、价格字段对不对、市价执行模式里是否误带止损止盈、手数是否落在 SYMBOL_VOLUME_MIN / SYMBOL_VOLUME_MAX / SYMBOL_VOLUME_STEP / SYMBOL_VOLUME_LIMIT 内、品种和账户状态是否允许交易。任意一项不过就被拒,结果通过 MqlTradeResult 回传客户端。 过了初审的请求进等待队列,才会生成订单或改持仓;但改止损止盈、改挂单参数的请求不会新建订单。队列里的请求存活上限是三分钟,超时直接剔除,所以发单后要及时读回执确认。外汇和贵金属杠杆高,请求被拒或超时都会让策略漏单,务必在 MT5 里跑一遍 OrderSend 回环验证。
◍ 一次挂单成交背后会刷出几个 Trade 事件
MQL5 的事件模型靠预定义处理函数落地,交易类事件统一由 OnTrade() 接管。这段代码只能写在 EA 里,指标和脚本里即便放了同名同型函数也不会被调用——环境只认 EA 的入口。 服务端在订单、持仓、成交或交易历史任一发生变化时生成交易事件,并推送到客户端。一个操作往往触发多个事件:比如挂单被触发,既写一笔成交进历史,又把原挂单移进历史订单表,这已经是两个事件。 举个可验算的例子。一笔买入 10 手 EURUSD 的挂单等待成交,市场上先后冒出卖出 1 手、4 手、5 手三笔反向报价,合计 10 手且部分成交政策允许,于是被逐个吃掉。 第一次 1 手成交产生两个事件:成交本身 + 原挂单剩余量变为 9 手。4 手那笔再带出两个,最后 5 手成交带出三个(成交、数量变更、订单移入历史)。稳定连接下客户端共收到 7 个 Trade 事件,而不是 1 个。 别把“一个请求对应一个事件”当常识。每笔请求可能分阶段改订单状态、持仓和历史,OnTrade() 被连续叫多次是常态。外汇与贵金属杠杆高、滑点和部分成交频繁,EA 里写交易逻辑必须按多事件重入来防御,而非假设单次触发。