- EA 交易的主要事件:OnTick
- 基本原理和概念:订单、交易和仓位
- 交易操作类型
- 订单类型
- 按价格和数量划分的订单执行模式
- 挂单到期日期
- 期货订单的保证金计算方法:OrderCalcMargin
- 估算交易操作的利润:OrderCalcProfit
- MqlTradeRequest 结构体
- MqlTradeCheckResult 结构体
- 请求验证:OrderCheck
- 请求发送结果:MqlTradeResult 结构体
- 发送交易请求:OrderSend 和 OrderSendAsync
- 买入和卖出操作
- 修改仓位的止损和/或止盈水平
- 跟踪止损
- 平仓:全部和部分
- 反向平仓:全部和部分
- 挂单
- 修改挂单
- 删除挂单
- 获取活动订单列表
- 订单特性(现行和历史)
- 用于读取活动订单特性的函数
- 按特性选择订单
- 获取仓位列表
- 仓位特性
- 用于读取仓位特性的函数
- 交易特性
- 从历史中选择订单和交易
- 用于从历史中读取订单特性的函数
- 用于从历史中读取交易特性的函数
- 交易类型
- OnTradeTransaction 事件
- 同步和异步请求
- OnTrade 事件
- 监测交易环境变化
- 创建多交易品种 EA 交易
- EA 交易的优势和局限性
- 在 MQL 向导中创建 EA 交易
获取仓位列表
在许多 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 结构体的 position 和 position_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函数时)。
当使用 PositionsTotal、OrdersTotal 及类似函数构造算法时,应考虑终端运算的异步原则。在编写 MqlTradeSync.mqh 类和实现等待交易请求的执行结果时,我们已经谈到了这个主题。但是,这种等待在客户端不一定总是可行。具体来说,如果我们下了一个挂单,那么它到市场订单的转换和随后的执行将发生在服务器上。此时,订单可能不再列在活动订单中(OrdersTotal 将返回 0),但仓位尚未显示(PositionsTotal 也等于 0)。因此,在没有仓位的情况下,具有下单条件的 MQL 程序可能会错误地启动新订单,其结果是仓位最终会翻倍。
为了解决这个问题,MQL 程序必须更深入地分析交易环境,而不仅仅是检查一次订单和仓位数量。例如,你可以保留交易环境最新正确状态的快照,并且不允许任何实体在没有某种确认的情况下消失。只有这样才能形成新的状态。因此,订单只能与仓位变更(创建、平仓)一起删除,或以取消状态移至历史。在 TradeGuard.mqh 文件中,以 TradeGuard 类的形式提出了一种可能的解决方案。本书还包括演示脚本 TradeGuardExample.mq5 ,你可以补充学习。