获取仓位列表

在许多 EA 交易示例中,我们已经使用了 MQL5 API 函数来分析未平仓交易仓位。本节给出了其正式说明。

值得注意的是,这组函数并不能创建、修改或删除仓位。正如我们前面看到的,所有这些操作都是通过发送订单间接执行的。如果成功执行,则进行交易,结果形成仓位。

另一个特点是这些函数只适用于在线仓位。为了恢复仓位的历史,就必须分析交易的历史。

PositionsTotal 函数允许你找出账户上持仓的总数(对于所有金融工具)。

int PositionsTotal()

对于仓位的净额结算会计(ACCOUNT_MARGIN_MODE_RETAIL_NETTING 和 ACCOUNT_MARGIN_MODE_EXCHANGE),任何时候每个交易品种只能有一个仓位。这个仓位可能来自一个或多个交易。

有了仓位的独立表示 (ACCOUNT_MARGIN_MODE_RETAIL_HEDGING),每个交易品种可以同时开立几个仓位,包括多方向仓位。每笔进场交易都会创建一个单独的仓位,因此一个订单的部分分步执行可以生成几个仓位。

PositionGetSymbol 函数可根据仓位的编号返回其交易品种。

string PositionGetSymbol(int index)

索引必须介于 0 到 N-1 之间,其中 N 为预调用 PositionsTotal 收到的值。仓位的顺序没有规定。

如果没有找到仓位,那么将返回一个空字符串,错误代码将在 _LastError 中提供。

在几个测试 EA 交易中(TrailingStop.mq5 TradeCloseBy.mq5等)提供了使用这两个函数的示例,函数名为 GetMyPosition/GetMyPositions

未平仓仓位的特性在于唯一订单号,即区别于其他仓位的编号,但在某些情况下,订单号在订单生命周期内可能会发生变化,例如一笔交易在净额结算模式下仓位反转,或者是服务器上服务操作的结果(为应计掉期、清算而重新开立)。

为了通过编号获取仓位订单号,我们使用了 PositionGetTicket 函数。

ulong PositionGetTicket(int index)

此外,该函数突出显示终端交易环境中的仓位,然后允许你使用一组特殊的 PositionGet 函数读取其特性。换言之,与订单类似,终端为每个 MQL 程序保持一个内部缓存来存储仓位的特性。为了突出显示仓位,除了 PositionGetTicket 之外,还有两个函数: PositionSelect PositionSelect 和 PositionSelectByTicket ,我们将在下面讨论。

如果出现错误,PositionGetTicket 函数将返回 0。

不要将订单号与分配给每个仓位且永不改变的标识符相混淆。标识符用于将仓位与订单和交易联系起来。我们稍后会谈到这一点。
 
完成涉及仓位的请求需要订单号:订单号在 MqlTradeRequest 结构体的 positionposition_by 字段中指定。此外,通过将订单号保存在变量中,程序随后可以使用 PositionSelectByTicket 函数(见下文)选择并使用特定的仓位,而无需在循环中重复枚举仓位。

当在净额结算账户上反向开仓时,POSITION_TICKET 将更改为发起此运算的订单订单号。但是,仍然可以使用 ID 来跟踪此类仓位。对冲模式不支持仓位反向。

bool PositionSelect(const string symbol)

该函数根据金融工具的名称选择持仓。

通过仓位的独立表示 (ACCOUNT_MARGIN_MODE_RETAIL_HEDGING),每个交易品种可以同时有多个持仓。在这种情况下,PositionSelect 将选择订单号最小的仓位。

返回的结果表示函数执行成功 (true) 或不成功 (false)。

所选仓位的特性被缓存的事实意味着该仓位本身可能不再存在,或者如果程序在一段时间后读取其特性,它可能会被更改。建议在访问数据之前调用 PositionSelect 函数。

bool PositionSelectByTicket(ulong ticket)

该函数可选择一个未平仓仓位,以便在指定的订单号上进一步工作。

我们将在后面看到使用该函数的示例(在学习 特性 及其相关的 PositionGet PositionGet函数时)。

当使用 PositionsTotalOrdersTotal 及类似函数构造算法时,应考虑终端运算的异步原则。在编写 MqlTradeSync.mqh 类和实现等待交易请求的执行结果时,我们已经谈到了这个主题。但是,这种等待在客户端不一定总是可行。具体来说,如果我们下了一个挂单,那么它到市场订单的转换和随后的执行将发生在服务器上。此时,订单可能不再列在活动订单中(OrdersTotal 将返回 0),但仓位尚未显示(PositionsTotal 也等于 0)。因此,在没有仓位的情况下,具有下单条件的 MQL 程序可能会错误地启动新订单,其结果是仓位最终会翻倍。

为了解决这个问题,MQL 程序必须更深入地分析交易环境,而不仅仅是检查一次订单和仓位数量。例如,你可以保留交易环境最新正确状态的快照,并且不允许任何实体在没有某种确认的情况下消失。只有这样才能形成新的状态。因此,订单只能与仓位变更(创建、平仓)一起删除,或以取消状态移至历史。在 TradeGuard.mqh 文件中,以 TradeGuard 类的形式提出了一种可能的解决方案。本书还包括演示脚本 TradeGuardExample.mq5 ,你可以补充学习。