- EA 交易的主要事件:OnTick
- 基本原理和概念:订单、交易和仓位
- 交易操作类型
- 订单类型
- 按价格和数量划分的订单执行模式
- 挂单到期日期
- 期货订单的保证金计算方法:OrderCalcMargin
- 估算交易操作的利润:OrderCalcProfit
- MqlTradeRequest 结构体
- MqlTradeCheckResult 结构体
- 请求验证:OrderCheck
- 请求发送结果:MqlTradeResult 结构体
- 发送交易请求:OrderSend 和 OrderSendAsync
- 买入和卖出操作
- 修改仓位的止损和/或止盈水平
- 跟踪止损
- 平仓:全部和部分
- 反向平仓:全部和部分
- 挂单
- 修改挂单
- 删除挂单
- 获取活动订单列表
- 订单特性(现行和历史)
- 用于读取活动订单特性的函数
- 按特性选择订单
- 获取仓位列表
- 仓位特性
- 用于读取仓位特性的函数
- 交易特性
- 从历史中选择订单和交易
- 用于从历史中读取订单特性的函数
- 用于从历史中读取交易特性的函数
- 交易类型
- OnTradeTransaction 事件
- 同步和异步请求
- OnTrade 事件
- 监测交易环境变化
- 创建多交易品种 EA 交易
- EA 交易的优势和局限性
- 在 MQL 向导中创建 EA 交易
请求验证:OrderCheck
要执行任何交易操作,MQL 程序必须首先用必要的数据填充 MqlTradeRequest 结构体。在使用交易函数将其发送到服务器之前,必须检查其形式上的正确性,并评估该请求的结果,特别是需要的保证金金额和剩余的可用资金。这项检查由 OrderCheck 函数执行。
bool OrderCheck(const MqlTradeRequest &request, MqlTradeCheckResult &result)
如果没有足够的资金或参数填写不正确,函数将返回 false。此外,当交易被禁用时,该函数还会对拒绝作出反应,无论是在整个终端中还是针对特定程序。有关错误代码,请检查 result 结构体的 retcode 字段。
request 结构体的成功检查和交易环境以 true 状态结束,但是,如果使用 OrderSend 或 OrderSendAsync 函数重复请求的操作,并不能保证请求的操作一定会成功。在不同调用之间,交易条件可能已发生变化,或者服务器上的经纪人可能具有应用于特定外部交易系统的设置,而 OrderCheck 执行的正式验证算法无法满足这些设置。
要获得预期财务结果的说明,应分析 result 结构体的字段。
函数 OrderCalcMargin 仅计算一个拟定仓位所需要的估算保证金,而 OrderCheck 则不同,是以简化模式考虑了交易账户的一般状态。所以,该函数用订单执行后形成的累积变量填充 MqlTradeCheckResult 结构体中的 margin 字段和其他相关字段(margin_free 和 margin_level)。例如,如果在调用 OrderCheck,时任何金融工具已建仓,并且正在检查的请求增加仓位,则 margin 字段将反映存款的金额,包括以前的保证金负债。如果新订单包含相反方向的操作,保证金将不会增加(实际上,保证金应减少,因为仓位应在净额结算账户上完全平仓,对冲保证金须应用于对冲账户上的相反仓位;但是,该函数不会执行如此精确的计算)。
首先,OrderCheck 对于程序员在熟悉交易 API 的初始阶段非常有用,可在不将请求发送到服务器的情况下进行实验。
我们使用一个简单的非交易性 EA 交易 CustomOrderCheck.mq5 来测试 OrderCheck 函数的性能。为了便于使用,我们将其作为 EA 交易而不是脚本:这样,在使用当前设置启动后 EA 交易还会留在图表上,可以通过更改单个输入参数轻松编辑。而对于脚本,我们必须每次从默认值开始设置这些字段。
要运行检查,让我们在 OnInit 中设置一个计时器。
void OnInit()
|
至于计时器处理程序,主要算法将在此处实现。一开始,我们取消了计时器,因为我们需要代码执行一次,然后等待用户更改参数。
void OnTimer()
|
EA 交易的输入参数完全重复交易请求结构体的字段集。
input ENUM_TRADE_REQUEST_ACTIONS Action = TRADE_ACTION_DEAL;
|
其中的许多字段不影响检查和财务计算,但保留了下来以便你验证。
默认情况下,变量的状态对应于以当前金融工具的最小手数建仓的请求。特别是没有显式初始化的 Type 参数会得到 0 值,等于 ENUM_ORDER_TYPE 结构体的 ORDER_TYPE_BUY 成员。在 Action 参数中,我们指定了显式初始化,因为 0 不对应于 ENUM_TRADE_REQUEST_ACTIONS 枚举的任何元素(TRADE_ACTION_DEAL 的第一个元素为 1)。
void OnTimer()
|
我们来填充该结构体。真正的机器人通常只需要为几个字段赋值,但是由于这个测试是通用的,我们必须确保用户输入的任何参数都能通过。
request.action = Action;
|
请注意,此处我们还没有标准化价格和手数,尽管在真实程序中必须这样做。因此,这个测试可以输入“不均匀”值,并确保它们会导致错误。在下面的示例中,将启用规范化。
然后我们调用 OrderCheck 并记录 request 和 result 结构体。我们仅关注后者的 retcode 字段,所以使用宏 TRCSTR (TradeRetcode.mqh) 将其额外打印为文本形式的“解密”结果。你还可以分析 comment 字符串字段,但是其格式可能会改变,以便更适合向用户显示。
ResetLastError();
|
结构体的输出由基于 ArrayPrint 的 StructPrint 辅助函数提供。因此,我们仍然会得到原始的数据显示。具体来说,枚举的元素以数字原样表示。稍后,我们将开发一个更透明(用户友好)的 MqlTradeRequest 结构体输出函数(参见 TradeUtils.mqh)。
为了便于分析结果,在 OnTimer 函数的开始,我们将显示账户的当前状态,最后,为了便于比较,我们将使用 OrderCalcMargin 函数计算给定交易操作的保证金。
void OnTimer()
|
以下是使用默认设置的 XAUUSD 的日志示例。
AccountInfoDouble(ACCOUNT_EQUITY)=15565.22 / ok AccountInfoDouble(ACCOUNT_PROFIT)=0.0 / ok AccountInfoDouble(ACCOUNT_MARGIN)=0.0 / ok AccountInfoDouble(ACCOUNT_MARGIN_FREE)=15565.22 / ok AccountInfoDouble(ACCOUNT_MARGIN_LEVEL)=0.0 / ok OrderCheck(request,result)=true / ok [action] [magic] [order] [symbol] [volume] [price] [stoplimit] [sl] [tp] [deviation] [type] » 1 0 0 "XAUUSD" 0.01 1899.97 0.00 0.00 0.00 0 0 » » [type_filling] [type_time] [expiration] [comment] [position] [position_by] [reserved] » 0 0 1970.01.01 00:00:00 "" 0 0 0 OK_0 [retcode] [balance] [equity] [profit] [margin] [margin_free] [margin_level] [comment] [reserved] 0 15565.22 15565.22 0.00 19.00 15546.22 81922.21 "Done" 0 OrderCalcMargin(Type,symbol,volume,price,margin)=true / ok margin=19.0 / ok |
下一个示例显示了对账户保证金预期增长的估算,其中已经有一个未结头寸,我们将对其翻倍。
AccountInfoDouble(ACCOUNT_EQUITY)=9999.540000000001 / ok AccountInfoDouble(ACCOUNT_PROFIT)=-0.83 / ok AccountInfoDouble(ACCOUNT_MARGIN)=79.22 / ok AccountInfoDouble(ACCOUNT_MARGIN_FREE)=9920.32 / ok AccountInfoDouble(ACCOUNT_MARGIN_LEVEL)=12622.49431961626 / ok OrderCheck(request,result)=true / ok [action] [magic] [order] [symbol] [volume] [price] [stoplimit] [sl] [tp] [deviation] [type] » 1 0 0 "PLZL.MM" 1.0 12642.0 0.0 0.0 0.0 0 0 » » [type_filling] [type_time] [expiration] [comment] [position] [position_by] [reserved] » 0 0 1970.01.01 00:00:00 "" 0 0 0 OK_0 [retcode] [balance] [equity] [profit] [margin] [margin_free] [margin_level] [comment] [reserved] 0 10000.87 9999.54 -0.83 158.26 9841.28 6318.43 "Done" 0 OrderCalcMargin(Type,symbol,volume,price,margin)=true / ok margin=79.04000000000001 / ok |
尝试更改任何请求参数,看看请求是否成功。不正确的参数组合将导致 标准列表中的错误代码,但是由于无效选项比保留选项多得多(最常见的错误),该函数通常会返回通用代码 TRADE_RETCODE_INVALID (10013)。在这方面,建议使用更高程度的诊断来实现你自己的结构体检查。
向服务器发送真实请求时,可在各种不可预见的情况下使用相同的 TRADE_RETCODE_INVALID 代码,例如,当试图重新编辑一个在外部交易系统中已经开始(但尚未完成)修改操作的订单时。