- EA 交易的主要事件:OnTick
- 基本原理和概念:订单、交易和仓位
- 交易操作类型
- 订单类型
- 按价格和数量划分的订单执行模式
- 挂单到期日期
- 期货订单的保证金计算方法:OrderCalcMargin
- 估算交易操作的利润:OrderCalcProfit
- MqlTradeRequest 结构体
- MqlTradeCheckResult 结构体
- 请求验证:OrderCheck
- 请求发送结果:MqlTradeResult 结构体
- 发送交易请求:OrderSend 和 OrderSendAsync
- 买入和卖出操作
- 修改仓位的止损和/或止盈水平
- 跟踪止损
- 平仓:全部和部分
- 反向平仓:全部和部分
- 挂单
- 修改挂单
- 删除挂单
- 获取活动订单列表
- 订单特性(现行和历史)
- 用于读取活动订单特性的函数
- 按特性选择订单
- 获取仓位列表
- 仓位特性
- 用于读取仓位特性的函数
- 交易特性
- 从历史中选择订单和交易
- 用于从历史中读取订单特性的函数
- 用于从历史中读取交易特性的函数
- 交易类型
- OnTradeTransaction 事件
- 同步和异步请求
- OnTrade 事件
- 监测交易环境变化
- 创建多交易品种 EA 交易
- EA 交易的优势和局限性
- 在 MQL 向导中创建 EA 交易
下达挂单
在 订单类型中,我们从理论上探讨了平台支持的所有挂单下达选项。从实用的角度来看,订单是使用 OrderSend/OrderSendAsync 函数创建的,根据特殊的规则预先填充了请求结构体 MqlTradeRequest。具体而言,action 字段必须包含 TRADE_ACTION_PENDING 值(在 ENUM_TRADE_REQUEST_ACTIONS 枚举中)。考虑到这一点,以下字段为必填:
- action
- symbol
- volume
- price
- type(默认值 0 对应于 ORDER_TYPE_BUY)
- type_filling(默认值 0 对应于 ORDER_FILLING_FOK)
- type_time(默认值 0 对应于 ORDER_TIME_GTC)
- expiration(默认值为 0,不适用于 ORDER_TIME_GTC)
如果零默认值适用于该任务,则可以跳过最后四个字段中的某些字段。
只有订单类型为 ORDER_TYPE_BUY_STOP_LIMIT 和 ORDER_TYPE_SELL_STOP_LIMIT 时,才必须填写 stoplimit 字段。
以下字段可选填:
- sl
- tp
- magic
- comment
sl 和 tp 中的零值表示没有保护水平。
我们在 MqlTradeSync.mqh 文件中将检查值和将字段填充方法添加到我们的结构体中。所有类型的订单的形成原理都是相同的,所以我们考虑一些下达限制买卖订单的特殊情况。其余类型的仅在字段类型的值方面有区别。具有全套必需字段以及保护水平的公共方法是根据类型命名的:buyLimit 和 sellLimit。
ulong buyLimit(const string name, const double lot, const double p,
|
由于该结构体包含 symbol 字段,而该字段在构造函数中的初始化是可选的,所以有一些类似的无 name 参数的方法:它们通过传递 symbol 作为第一个参数来调用上述方法。因此,要以最少的工作量创建订单,请编写以下代码:
MqlTradeRequestSync request; // by default uses the current chart symbol
|
用于检查传递的值、规范化、并将其保存在结构体字段中以及创建挂单代码的常规部分已经被移到了辅助方法 _pending 中。如果成功,则返回订单号,如果失败,则返回 0。
ulong _pending(const string name, const double lot, const double p,
|
我们已经知道如何填充 action 字段以及如何从以前的交易操作中调用 setSymbol 和 setVolumePrices 的方法。
多字符串 if 运算符可确保正在准备的运算出现在允许交易品种运算中(在 SYMBOL_ORDER_MODE 特性中指定)。整数型除法 type 除以二并将结果值移位 1,用于在允许的订单类型掩码中设置正确的位。这是由于 ENUM_ORDER_TYPE 枚举中的常量和 SYMBOL_ORDER_MODE 特性的组合。例如,ORDER_TYPE_BUY_STOP 和 ORDER_TYPE_SELL_STOP 的值分别为 4 和 5,除以 2 均为 2(去掉小数)。运算 1 << 2 的结果 4 等于 SYMBOL_ORDER_STOP。
挂单的一个特殊功能是处理到期日期。setExpiration 方法用于处理到期日期。在此方法中,应确保允许为该交易品种指定的到期模式 ENUM_ORDER_TYPE_TIME (duration) 并且正确填写 until 中的日期和时间。
bool setExpiration(ENUM_ORDER_TYPE_TIME duration = ORDER_TIME_GTC, datetime until = 0)
|
允许模式的位掩码在 SYMBOL_EXPIRATION_MODE 特性中提供。掩码中的位和常量 ENUM_ORDER_TYPE_TIME 的组合是这样的,我们只需计算表达式 1 << duration,并将其叠加在掩码上:非零值表示模式存在。
对于 ORDER_TIME_SPECIFIED 和 ORDER_TIME_SPECIFIED_DAY 模式,具有特定 datetime 值的 expiration 字段不能为空。此外,指定的日期和时间不能是过去的时间。
由于前面介绍的 _pending 方法最终使用 OrderSend 向服务器发送请求,所以我们的程序必须确保实际创建了带有接收订单号的订单(这对于可以输出到外部交易系统的限价订单尤其重要)。因此,在用于“阻止”结果控制的 completed 方法中,我们将为 TRADE_ACTION_PENDING 操作添加一个分支。
bool completed()
|
在 MqlTradeResultSync 结构体中,我们添加了 placed 方法。
bool placed(const ulong msc = 1000)
|
其主要任务是使用 orderExist 函数中的 wait 等待订单的出现:其已经被用于 开仓验证的第一阶段。
为了测试新功能,我们实现 EA 交易 PendingOrderSend.mq5。其支持使用输入变量选择挂单类型及其所有特性,之后执行确认请求。
enum ENUM_ORDER_TYPE_PENDING
|
每次启动或更改参数时,EA 交易都会创建一个新订单。自动 订单删除 尚未提供。我们将在后面讨论这种操作类型。在这方面,不要忘记手动删除订单。
与前面的一些示例一样,一次性订单下达是基于计时器执行的(因此,你应首先确保市场是开放的)。
void OnTimer()
|
PlaceOrder 函数接受所有设置作为参数,发送一个请求,并返回一个成功指示符(非零订单号)。所有受支持类型的订单都提供了与当前价格的预先填充距离,该距离作为每日报价范围的一部分进行计算。
ulong PlaceOrder(const ENUM_ORDER_TYPE type,
|
例如,ORDER_TYPE_BUY_LIMIT 的系数为 -0.5,表示订单将低于当前价格一半的日线范围下达(在该范围内反弹),ORDER_TYPE_BUY_STOP 的系数为 +1.0,表示订单将位于该范围的上边界(突破)。
日线范围本身的计算方式如下。
const double range = iHigh(symbol, PERIOD_D1, 1) - iLow(symbol, PERIOD_D1, 1);
|
我们找到了下面需要的交易量和点值。
const double volume = lot == 0 ? SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN) : lot;
|
根据总范围中给定的系数,在 price 变量中计算下达订单的价格水平。
const double price = TU::GetCurrentPrice(type, symbol) + range * coefficients[type]; |
只能为 *_STOP_LIMIT 订单填写 stoplimit 字段。其值存储在 origin 变量中。
const bool stopLimit =
|
当这两种类型的订单被触发时,将以当前价格下达一个新的挂单。事实上,在这种情况下,价格从当前值移动到订单被激活的 price 水平,因此“以前的当前”价格成为限价订单指示的正确反弹水平。我们将在下面说明这种情况。
保护水平是使用 TU::TradeDirection 对象确定的。对于限制止损订单,我们从 origin 开始计算。
TU::TradeDirection dir(type);
|
接下来,说明其结构体并填写可选字段。
MqlTradeRequestSync request(symbol);
|
此处,你可以选择填充模式。默认情况下,MqlTradeRequestSync 会自动选择第一个允许的模式 ENUM_ORDER_TYPE_FILLING。
根据用户选择的订单类型,我们可调用某一种交易方法。
ResetLastError();
|
如果收到订单号,我们应等待其出现在终端的交易环境中。
if(order != 0)
|
我们使用默认设置运行 EURUSD 图表上的 EA 交易,并另外选择到 1000 点保护水平的距离。我们将在日志中看到以下条目(假设默认设置与你账户中的 EURUSD 权限相匹配)。
Autodetected daily range: 0.01413
|
以下是其在图表上的显示效果:
挂单 ORDER_TYPE_BUY_STOP
我们手动删除该订单,并将订单类型更改为 ORDER_TYPE_BUY_STOP_LIMIT。结果情况会更加复杂。
挂单 ORDER_TYPE_BUY_STOP_LIMIT
上面一对点划线所在的价格为订单触发价格,因此 ORDER_TYPE_BUY_LIMIT 订单将在当前价格水平下达,Stop Loss 和 Take Profit 值用红线标记。期货 ORDER_TYPE_BUY_LIMIT 订单的 Take Profit 水平实际上与新创建的初步订单 ORDER_TYPE_BUY_STOP_LIMIT 的激活水平一致。
作为自学的另一个示例,本书包含了一个 EA 交易 AllPendingsOrderSend.mq5,EA 交易一次设置 6 个挂单:每种类型 1 个。
所有类型的挂单
如果使用默认设置运行该 EA 交易,你可能会得到如下日志条目:
Autodetected daily range: 0.01413
|