MetaTrader 5 中的订单、持仓和成交(基础篇)
📘

MetaTrader 5 中的订单、持仓和成交(基础篇)

第 1/3 篇

「MT5 里订单、持仓与成交到底分几层」

很多从 MT4 切到 MT5 的人,第一道坎不是指标写不出来,而是搞不清终端里三类核心对象:订单(Order)、持仓(Position)、成交(Deal)。MT5 是净持仓模式,一个品种同一方向只保留一个持仓,这与 MT4 每单独立不同。 订单是挂在交易柜台等待成交的指令,分限价、止损、随市三类;成交是订单被撮合后产生的历史记录,带唯一 ticket 和成交价;持仓则是当前真实占用的敞口,随成交累积或平仓而增减。 一个直观数据点:在 MT5 终端『 toolbox 』里,默认 Orders 标签页只显示未成交挂单,Positions 显示当前净持仓,Deal 在 History 里按时间流水。三者通过 MagicSymbol 关联,但 ticket 各不通用。 做价格行为复盘时,别直接用订单推断持仓变化——挂单可能部分成交、可能失效。打开 MT5 按 F8 切到「交易」标签,把三类视图并排看一遍,比读文档快。外汇与贵金属杠杆高,净持仓模式下一笔反向单会先平仓再开新仓,滑点风险需自担。

◍ MT5 里的订单、成交与持仓到底怎么分

在 MT5 里,订单是发给交易服务器的操作请求,格式不对根本不会进平台。它分两类:市价单按当前价立刻跑,挂单则等条件触发,还能设到期日。待成交或待撤的挂单只在「Trade」标签页挂着,可改可撤;一旦执行、撤单或过期,就掉进「History」里,再也动不了。 成交是订单跑完的产物,一笔订单可能拆成好几笔部分成交——比如买 10 手的单子可能连续啃出几笔 Buy 成交。成交写死在历史里不可改,永远在「History」出现。 持仓是某个品种方向上的合约敞口。关键点:同一账户同一品种同时只能有一个未平持仓,要么多(Long)要么空(Short)。同方向加仓会膨胀持仓量,反手减仓;仓位被搓到零就是平仓。外汇和贵金属杠杆高,这种单一持仓机制意味着反向误操作会直接碾掉原有敞口,风险不小。 用 OrderSend() 发单、撤单、改单,活动订单和持仓只看「Trade」,别跟「History」里的旧单搞混,否则复盘时容易误判当前风险。

MT5 怎么把成交记录存进本地又不漏数据

MT5 客户端把交易历史写进一个专用资料库,每次连上交易服务器只拉取缺失的成交和已完成订单记录,目的是省流量。客户端关掉或切换账户时,整段历史落盘到硬盘,下次启动再读回来。 所有本地库都以加密形式写入磁盘,密钥跟安装那台机器绑定。这意味着你把整个终端目录拷到别的电脑,资料库打不开,能挡掉直接复制硬盘导致的未授权访问。 连上账户后,客户端先载本地库,再向服务器发同步请求补齐差异;同时服务器会主动推一份进行中的交易事件报告。事件覆盖出金/结余、手续费库存费税金、订单的挂删改、成交执行、建仓平仓、持仓量和方向变动。 「History」选项卡读的是本地库,把显示周期调小不会真删数据,只是视图收窄;调大周期才可能在本地缺数据时向服务器要更深的记录。连接断了客户端会定时重连,重连后补最新变化保库完整。这套机制下,你换电脑登录同一账户不会丢历史,但别指望缩短显示间隔能瘦身本地存储。

「EA 拿历史成交前先搞清楚缓存边界」

