首页 / 交易学院 / MT5 订单、持仓、成交:三层模型与缓存陷阱
MT5 订单、持仓、成交:三层模型与缓存陷阱
📑

MT5 订单、持仓、成交:三层模型与缓存陷阱

理解 Order / Position / Deal,邃开 MQL5 交易函数最常见的性能坑

EA 开发实战 难度 · 进阶 2026-07-15 11 分钟阅读
#MT5#订单#持仓#成交#缓存#MQL5

要在 MT5 上写靠谱的 EA,第一道坎就是理解“订单、持仓、成交”三层模型,以及 MQL5 程序如何通过“缓存”访问它们。概念不清,轻则读不到数据,重则写出拖垮终端的“全量历史”循环。

一、三个核心概念

订单(Order)是交易服务器收到的操作请求,分为市价单与挂单,活动订单在 Trade 选项卡,执行/撤销后转入 History 且不可修改。成交(Deal)是订单执行的结果,一个订单可拆成多笔部分成交,只存于历史、不可改。持仓(Position)是某品种当前净头寸——同品种同时只能有一个,同向增仓、反向减仓,归零即平仓。

二、客户端与服务器的信息同步

客户端把交易历史存于本地加密资料库(密钥绑定本机),连服务器时只同步缺失部分以省流量。交易事件(出金、手续费、订单变动、成交、建/平仓)由服务器主动推送。Trade 选项卡显示活动订单/持仓,History 显示历史;调显示周期不改变本地存储深度,只会扩大范围时向服务器要更深数据。

三、MQL5 的缓存机制(最关键)

MQL5 程序不能直接访问客户端数据库,只能通过“填缓存”请求把数据拷进自身内存缓存,再从中读取。缓存不会自动同步,必须手动更新;任何填缓存请求都会先清空原缓存。

⚠ 忘记更新缓存的后果
若持仓缓存没刷新,EA 读到的还是旧持仓——以为没亏,其实亏损早已扩大。

四、填缓存的函数

活动订单:OrderSelect(ticket) 按单证、OrderGetTicket(i) 配合 OrdersTotal() 遍历。持仓:PositionSelect(symbol) 按品种、PositionGetSymbol(i) 配合 PositionsTotal() 遍历。历史:HistorySelect(start,end) 按时间区间、HistorySelectByPosition(id) 按持仓标识符,以及 HistoryOrderSelect / HistoryDealSelect 按单证。

五、读缓存的函数

订单:OrderGetDouble/Integer/String;持仓:PositionGetDouble/Integer/String;历史订单与成交:HistoryOrderGet*/HistoryDealGet*(注意是从缓存取,不是数据库)。索引取单证用 HistoryOrderGetTicket(i) / HistoryDealGetTicket(i)。

六、最易踩的坑:历史全量加载

错误写法 HistorySelect(0, TimeCurrent()) 会从 1970 年至今全量载入,成千上万条记录严重拖慢程序。务必限定区间,如最近 3 天。

✦ 正确做法
在 OnTrade 里置 TradeHistoryChanged 标志 → 仅当变化时用合理区间(如 end-3*PeriodSeconds(D1))调 HistorySelect → 按单证读属性,避免重复全量循环。

小结

常见问题

订单是“交易请求”,可能挂起或被部分执行;成交是订单被执行后的结果,一个订单可拆成多笔部分成交。成交只存在于历史、不可修改。
程序不能直接读客户端数据库,只能通过“填缓存”请求把数据拷进自身内存再读取,以此隔离程序与终端数据库、保证线程安全。
会从 1970 年至今全量加载,记录成千上万条,严重拖慢生至卡死 EA;永远用 start/end 限定区间。
不一样。OrdersTotal 返回客户端资料库实际活动订单数(不受缓存影响);HistoryOrdersTotal 返回“当前缓存中”的历史订单数,随填充函数变化。