在本文中,我打算介绍一种使用 MQL5 的手段来控制交易事件的方法。我要指出的是,有些文章已经专门讨论过这个话题。"EA 交易中采用 OnTrade() 函数处理交易事件" 即是其一。我不想重复其他作者,并将使用另一个处理器 - OnTradeTransaction()。
我想提请读者注意以下几点。在 MQL5 语言的当前版本,客户终端里包含 14 个正式的事件处理器。此外,程序员有可能利用 EventChartCustom() 创建自定义事件,并利用 OnChartEvent() 来处理它们。然而,术语“事件驱动编程”(EDP)在文档中并未提及。这很奇怪,事实表明,MQL5 的任何程序,都基于 EDP 原则创建。例如,在所有 EA 模板的“EA 事件处理器”步骤,可让用户进行选择。
很明显,不管怎样,事件驱动编程机制在 MQL5 中都被使用。该语言包含的程序块由两部分组成:事件选择和处理。此外,如果我们谈论的是客户端的事件,程序员只控制第二部分,即事件处理器。为了公平起见,也有一些事件异常。定时器和自定义事件也在其中。这些事件的控制权,则完全留给了程序员。
在深入讨论我们的话题之前,让我们参考官方资料。
根据文档, 该 TradeTransaction 事件是一个交易账户的确定操作结果。操作本身由数个确定的事务阶段构成。例如,按市价开仓,通过交易账户进行的最常见操作有以下几个阶段:
这些序列,仅显示出终端-服务器对之间的工作逻辑,它们反映在 EA 代码的字符串中。从 TradeTransaction 交易事件的角度来看,在市场中开仓,会按以下途径发生:
所以, 开仓调用五次 OnTradeTransaction() 处理器。
我们稍后将详细讨论程序代码,现在我们打算近距离观察函数头。它有三个输入参数。
void OnTradeTransaction( const MqlTradeTransaction& trans, // structure of the trade transaction const MqlTradeRequest& request, // structure of the request const MqlTradeResult& result // structure of the response );
这些参数在文档中有详细描述。我想提请注意,一个交易事务结构的参数,是一类抛出信息,由处理器在当前调用过程中接收。
我也必须用几句话来说一下有关交易事务,因为我们将会碰到了很多。
在 MQL5 中, ENUM_TRADE_TRANSACTION_TYPE 是一个特殊枚举,它负责提供交易事务的类型。要找出交易事务所属类型, 我们需要参考参数- MqlTradeTransaction 类型常量。
struct MqlTradeTransaction { ulong deal; // Ticket of the deal ulong order; // Ticket of the order string symbol; // Trade symbol ENUM_TRADE_TRANSACTION_TYPE type; // Type of the trade transaction ENUM_ORDER_TYPE order_type; // Type of the order ENUM_ORDER_STATE order_state; // Status of the order ENUM_DEAL_TYPE deal_type; // Type of the deal ENUM_ORDER_TYPE_TIME time_type; // Order expiration type datetime time_expiration; // Order expiration time double price; // Price double price_trigger; // Price that triggers the Stop Limit order double price_sl; // Level of Stop Loss double price_tp; // Level of Take Profit double volume; // Volume in lots };
结构的第四个字段即是我们寻找的枚举变量。
实质上,所有交易操作的仓位处理,都会导致调用五次 OnTradeTransaction() 处理器。其中有:
修改仓位是仅有的调用两次 TradeTransaction 处理器的交易操作。
由于没有关于事务类型的信息来对应明确的交易操作,我们打算通过试验和排错来发现它。
在此之前, 我们要创建包含 TradeTransaction 事件处理器的 EA 模板。我为我的模板命名为 TradeProcessor.mq5。我添加了一个功能,可以在日志中显示结构字段值的信息。这些值是事件处理器的参数。分析这些记录将非常耗时,但最后它会通过呈现事件全貌来补偿。
我们需要在 MetaTrader 5 终端里,在任意图表中以调试模式启动 EA。
手工开仓并查看代码。第一次处理器调用将会如此 (图例. 1).
图例.1. 类型字段等于 TRADE_TRANSACTION_REQUEST
以下条目出现在日志中:
IO 0 17:37:53.233 TradeProcessor (EURUSD,H1) ---===Transaction===--- NK 0 17:37:53.233 TradeProcessor (EURUSD,H1) Ticket of the deal: 0 RR 0 17:37:53.233 TradeProcessor (EURUSD,H1) Type of the deal: DEAL_TYPE_BUY DE 0 17:37:53.233 TradeProcessor (EURUSD,H1) Ticket of the order: 0 JS 0 17:37:53.233 TradeProcessor (EURUSD,H1) Status of the order: ORDER_STATE_STARTED JN 0 17:37:53.233 TradeProcessor (EURUSD,H1) Type of the order: ORDER_TYPE_BUY FD 0 17:37:53.233 TradeProcessor (EURUSD,H1) Price: 0.0000 FN 0 17:37:53.233 TradeProcessor (EURUSD,H1) Level of Stop Loss: 0.0000 HF 0 17:37:53.233 TradeProcessor (EURUSD,H1) Level of Take Profit: 0.0000 FQ 0 17:37:53.233 TradeProcessor (EURUSD,H1) Price that triggers the Stop Limit order: 0.0000 RR 0 17:37:53.233 TradeProcessor (EURUSD,H1) Trade symbol: HD 0 17:37:53.233 TradeProcessor (EURUSD,H1) Pending order expiration time: 1970.01.01 00:00 GS 0 17:37:53.233 TradeProcessor (EURUSD,H1) Order expiration type: ORDER_TIME_GTC DN 0 17:37:53.233 TradeProcessor (EURUSD,H1) Type of the trade transaction TRADE_TRANSACTION_REQUEST FK 0 17:37:53.233 TradeProcessor (EURUSD,H1) Volume in lots: 0.00
在这程序块中,只有关注事务类型的记录,才是我们感兴趣的。正如我们所见, 该类型属于 (TRADE_TRANSACTION_REQUEST) 请求。
有关请求的详情,可以在 “Request”程序块中获得。
QG 0 17:37:53.233 TradeProcessor (EURUSD,H1) ---===Request===--- HL 0 17:37:53.233 TradeProcessor (EURUSD,H1) Type of the trade operation: TRADE_ACTION_DEAL EE 0 17:37:53.233 TradeProcessor (EURUSD,H1) Comment to the order: JP 0 17:37:53.233 TradeProcessor (EURUSD,H1) Deviation from the requested price: 0 GS 0 17:37:53.233 TradeProcessor (EURUSD,H1) Order expiration time: 1970.01.01 00:00 LF 0 17:37:53.233 TradeProcessor (EURUSD,H1) Magic number of the EA: 0 FM 0 17:37:53.233 TradeProcessor (EURUSD,H1) Ticket of the order: 22535869 EJ 0 17:37:53.233 TradeProcessor (EURUSD,H1) Price: 1.3137 QR 0 17:37:53.233 TradeProcessor (EURUSD,H1) Stop Loss level of the order: 0.0000 IJ 0 17:37:53.233 TradeProcessor (EURUSD,H1) Take Profit level of the order: 0.0000 KK 0 17:37:53.233 TradeProcessor (EURUSD,H1) StopLimit level of the order: 0.0000 FS 0 17:37:53.233 TradeProcessor (EURUSD,H1) Trade symbol: EURUSD RD 0 17:37:53.233 TradeProcessor (EURUSD,H1) Type of the order: ORDER_TYPE_BUY
请求执行的结果数据,可以从 "Response" 程序块中获得。
KG 0 17:37:53.233 TradeProcessor (EURUSD,H1) ---===Response===--- JR 0 17:37:53.233 TradeProcessor (EURUSD,H1) Code of the operation result: 10009 GD 0 17:37:53.233 TradeProcessor (EURUSD,H1) Ticket of the deal: 15258202 NR 0 17:37:53.233 TradeProcessor (EURUSD,H1) Ticket of the order: 22535869 EF 0 17:37:53.233 TradeProcessor (EURUSD,H1) Volume of the deal: 0.11 MN 0 17:37:53.233 TradeProcessor (EURUSD,H1) Price of the deal: 1.3137 HJ 0 17:37:53.233 TradeProcessor (EURUSD,H1) Bid: 1.3135 PM 0 17:37:53.233 TradeProcessor (EURUSD,H1) Ask: 1.3137 OG 0 17:37:53.233 TradeProcessor (EURUSD,H1) Comment to the operation: RQ 0 17:37:53.233 TradeProcessor (EURUSD,H1) Request ID: 1
分析处理器的其它参数,如请求和响应的结构,您可以得到有关在第一次请求调用时的附加信息。
注意第二次调用是将订单加入到已开订单列表中 (图例. 2)。
图例.2. 类型字段等于 TRADE_TRANSACTION_ORDER_ADD
程序块 "Transaction" 是日志中我们唯一需要的东西。
MJ 0 17:41:12.280 TradeProcessor (EURUSD,H1) ---===Transaction===--- JN 0 17:41:12.280 TradeProcessor (EURUSD,H1) Ticket of the deal: 0 FG 0 17:41:12.280 TradeProcessor (EURUSD,H1) Type of the deal: DEAL_TYPE_BUY LM 0 17:41:12.280 TradeProcessor (EURUSD,H1) Ticket of the order: 22535869 LI 0 17:41:12.280 TradeProcessor (EURUSD,H1) Status of the order: ORDER_STATE_STARTED LP 0 17:41:12.280 TradeProcessor (EURUSD,H1) Type of the order: ORDER_TYPE_BUY QN 0 17:41:12.280 TradeProcessor (EURUSD,H1) Price: 1.3137 PD 0 17:41:12.280 TradeProcessor (EURUSD,H1) Level of Stop Loss: 0.0000 NL 0 17:41:12.280 TradeProcessor (EURUSD,H1) Level of Take Profit: 0.0000 PG 0 17:41:12.280 TradeProcessor (EURUSD,H1) Price that triggers the Stop Limit order: 0.0000 DL 0 17:41:12.280 TradeProcessor (EURUSD,H1) Trade symbol: EURUSD JK 0 17:41:12.280 TradeProcessor (EURUSD,H1) Pending order expiration time: 1970.01.01 00:00 QD 0 17:41:12.280 TradeProcessor (EURUSD,H1) Order expiration type: ORDER_TIME_GTC IQ 0 17:41:12.280 TradeProcessor (EURUSD,H1) Type of the trade transaction: TRADE_TRANSACTION_ORDER_ADD PL 0 17:41:12.280 TradeProcessor (EURUSD,H1) Volume in lots: 0.11
在订单中,我们可以看到,已经收到了单号和其它参数(品名,价格和交易量),并包含在已完成订单的列表中。
第三次调用事件处理器,是将订单从已开订单列表中删除 (图例. 3)。
图例.3. 类型字段等于 TRADE_TRANSACTION_ORDER_DELETE
程序块 "Transaction" 是日志中我们唯一需要的东西。
PF 0 17:52:36.722 TradeProcessor (EURUSD,H1) ---===Transaction===--- OE 0 17:52:36.722 TradeProcessor (EURUSD,H1) Ticket of the deal: 0 KL 0 17:52:36.722 TradeProcessor (EURUSD,H1) Type of the deal: DEAL_TYPE_BUY EH 0 17:52:36.722 TradeProcessor (EURUSD,H1) Ticket of the order: 22535869 QM 0 17:52:36.722 TradeProcessor (EURUSD,H1) Status of the order: ORDER_STATE_STARTED QK 0 17:52:36.722 TradeProcessor (EURUSD,H1) Type of the order: ORDER_TYPE_BUY HS 0 17:52:36.722 TradeProcessor (EURUSD,H1) Price: 1.3137 MH 0 17:52:36.722 TradeProcessor (EURUSD,H1) Level of Stop Loss: 0.0000 OP 0 17:52:36.722 TradeProcessor (EURUSD,H1) Level of Take Profit: 0.0000 EJ 0 17:52:36.722 TradeProcessor (EURUSD,H1) Price that triggers the Stop Limit order: 0.0000 IH 0 17:52:36.722 TradeProcessor (EURUSD,H1) Trade symbol: EURUSD KP 0 17:52:36.722 TradeProcessor (EURUSD,H1) Pending order expiration time: 1970.01.01 00:00 LO 0 17:52:36.722 TradeProcessor (EURUSD,H1) Order expiration type: ORDER_TIME_GTC HG 0 17:52:36.722 TradeProcessor (EURUSD,H1) Type of the trade transaction: TRADE_TRANSACTION_ORDER_DELETE CG 0 17:52:36.722 TradeProcessor (EURUSD,H1) Volume in lots: 0.11
这里除了事务类型,没有新信息。
第四次调用处理器,是当新的历史订单出现在历史数据里。 (图例. 4)。
图例.4. 类型字段等于 TRADE_TRANSACTION_HISTORY_ADD
我们可以从程序块 "Transaction" 得到相关信息。
QO 0 17:57:32.234 TradeProcessor (EURUSD,H1) ---===Transaction==--- RJ 0 17:57:32.234 TradeProcessor (EURUSD,H1) Ticket of the deal: 0 NS 0 17:57:32.234 TradeProcessor (EURUSD,H1) Type of the deal: DEAL_TYPE_BUY DQ 0 17:57:32.234 TradeProcessor (EURUSD,H1) Ticket of the order: 22535869 EH 0 17:57:32.234 TradeProcessor (EURUSD,H1) Status of the order: ORDER_STATE_FILLED RL 0 17:57:32.234 TradeProcessor (EURUSD,H1) Type of the order: ORDER_TYPE_BUY KJ 0 17:57:32.234 TradeProcessor (EURUSD,H1) Price: 1.3137 NO 0 17:57:32.234 TradeProcessor (EURUSD,H1) Level of Stop Loss: 0.0000 PI 0 17:57:32.234 TradeProcessor (EURUSD,H1) Level of Take Profit: 0.0000 FS 0 17:57:32.234 TradeProcessor (EURUSD,H1) Price that triggers the Stop Limit order: 0.0000 JS 0 17:57:32.234 TradeProcessor (EURUSD,H1) Trade symbol: EURUSD LG 0 17:57:32.234 TradeProcessor (EURUSD,H1) Pending order expiration time: 1970.01.01 00:00 KP 0 17:57:32.234 TradeProcessor (EURUSD,H1) Order expiration type: ORDER_TIME_GTC OL 0 17:57:32.234 TradeProcessor (EURUSD,H1) Type of the trade transaction: TRADE_TRANSACTION_HISTORY_ADD JH 0 17:57:32.234 TradeProcessor (EURUSD,H1) Volume in lots: 0.00
在此阶段, 我们可以看到订单已经被执行。
最后,成交订单被添加到历史记录时,第五次调用发生 (图例. 5)。
图例.5. 类型字段等于 TRADE_TRANSACTION_DEAL_ADD
在日志中, 我们同样只对程序块中的 "Transaction" 感兴趣。
OE 0 17:59:40.718 TradeProcessor (EURUSD,H1) ---===Transaction===--- MS 0 17:59:40.718 TradeProcessor (EURUSD,H1) Ticket of the deal: 15258202 RJ 0 17:59:40.718 TradeProcessor (EURUSD,H1) Type of the deal: DEAL_TYPE_BUY HN 0 17:59:40.718 TradeProcessor (EURUSD,H1) Ticket of the order: 22535869 LK 0 17:59:40.718 TradeProcessor (EURUSD,H1) Status of the order: ORDER_STATE_STARTED LE 0 17:59:40.718 TradeProcessor (EURUSD,H1) Type of the order: ORDER_TYPE_BUY MM 0 17:59:40.718 TradeProcessor (EURUSD,H1) Price: 1.3137 PF 0 17:59:40.718 TradeProcessor (EURUSD,H1) Level of Stop Loss: 0.0000 NN 0 17:59:40.718 TradeProcessor (EURUSD,H1) Level of Take Profit: 0.0000 PI 0 17:59:40.718 TradeProcessor (EURUSD,H1) Price that triggers the Stop Limit order: 0.0000 DJ 0 17:59:40.718 TradeProcessor (EURUSD,H1) Trade symbol: EURUSD JM 0 17:59:40.718 TradeProcessor (EURUSD,H1) Pending order expiration time: 1970.01.01 00:00 QI 0 17:59:40.718 TradeProcessor (EURUSD,H1) Order expiration type: ORDER_TIME_GTC CK 0 17:59:40.718 TradeProcessor (EURUSD,H1) Type of the trade transaction: TRADE_TRANSACTION_DEAL_ADD RQ 0 17:59:40.718 TradeProcessor (EURUSD,H1) Volume in lots: 0.11
在这个程序块中,最重要的字符串是成交单号。
我将要提出的事务规划。对于仓位,它们只有两部分。第一部分看上去像图例. 6。
图例.6. 第一个事务流程规划
所有针对仓位处理的交易操作,都按照这个规划执行。此处仅有的例外就是修改仓位操作。最后的操作包括以下事务流程 (图例. 7)。
图例.7. 第二个事务流程规划
因此,修改仓位不能在成交和订单历史记录中被跟踪。
那里几乎是所有仓位的信息。
对于限价订单,应当注意的是,它们的操作只需较少事务。同时,订单处理时还有更多事务类型组合。
为修改订单,处理器被调用两次,类似于修改仓位。下单及删除订单则需要调用三次。该 TradeTransaction 事件在删除订单或执行时调用四次。
现在,我们将放置一个限价订单。我们需要在 MetaTrader 5 终端上,在任意图表中以调试模式启动 EA。
处理器的第一次调用将是请求连接 (图例. 8)。
图例.8. 类型字段等于 TRADE_TRANSACTION_REQUEST
日志中将包含以下条目:
IO 0 18:13:33.195 TradeProcessor (EURUSD,H1) ---===Transaction===--- NK 0 18:13:33.195 TradeProcessor (EURUSD,H1) Ticket of the deal: 0 RR 0 18:13:33.195 TradeProcessor (EURUSD,H1) Type of the deal: DEAL_TYPE_BUY DE 0 18:13:33.195 TradeProcessor (EURUSD,H1) Ticket of the order: 0 JS 0 18:13:33.195 TradeProcessor (EURUSD,H1) Status of the order: ORDER_STATE_STARTED JN 0 18:13:33.195 TradeProcessor (EURUSD,H1) Type of the order: ORDER_TYPE_BUY FD 0 18:13:33.195 TradeProcessor (EURUSD,H1) Price: 0.0000 FN 0 18:13:33.195 TradeProcessor (EURUSD,H1) Level of Stop Loss: 0.0000 HF 0 18:13:33.195 TradeProcessor (EURUSD,H1) Level of Take Profit: 0.0000 FQ 0 18:13:33.195 TradeProcessor (EURUSD,H1) Price that triggers the Stop Limit order: 0.0000 RR 0 18:13:33.195 TradeProcessor (EURUSD,H1) Trade symbol: HD 0 18:13:33.195 TradeProcessor (EURUSD,H1) Pending order expiration time: 1970.01.01 00:00 GS 0 18:13:33.195 TradeProcessor (EURUSD,H1) Order expiration type: ORDER_TIME_GTC DN 0 18:13:33.195 TradeProcessor (EURUSD,H1) Type of the trade transaction: TRADE_TRANSACTION_REQUEST FK 0 18:13:33.195 TradeProcessor (EURUSD,H1) Volume in lots: 0.00 NS 0 18:13:33.195 TradeProcessor (EURUSD,H1) QG 0 18:13:33.195 TradeProcessor (EURUSD,H1) ---===Request==--- IQ 0 18:13:33.195 TradeProcessor (EURUSD,H1) Type of the trade operation: TRADE_ACTION_PENDING OE 0 18:13:33.195 TradeProcessor (EURUSD,H1) Order comment: PQ 0 18:13:33.195 TradeProcessor (EURUSD,H1) Deviation from the requested price: 0 QS 0 18:13:33.195 TradeProcessor (EURUSD,H1) Order expiration time: 1970.01.01 00:00 FI 0 18:13:33.195 TradeProcessor (EURUSD,H1) Magic number of the EA: 0 CM 0 18:13:33.195 TradeProcessor (EURUSD,H1) Ticket of the order: 22535983 PK 0 18:13:33.195 TradeProcessor (EURUSD,H1) Price: 1.6500 KR 0 18:13:33.195 TradeProcessor (EURUSD,H1) Stop Loss level of the order: 0.0000 OI 0 18:13:33.195 TradeProcessor (EURUSD,H1) Take Profit level of the order: 0.0000 QK 0 18:13:33.195 TradeProcessor (EURUSD,H1) StopLimit level of the order: 0.0000 QQ 0 18:13:33.195 TradeProcessor (EURUSD,H1) Trade symbol: GBPUSD RD 0 18:13:33.195 TradeProcessor (EURUSD,H1) Type of the order: ORDER_TYPE_BUY_LIMIT LS 0 18:13:33.195 TradeProcessor (EURUSD,H1) Order execution type: ORDER_FILLING_RETURN MN 0 18:13:33.195 TradeProcessor (EURUSD,H1) Order expiration type: ORDER_TIME_GTC IK 0 18:13:33.195 TradeProcessor (EURUSD,H1) Volume in lots: 0.14 NS 0 18:13:33.195 TradeProcessor (EURUSD,H1) CD 0 18:13:33.195 TradeProcessor (EURUSD,H1) ---===Response===--- RQ 0 18:13:33.195 TradeProcessor (EURUSD,H1) Code of the operation result: 10009 JI 0 18:13:33.195 TradeProcessor (EURUSD,H1) Ticket of the deal: 0 GM 0 18:13:33.195 TradeProcessor (EURUSD,H1) Ticket of the order: 22535983 LF 0 18:13:33.195 TradeProcessor (EURUSD,H1) Volume of the deal: 0.14 JN 0 18:13:33.195 TradeProcessor (EURUSD,H1) Price of the deal: 0.0000 MK 0 18:13:33.195 TradeProcessor (EURUSD,H1) Bid: 0.0000 CM 0 18:13:33.195 TradeProcessor (EURUSD,H1) Ask: 0.0000 IG 0 18:13:33.195 TradeProcessor (EURUSD,H1) Comment to the operation: DQ 0 18:13:33.195 TradeProcessor (EURUSD,H1) Request ID: 1
第二次调用处理器将把订单加入到已开订单列表中 (图例. 9)。
图例.9. 类型字段等于 TRADE_TRANSACTION_ORDER_ADDED
在日志中我们只需看 "Transaction" 程序块。
HJ 0 18:17:02.886 TradeProcessor (EURUSD,H1) ---===Transaction===--- GQ 0 18:17:02.886 TradeProcessor (EURUSD,H1) Ticket of the deal: 0 CH 0 18:17:02.886 TradeProcessor (EURUSD,H1) Type of the deal: DEAL_TYPE_BUY RL 0 18:17:02.886 TradeProcessor (EURUSD,H1) Ticket of the order: 22535983 II 0 18:17:02.886 TradeProcessor (EURUSD,H1) Status of the order: ORDER_STATE_STARTED OG 0 18:17:02.886 TradeProcessor (EURUSD,H1) Type of the order: ORDER_TYPE_BUY_LIMIT GL 0 18:17:02.886 TradeProcessor (EURUSD,H1) Price: 1.6500 IE 0 18:17:02.886 TradeProcessor (EURUSD,H1) Level of Stop Loss: 0.0000 CO 0 18:17:02.886 TradeProcessor (EURUSD,H1) Level of Take Profit: 0.0000 IF 0 18:17:02.886 TradeProcessor (EURUSD,H1) Price that triggers the Stop Limit order: 0.0000 PL 0 18:17:02.886 TradeProcessor (EURUSD,H1) Trade symbol: GBPUSD OL 0 18:17:02.886 TradeProcessor (EURUSD,H1) Pending order expiration time: 1970.01.01 00:00 HJ 0 18:17:02.886 TradeProcessor (EURUSD,H1) Order expiration type: ORDER_TIME_GTC LF 0 18:17:02.886 TradeProcessor (EURUSD,H1) Type of the trade transaction: TRADE_TRANSACTION_ORDER_ADD FR 0 18:17:02.886 TradeProcessor (EURUSD,H1) Volume in lots: 0.14
第三次调用处理器将根据放置的订单刷新数据 (图例. 10)。
特别是,订单状态将接收到 ORDER_STATE_PLACED 的值。
图例.10. 类型字段等于 TRADE_TRANSACTION_ORDER_UPDATE
在日志中, 我们只需看 "Transaction" 程序块中的记录。
HS 0 18:21:27.004 TradeProcessor (EURUSD,H1) ---===Transaction==--- GF 0 18:21:27.004 TradeProcessor (EURUSD,H1) Ticket of the deal: 0 CO 0 18:21:27.004 TradeProcessor (EURUSD,H1) Type of the deal: DEAL_TYPE_BUY RE 0 18:21:27.004 TradeProcessor (EURUSD,H1) Ticket of the order: 22535983 KM 0 18:21:27.004 TradeProcessor (EURUSD,H1) Status of the order: ORDER_STATE_PLACED QH 0 18:21:27.004 TradeProcessor (EURUSD,H1) Type of the order: ORDER_TYPE_BUY_LIMIT EG 0 18:21:27.004 TradeProcessor (EURUSD,H1) Price: 1.6500 GL 0 18:21:27.004 TradeProcessor (EURUSD,H1) Level of Stop Loss: 0.0000 ED 0 18:21:27.004 TradeProcessor (EURUSD,H1) Level of Take Profit: 0.0000 GO 0 18:21:27.004 TradeProcessor (EURUSD,H1) Price that triggers the Stop Limit order: 0.0000 RE 0 18:21:27.004 TradeProcessor (EURUSD,H1) Trade symbol: GBPUSD QS 0 18:21:27.004 TradeProcessor (EURUSD,H1) Pending order expiration time: 1970.01.01 00:00 JS 0 18:21:27.004 TradeProcessor (EURUSD,H1) Order expiration type: ORDER_TIME_GTC RD 0 18:21:27.004 TradeProcessor (EURUSD,H1) Type of the trade transaction: TRADE_TRANSACTION_ORDER_UPDATE JK 0 18:21:27.004 TradeProcessor (EURUSD,H1) Volume in lots: 0.14
这里最重要的字符串是订单的状态。
不像仓位处理,限价订单处理不能由一个规划来实现。每次针对限价订单的操作,从事务类型的角度来看都是唯一的。
下限价订单将产生三次事务 (图例. 11)。
图例.11. 下限价订单事务流程
修改限价订单将产生两次事务 (图例. 12)。
图例.12. 修改限价订单事务流程
如果限价订单被删除, 则该 OnTradeTransaction() 处理器将被调用四次 (图例. 13)。
图例.13. 限价订单删除事务流程
删除限价订单由以下规划定义 (图例. 14)。
图例.14. 限价订单删除事务流程
触发限价订单,最后的交易操作将导致四种不同的事务 (图例. 15)。
图例.15. 限价订单激活事务流程
我不打算把每一个事务组合的日志条目带到这里。如果读者觉得倾向这样做,他们可以通过执行代码进行研判。
让我们通过最终用户的眼睛,来看看与 TradeTransaction 事件协同工作的程序。最终用户很可能需要一个程序,可以完美地与订单和仓位两者工作。程序员必须为 OnTradeTransaction() 编写代码,让它无论过程如何都可以识别所有事务和它们的组合 - 仓位或订单。理想情况下,该程序能够指出执行什么样的操作可以完成一系列事务流程。
在下面的例子中,一系列事务流程被使用。MQL5 的开发者通过以下声明:
因此,如果需求是写一个接近理想工作的程序,您可以改善建议样本,制作事务过程使之独立于事务到达顺序。
在一般情况下,仓位和订单可以有常见事务类型。此处有 11 种事务类型。其中仅有四种需要在来自终端的交易中处理:
我们不打算在本文中讨论它们。这些类型,取决于开发者,可以设计用来扩展交易服务器端的功能。我必须承认,我以前还没有处理过这些类型。
这样留给我们七个功能齐全的类型,从 OnTradeTransaction() 中得到最常用的流程。
在处理器主体的这一段,定义了当前事务类型,具有极其重要的角色。
//--- ========== Types of transaction [START] switch(trans_type) { //--- 1) if it is a request case TRADE_TRANSACTION_REQUEST: { //--- break; } //--- 2) if it is an addition of a new open order case TRADE_TRANSACTION_ORDER_ADD: { //--- break; } //--- 3) if it is a deletion of an order from the list of open ones case TRADE_TRANSACTION_ORDER_DELETE: { //--- break; } //--- 4) if it is an addition of a new order to the history case TRADE_TRANSACTION_HISTORY_ADD: { //--- break; } //--- 5) if it is an addition of a deal to history case TRADE_TRANSACTION_DEAL_ADD: { //--- break; } //--- 6) if it is a modification of a position case TRADE_TRANSACTION_POSITION: { //--- break; } //--- 7) if it is a modification of an open order case TRADE_TRANSACTION_ORDER_UPDATE: { //--- break; } } //--- ========== Types of transactions [END]
我们将尝试定义什么样的交易操作,可由当前的事务类型来处理。要发现我们正在做什么 - 仓位或订单, 我们将交易操作的类型分派给 case 模块来处理请求。
该模块看起来如下所示:
//--- 1) if it is a request case TRADE_TRANSACTION_REQUEST: { //--- last_action=request.action; string action_str; //--- what is the request for? switch(last_action) { //--- а) on market case TRADE_ACTION_DEAL: { action_str="place a market order"; trade_obj=TRADE_OBJ_POSITION; break; } //--- б) place a pending order case TRADE_ACTION_PENDING: { action_str="place a pending order"; trade_obj=TRADE_OBJ_ORDER; break; } //--- в) modify position case TRADE_ACTION_SLTP: { trade_obj=TRADE_OBJ_POSITION; //--- StringConcatenate(action_str,request.symbol,": modify the levels of Stop Loss", " and Take Profit"); //--- break; } //--- г) modify order case TRADE_ACTION_MODIFY: { action_str="modify parameters of the pending order"; trade_obj=TRADE_OBJ_ORDER; break; } //--- д) delete order case TRADE_ACTION_REMOVE: { action_str="delete pending order"; trade_obj=TRADE_OBJ_ORDER; break; } } //--- if(InpIsLogging) Print("Request received: "+action_str); //--- break; }
在这种情况下改变一些变量并不困难。
static ENUM_TRADE_REQUEST_ACTIONS last_action; // market operation at the first pass
该 last_action 变量将记忆为什么事件处理器被启动。
static ENUM_TRADE_OBJ trade_obj; // specifies the trade object at the first pass
而变量 trade_obj 将保持记忆处理了什么 - 仓位或订单。为此,我们应创建 ENUM_TRADE_OBJ 枚举。
此后,我们将继续处理 TRADE_TRANSACTION_ORDER_ADD 事务类型的模块:
//--- 2) if it is an addition of a new open order case TRADE_TRANSACTION_ORDER_ADD: { if(InpIsLogging) { if(trade_obj==TRADE_OBJ_POSITION) Print("Open a new market order: "+ EnumToString(trans.order_type)); //--- else if(trade_obj==TRADE_OBJ_ORDER) Print("Place a new pending order: "+ EnumToString(trans.order_type)); } //--- break; }
这个模块是相当简单的。由于仓位在第一步处理,日志条目 "Open a new market order" 将出现在当前地方,否则为 "Place a new pending order"。在这个区块中,没有其它更多动作的信息。
现在轮到第三个模块,处理 TRADE_TRANSACTION_ORDER_DELETE 类型:
//--- 3) if it is a deletion of an order from the list of open ones case TRADE_TRANSACTION_ORDER_DELETE: { if(InpIsLogging) PrintFormat("Order deleted from the list of open ones: #%d, "+ EnumToString(trans.order_type),trans.order); //--- break; }
该模块也仅具有一个角色。
第四个 case-模块处理 TRADE_TRANSACTION_HISTORY_ADD 类型:
//--- 4) if it is an addition of a new order to the history case TRADE_TRANSACTION_HISTORY_ADD: { if(InpIsLogging) PrintFormat("Order added to the history: #%d, "+ EnumToString(trans.order_type),trans.order); //--- if a pending order is being processed if(trade_obj==TRADE_OBJ_ORDER) { //--- if it is the third pass if(gTransCnt==2) { //--- if the order was canceled, check the deals datetime now=TimeCurrent(); //--- request the history of orders and deals HistorySelect(now-PeriodSeconds(PERIOD_H1),now); //--- attempt to find a deal for the order CDealInfo myDealInfo; int all_deals=HistoryDealsTotal(); //--- bool is_found=false; for(int deal_idx=all_deals;deal_idx>=0;deal_idx--) if(myDealInfo.SelectByIndex(deal_idx)) if(myDealInfo.Order()==trans.order) is_found=true; //--- if the deal was not found if(!is_found) { is_to_reset_cnt=true; //--- PrintFormat("Order canceled: #%d",trans.order); } } //--- if it is the fourth pass if(gTransCnt==3) { is_to_reset_cnt=true; PrintFormat("Order deleted: #%d",trans.order); } } //--- break; }
此外,该订单被添加到历史记录,这个模块将进行检查,是否我们处理的是限价订单。在我们完成的情况下,我们需要找出当前哪些数字要传递到处理器。若限价订单被取消,事务类型将会在第三次传递时出现。当限价订单被删除时,该类型将会在第四次传递时出现。
模块在第三次传递时检查字符串,我们需要再次参考成交历史。如果订单未发现成交,我们认为此订单已被取消。
第五个 case-模块处理 TRADE_TRANSACTION_DEAL_ADD 类型。按照字符串尺寸计算,这是程序的最大模块。
在此块中检查成交。重要的是按照单号选择成交来获取它的属性。如果仓位已开或已平,则可以提供成交类型。限价订单的触发信息也可在此获取。有一种情况,在 TradeTransaction 事件处理器工作时,限价订单成交。
//--- 5) if it is an addition of a deal to history case TRADE_TRANSACTION_DEAL_ADD: { is_to_reset_cnt=true; //--- ulong deal_ticket=trans.deal; ENUM_DEAL_TYPE deal_type=trans.deal_type; //--- if(InpIsLogging) PrintFormat("Deal added to history: #%d, "+EnumToString(deal_type),deal_ticket); if(deal_ticket>0) { datetime now=TimeCurrent(); //--- request the history of orders and deals HistorySelect(now-PeriodSeconds(PERIOD_H1),now); //--- select a deal by the ticket if(HistoryDealSelect(deal_ticket)) { //--- check the deal CDealInfo myDealInfo; myDealInfo.Ticket(deal_ticket); long order=myDealInfo.Order(); //--- parameters of the deal ENUM_DEAL_ENTRY deal_entry=myDealInfo.Entry(); double deal_vol=0.; //--- if(myDealInfo.InfoDouble(DEAL_VOLUME,deal_vol)) if(myDealInfo.InfoString(DEAL_SYMBOL,deal_symbol)) { //--- position CPositionInfo myPos; double pos_vol=WRONG_VALUE; //--- if(myPos.Select(deal_symbol)) pos_vol=myPos.Volume(); //--- if the market was entered if(deal_entry==DEAL_ENTRY_IN) { //--- 1) opening of a position if(deal_vol==pos_vol) PrintFormat("\n%s: new position opened",deal_symbol); //--- 2) addition to the open position else if(deal_vol<pos_vol) PrintFormat("\n%s: addition to the current position",deal_symbol); } //--- if the market was exited else if(deal_entry==DEAL_ENTRY_OUT) { if(deal_vol>0.0) { //--- 1) closure of a position if(pos_vol==WRONG_VALUE) PrintFormat("\n%s: position closed",deal_symbol); //--- 2) partial closure of the open position else if(pos_vol>0.0) PrintFormat("\n%s: partial closing of the current position",deal_symbol); } } //--- if position was reversed else if(deal_entry==DEAL_ENTRY_INOUT) { if(deal_vol>0.0) if(pos_vol>0.0) PrintFormat("\n%s: position reversal",deal_symbol); } } //--- order activation if(trade_obj==TRADE_OBJ_ORDER) PrintFormat("Pending order activation: %d",order); } } //--- break; }
事务类型 TRADE_TRANSACTION_POSITION 是唯一的,并仅在仓位被修改时处理:
//--- 6) if it is a modification of a position case TRADE_TRANSACTION_POSITION: { is_to_reset_cnt=true; //--- PrintFormat("Modification of a position: %s",deal_symbol); //--- if(InpIsLogging) { PrintFormat("New price of stop loss: %0."+ IntegerToString(_Digits)+"f",trans.price_sl); PrintFormat("New price of take profit: %0."+ IntegerToString(_Digits)+"f",trans.price_tp); } //--- break; }
最后的 case-模块启用处理 TRADE_TRANSACTION_ORDER_UPDATE 类型。
这个类型只出现在与限价订单工作时。它在任意交易操作触发时启动,关注限价订单,尽管状态可能会变化。
//--- 7) if it is a modification of an open order case TRADE_TRANSACTION_ORDER_UPDATE: { //--- if it was the first pass if(gTransCnt==0) { trade_obj=TRADE_OBJ_ORDER; PrintFormat("Canceling the order: #%d",trans.order); } //--- if it was the second pass if(gTransCnt==1) { //--- if it is an order modification if(last_action==TRADE_ACTION_MODIFY) { PrintFormat("Pending order modified: #%d",trans.order); //--- clear counter is_to_reset_cnt=true; } //--- if it is deletion of the order if(last_action==TRADE_ACTION_REMOVE) { PrintFormat("Delete pending order: #%d",trans.order); } } //--- if it was the third pass if(gTransCnt==2) { PrintFormat("A new pending order was placed: #%d, "+ EnumToString(trans.order_type),trans.order); //--- clear counter is_to_reset_cnt=true; } //--- break; }
总结,如果在第一次触发 OnTradeTransaction() 时此类型出现,则订单既可能被取消,或被执行。
如果在第二次启动事件处理器时此类型出现,则订单既可能被删除,或被修改。为了找出订单的确凿结果,参考包含最后交易操作的静态变量 last_action。
第三次启动事件处理器是此类型出现的最后情况。第三次启动完成下限价订单的过程。
一个布尔变量 is_to_reset_cnt 也在代码中被使用。它作为标志用于清除 OnTradeTransaction() 处理器的传递计数。
这几乎是全部的有关 TradeTransaction 事件流程。我还在调用处理器的开头,添加了一个暂停。在被移至历史数据前,它为成交或订单提供了少许延迟机会。
在本文中,我尝试描绘有哪些不同的交易操作可以使用,以及如何能够检索有关在终端里发生的事件信息。
这种方法的最大好处是,程序可以接收有关交易操作的分阶段实施信息。在我看来,这种方式可用于复制一个终端的交易到另一个终端。
本社区仅针对特定人员开放
查看需注册登录并通过风险意识测评
5秒后跳转登录页面...
移动端课程