MT5 里指标、脚本、EA 可以同时跑好几个,它们都向客户端要订单、成交、持仓数据,但都走间接接口,MQL5 程序不能直接碰客户端底层数据库——这是稳定性和性能的硬约束。 每个程序通过请求,在自身内存里建一份交易环境的“工作模型”,也就是缓存。比如你要处理某笔订单,得先把订单写进程序缓存,后续所有操作都基于这份内存副本,不再实时读库。 历史里的持仓、成交、订单也是同一套路:先向客户端数据库发请求,数据落进本程序缓存后才算可用。 缓存不会自动和客户端库同步,这点最容易被忽略。不主动刷新,就可能用着过期数据。典型事故是:当前持仓没更新,EA 根本不知道某品种已经浮亏扩大,继续按旧仓位逻辑下单。 请求失败则缓存为空,拿不到任何必要数据;该更新却没更新,结果不可预期。开 MT5 跑个脚本打印 HistoryOrdersTotal 前,先确认你显式调过相关请求函数,否则返回 0 不是没历史,是缓存没建。

◍ 缓存按请求加载,别指望自动全量

MT5 里的交易历史可能堆积几千笔已执行订单和成交,当前 EA 跑逻辑根本用不到全部。缓存是按需建立的:它只保留上一次连上客户端数据库时拉过的数据,想要完整历史必须显式指定时间区间去请求。 系统给每类数据分了独立缓存——订单归订单缓存,持仓归仓位缓存,成交和订单历史各走各的历史缓存实例。从缓存读东西之前,得先把它填进去。 注意一个坑:不管请求最终成不成功,任何填充缓存的调用都会先把对应缓存清空。交易函数因此能切成两类——一类负责填缓存,一类负责从缓存读,调错顺序直接拿不到数。

把订单和持仓塞进 MT5 缓存的入口函数

在 MT5 里读交易状态,第一步永远是把数据从客户端资料库搬进当前缓存。活动订单和持仓各有一组填充函数:OrderSelect(ticket) 按单证搬活动订单,OrderGetTicket(index) 按列表索引搬,配合 OrdersTotal() 能遍历全部活动订单;PositionSelect(symbol) 按品种名搬未平持仓,PositionGetSymbol(index) 按索引搬,PositionsTotal() 给出现货持仓总数。 历史侧稍有不同。HistoryOrderSelect(ticket) 和 HistoryDealSelect(ticket) 都是按单证把单条历史订单或成交塞进对应缓存。成功时 HistoryOrdersTotal() 或 HistoryDealsTotal() 返回 1,失败则返回 0——这两个总数函数在这里直接被缓存内容绑架,不像活动侧的 OrdersTotal()、PositionsTotal() 始终返回资料库真实数量。 真正影响历史缓存范围的只有 HistorySelect(start,end) 和 HistorySelectByPosition(id)。前者按服务器时间区间拉成交和订单,后者按持仓 ID 拉,执行后 HistoryDealsTotal() 与 HistoryOrdersTotal() 才反映本次填充的量。做回测或复盘时,若没先调这两个函数,后面循环历史大概率拿到空集合。 有一点容易踩坑:调完 OrderSelect 或 PositionSelect 后,活动缓存只留那一条记录,但 OrdersTotal()、PositionsTotal() 不受缓存清空影响,仍报资料库实际条数。写 EA 时别用总数函数反推缓存里有什么,那是两本账。

常见问题

订单是未成交的委托,持仓是已成交且未平仓的头寸,两者分属不同层级。在终端的“交易”标签看订单,“持仓”子标签才显示已开仓部分。
历史成交按请求分页加载,不会自动全量进缓存。调用历史访问函数时要显式翻页请求,否则只拿到默认缓存边界内的部分记录。
小布可以读取账户状态并标注订单与持仓差异,在品种页直接列出待成交挂单和已开仓头寸,省去你手动核对终端标签。
用对应的订单与持仓获取函数主动请求,数据才会进入本地缓存供EA逻辑使用。别等系统自动推送,大概率只加载部分。
成交记录按请求写入本地缓存,重启后需重新按边界加载。若上次没请求完,漏掉的部分不会自动补全,需主动翻页拉取。