Guia Prático do MQL5: Processamento do Evento TradeTransaction
Introdução
Neste artigo eu gostaria de apresentar uma das maneiras de controlar os eventos de negociação utilizando os meios que a linguagem MQL5 nos proporciona. Devo mencionar que alguns artigos já foram dedicados a este tema. "Processamento de eventos trade no Expert Advisor usando a função OnTrade()" é um deles. Mas, ao contrário do material mencionado acima, usarei outro manipulador - OnTradeTransaction().
Eu gostaria de chamar a atenção dos leitores para o seguinte ponto. A versão atual da linguagem MQL5 conta formalmente com 14 manipuladores de eventos no Terminal Cliente. Além disso, o programador tem a possibilidade de criar eventos personalizados com o EventChartCustom() e processá-los com a OnChartEvent(). No entanto, o termo "programação orientada a eventos" ou "EDP" em inglês, não é mencionado na documentação. Isso é estranho devido ao fato de que qualquer programa em MQL5 é criado com base nos princípios da EDP. Por exemplo, quando o usuário necessita fazer uma escolha no passo do "manipulador de eventos para do Expert" em um template de qualquer Expert Advisor.
É óbvio que o mecanismo da programação orientada a eventos é usado em MQL5, de uma forma ou de outra. A linguagem pode conter blocos de programa que consiste em duas partes: na seleção e no processamento de um evento. Além disso, se estamos falando dos eventos do Terminal Cliente, o programador tem controle apenas sobre a segunda parte, ou seja, o manipulador de eventos. Para ser justo, há exceções para alguns eventos. O temporizador e o evento personalizado estão entre eles. O controle desses eventos é deixado inteiramente para o programador.
1. Evento TradeTransaction
Antes de ir a fundo em nosso tema, vamos consultar a informação oficial.
De acordo com a documentação, o evento TradeTransaction é um resultado de certas operações com a conta de negociação. Uma operação em si, consiste de uma série de etapas determinadas pelas transações. Por exemplo, abrir uma posição com uma ordem a mercado, ela é uma das operações mais populares em uma conta de negociação e é implementada nas seguintes etapas:
- Faça um pedido de negociação;
- Verifique se a solicitação de negociação;
- Envie a solicitação de negociação para o servidor;
- Receba uma resposta sobre a execução das ordens de negociação no servidor.
Essa sequência, no entanto, só mostra a lógica do funcionamento das conexões entre o terminal e o servidor, que se refletem nas linhas de código do EA. Do ponto de vista do evento de negociação TradeTransaction, a abertura de uma posição no mercado acontece da seguinte forma:
- O programa em MQL5 recebe uma notificação do servidor sobre o resultado da realização de seu pedido;
- O pedido, na forma de uma ordem com um ticket único é incluído na lista de ordens em aberto;
- A ordem é excluída da lista de pedidos em aberto após sua execução;
- Então, a ordem vai para o histórico da conta;
- No histórico da conta também contém os dados sobre os negócios que foram resultados das execuções das ordens.
Assim, a abertura de uma posição requer cinco chamadas para o manipulador OnTradeTransaction().
Nós vamos discutir o código do programa em detalhes um pouco mais tarde, agora vamos dar uma olhada mais de perto sobre o cabeçalho da função. Ele possui três parâmetros de entrada.
void OnTradeTransaction( const MqlTradeTransaction& trans, // estrutura de transação da negociação const MqlTradeRequest& request, // estrutura de solicitação const MqlTradeResult& result // estrutura de resposta );
Estes parâmetros são descritos em detalhes na documentação. Eu gostaria de destacar que o parâmetro da estrutura da transação de negociação é uma espécie de molde da informação de que o manipulador receberá durante a chamada atual.
Devo dizer também algumas palavras sobre o tipo de transação de negociação que iremos nos deparar com frequência.
Em MQL5, ENUM_TRADE_TRANSACTION_TYPE é uma enumeração especial, que é responsável pelo tipo de operação de negociação. Para descobrir qual o tipo de transação de negociação ela pertence, é preciso consultar o parâmetro da constante do tipo MqlTradeTransaction.
struct MqlTradeTransaction { ulong deal; // Ticket da operação ulong order; // Ticket da ordem string symbol; // Nome do instrumento de negociação ENUM_TRADE_TRANSACTION_TYPE type; // Tipo da transação de negociação ENUM_ORDER_TYPE order_type; // Tipo da ordem ENUM_ORDER_STATE order_state; // Estado da ordem ENUM_DEAL_TYPE deal_type; // Tipo da operação ENUM_ORDER_TYPE_TIME time_type; // Tipo de expiração da ordem datetime time_expiration; // Tempo de expiração da ordem double price; // Preço double price_trigger; // Preço que aciona a ordem de Stop Limit double price_sl; // Nível de Stop Loss double price_tp; // Nível de Take Profit double volume; // Volume em lotes };
O quarto campo da estrutura é a enumeração que estamos procurando.
2. Processamento de Posições
Praticamente todas as operações de negociação que estão relacionadas ao processamento de posições envolvem cinco chamadas do manipulador OnTradeTransaction(). Entre eles estão:
- abertura de uma posição;
- posição;
- inversão da posição;
- aumentar uma posição;
- fechamento parcial de uma posição.
A Modificação da posição é a única operação de negociação que chama o manipulador de eventos TradeTransaction duas vezes.
Como não há informações sobre quais tipos de transações são responsáveis por certas operações de negociação, nós vamos encontrá-las por meio da tentativa e erro.
Antes disso, teremos que criar um modelo do Expert que irá conter o manipulador de eventos TradeTransaction. Eu chamei minha versão do modelo de TradeProcessor.mq5. Eu adicionei um recurso que permite exibir as informações dos valores dos campos da estrutura no log. Estes valores são os parâmetros do evento - manipulador. Analisar esses registros será demorado, mas no final irá compensar, uma vez que será possível ver o quadro geral do que está acontecendo.
Nós precisamos iniciar o Expert no modo de depuração em qualquer gráfico do terminal MetaTrader 5.
Abra uma posição manualmente e de uma olhada no código. A primeira chamada do manipulador será assim (Fig. 1).
Fig.1. O tipo do campo é igual ao TRADE_TRANSACTION_REQUEST
As entradas a seguir irão aparecer no log:
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
Neste bloco, é de interesse para nós somente o registro sobre o tipo de transação. Como podemos ver, este tipo pertence a solicitação (TRADE_TRANSACTION_REQUEST).
As informações sobre os detalhes da solicitação podem ser obtidas no bloco "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
Os dados sobre o resultado da execução da solicitação irá chegar ao bloco "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
Tendo analisado os outros parâmetros do manipulador, tal como as estruturas da solicitação e resposta, é possível obter informações adicionais sobre o pedido na primeira chamada.
A segunda chamada está relacionada em adicionar a ordem na lista de pedidos em aberto (Fig. 2).
Fig.2. O tipo do campo é igual ao TRADE_TRANSACTION_ORDER_ADD
O bloco "Transaction" é a única que nós precisamos no log.
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
A ordem, como se pode ver, já recebeu o seu ticket e os outros parâmetros (símbolo, preço e volume) e foi incluído na lista de pedidos em aberto.
A terceira chamada do manipulador de eventos está relacionada com a remoção da ordem na lista de ordens em aberto (Fig. 3).
Fig.3. O tipo do campo é igual ao TRADE_TRANSACTION_ORDER_DELETE
O bloco "Transaction" é a única que nós precisamos no log.
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
Não há novas informações neste bloco, exceto o tipo de transação.
O manipulador é chamado pela quarta vez quando uma nova ordem histórica aparece no histórico (Fig. 4).
Fig.4. O tipo do campo é igual ao TRADE_TRANSACTION_HISTORY_ADD
Podemos obter as informações relevantes a partir do bloco "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
Nesta fase, podemos ver que a ordem foi executada.
Finalmente, a última (o quinto) chamada ocorre quando um negócio é adicionado ao histórico (Fig. 5).
Fig.5. O tipo do campo é igual ao TRADE_TRANSACTION_DEAL_ADD
No registo, mais uma vez, estamos interessados apenas no bloco "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
O ponto importante neste bloco é o ticket do negócio.
Eu vou apresentar um esquema da transação. Para as posições haverá apenas dois deles. A primeira delas se parece com a figura em. 6.
Fig.6. O primeiro esquema do processo de transação
Todas as operações de negociação relacionadas com o processamento de posições estão de acordo com esse esquema. A única exceção é a operação de modificar uma posição. A última operação inclui o processamento das duas operações seguintes (Fig. 7).
Fig.7. O segundo esquema do processo de transação
Assim, a modificação de uma posição não pode ser rastreada no histórico de negócios e ordens.
Basicamente, isso é tudo sobre posições.
3. Processamento de Ordens Pendentes
No que diz respeito as ordens pendentes, deve-se notar que as operações desse tipo realizam menos transações. Ao mesmo tempo, há mais combinações dos tipos de transação quando se trabalha com ordens.
Para modificar uma ordem, o manipulador é chamado duas vezes, semelhante a modificação de uma posição. Colocar e remover uma ordem leva três chamadas. O evento TradeTransaction ocorre quatro vezes na remoção de uma ordem ou a sua execução.
Agora iremos colocar uma ordem pendente. Precisamos iniciar novamente o Expert no modo de depuração em qualquer gráfico do terminal MetaTrader 5.
A primeira chamada do manipulador estará relacionada com o pedido (Fig. 8).
Fig.8. O tipo do campo é igual ao TRADE_TRANSACTION_REQUEST
O registro conterá as seguintes entradas:
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
A segunda chamada do manipulador irá adicionar a ordem para a lista de ordens em aberto (Fig. 9).
Fig.9. O tipo do campo é igual ao TRADE_TRANSACTION_ORDER_ADDED
No registo, nós precisamos ver apenas o bloco "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
A terceira chamada do manipulador irá renovar os dados de acordo com a ordem colocada (Fig. 10).
Em particular, o estado da ordem irá receber o valor de ORDER_STATE_PLACED.
Fig.10. O tipo do campo é igual ao TRADE_TRANSACTION_ORDER_UPDATE
No registo, nós precisamos ver os registros para o bloco "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
A seqüência mais importante aqui é o estado da ordem.
Ao contrário do processamento de posições, o processamento de ordens pendentes não pode ser implementado por um esquema. Cada operação de negociação ligada a uma ordem pendente será exclusiva do ponto de vista dos tipos de operações de negociações.
A Colocação de uma ordem pendente terá três operações (Fig. 11).
Fig.11. Transações que processam a colocação de uma ordem pendente
A Modificação de uma ordem pendente irá gerar duas transações (Fig. 12).
Fig.12. Transações que processam a modificação de uma ordem pendente
Se a ordem pendente está para ser excluída, então o manipulador OnTradeTransaction() será chamado quatro vezes (Fig. 13).
Fig.13. Transações que processam a exclusão de uma ordem pendente
A remoção de uma ordem pendente é definida pelo seguinte esquema (Fig. 14).
Fig.14. Transações que processam a remoção de uma ordem pendente
E a última operação de negociação diz respeito a ativação de uma ordem pendente, que irá gerar quatro operações diferentes (Fig. 15).
Fig.15. Transações que processam a ativação de uma ordem pendente
Eu não vou mostrar as entradas de registro para cada combinação de transações. Se o leitor se sente tão inclinado, é possível estudá-los executando o código.
4. Manipulador Universal
Vamos dar uma olhada no programa que possibilita o trabalho com o evento TradeTransaction através dos olhos do usuário final. É muito provável que o usuário final necessite de um programa que possa trabalhar perfeitamente tanto com as ordens quanto com as posições. Um programador deve escrever o código para a OnTradeTransaction() de uma maneira que irá deixá-lo identificar todas as transações e suas combinações, independentemente do que foi processado - uma posição ou uma ordem. Idealmente, o programa deve ser capaz de indicar qual operação que foi executada após a conclusão do processamento de uma série de operações.
No exemplo abaixo, um processamento sequencial de uma transação é usada. O desenvolvedor da MQL5 afirma o seguinte no entanto:
Então, se a exigência é escrever um programa que trabalhe perto do ideal, você deve melhorar o exemplo sugerido e fazer o processamento de transações independente da ordem de chegada das transações.
Em geral, as posições e as ordens podem possuir tipos comuns de transações. Existem 11 tipos de transações. Apenas quatro deles tem algo a ver com a negociação do terminal:
- TRADE_TRANSACTION_DEAL_UPDATE;
- TRADE_TRANSACTION_DEAL_DELETE;
- TRADE_TRANSACTION_HISTORY_UPDATE;
- TRADE_TRANSACTION_HISTORY_DELETE.
Nós não vamos discuti-los neste artigo. Estes tipos, de acordo com o desenvolvedor, foram projetados para estender a funcionalidade do lado do servidor de negociação. Devo admitir que eu nunca lidei com esses tipos antes.
Isso nos deixa com sete tipos completos que são processados, na maioria das vezes, na OnTradeTransaction().
No corpo do manipulador, o segmento que define o tipo de operação atual terá um importante papel.
//--- ========== Tipos de transação[START] switch(trans_type) { //--- 1) se for um pedido case TRADE_TRANSACTION_REQUEST: { //--- break; } //--- 2) se for uma adição de uma nova ordem aberta case TRADE_TRANSACTION_ORDER_ADD: { //--- break; } //--- 3) se for a remoção de uma ordem da lista de ordens em aberto case TRADE_TRANSACTION_ORDER_DELETE: { //--- break; } //--- 4) se for uma adição de uma nova ordem para o histórico case TRADE_TRANSACTION_HISTORY_ADD: { //--- break; } //--- 5) se for uma adição de um negócio para o histórico case TRADE_TRANSACTION_DEAL_ADD: { //--- break; } //--- 6) se for uma modificação de uma posição case TRADE_TRANSACTION_POSITION: { //--- break; } //--- 7) se for uma modificação de uma ordem em aberto case TRADE_TRANSACTION_ORDER_UPDATE: { //--- break; } } //--- ========== Tipos de transação [END]
Vamos tentar definir qual operação de negociação estaremos processando pelo tipo de transação atual. Para descobrir com qual estamos trabalhando - uma posição ou uma ordem, devemos lembrar o tipo de operação de negociação para o caso do módulo de processamento do pedido.
Assim, o módulo em si terá o seguinte aspecto:
//--- 1) se é um pedido case TRADE_TRANSACTION_REQUEST: { //--- last_action=request.action; string action_str; //--- para que é o pedido? switch(last_action) { //--- а) a mercado case TRADE_ACTION_DEAL: { action_str="Coloque uma ordem a mercado"; trade_obj=TRADE_OBJ_POSITION; break; } //--- б) colocar uma ordem pendente case TRADE_ACTION_PENDING: { action_str="Coloque uma ordem pendente"; trade_obj=TRADE_OBJ_ORDER; break; } //--- в) modificar uma posição case TRADE_ACTION_SLTP: { trade_obj=TRADE_OBJ_POSITION; //--- StringConcatenate(action_str,request.symbol,": modificar os níveis de Stop Loss", " e Take Profit"); //--- break; } //--- г) modificar uma ordem case TRADE_ACTION_MODIFY: { action_str="modificar os parâmetros de uma ordem pendente"; trade_obj=TRADE_OBJ_ORDER; break; } //--- д) remover uma ordem case TRADE_ACTION_REMOVE: { action_str="remover uma ordem pendente"; trade_obj=TRADE_OBJ_ORDER; break; } } //--- if(InpIsLogging) Print("Solicitação recebida: "+action_str); //--- break; }
Nnão é difícil, neste caso, alterar algumas variáveis .
static ENUM_TRADE_REQUEST_ACTIONS last_action; // Operação do mercado no primeiro passo
A variável last_action irá memorizar o porque do manipulador de eventos ter sido iniciado.
static ENUM_TRADE_OBJ trade_obj; // Especifica o objeto de negociação na primeira passagem
A variável trade_obj irá manter na memória o que foi processada - uma posição ou uma ordem. Para isso vamos criar a enumeração ENUM_TRADE_OBJ.
Depois disso, vamos avançar para o módulo que irá processar as transações do tipo TRADE_TRANSACTION_ORDER_ADD:
//--- 2) se é uma adição de uma nova ordem em aberto case TRADE_TRANSACTION_ORDER_ADD: { if(InpIsLogging) { if(trade_obj==TRADE_OBJ_POSITION) Print("Abra uma nova ordema a mercado: "+ EnumToString(trans.order_type)); //--- else if(trade_obj==TRADE_OBJ_ORDER) Print("Coloque uma nova ordem pendente: "+ EnumToString(trans.order_type)); } //--- break; }
Este módulo é bastante simples. Desde que a posição foi processada no primeiro passo, uma entrada de registro "Abra uma nova ordema a mercado" aparecerá no registro atual, caso contrário, aparecerá "Coloque uma nova ordem pendente". Não há mais ações além de informativos neste bloco.
Agora é a vez do terceiro módulo que processa o tipo TRADE_TRANSACTION_ORDER_DELETE:
//--- 3) se for uma exclusão de uma ordem a partir da lista de ordens em aberto case TRADE_TRANSACTION_ORDER_DELETE: { if(InpIsLogging) PrintFormat("Order excluída da lista de ordens em aberto: #%d, "+ EnumToString(trans.order_type),trans.order); //--- break; }
Este módulo também tem apenas um papel informativo.
O quarto caso do módulo processa o tipo TRADE_TRANSACTION_HISTORY_ADD:
//--- 4) no caso da adição de uma ordem para o histórico case TRADE_TRANSACTION_HISTORY_ADD: { if(InpIsLogging) PrintFormat("foi adicionado ao histórico: #%d, "+ EnumToString(trans.order_type),trans.order); //--- Se uma ordem pendente é processada if(trade_obj==TRADE_OBJ_ORDER) { //--- Se se trata do terceiro passo if(gTransCnt==2) { //--- Se o pedido foi cancelado, verifique as negociações datetime now=TimeCurrent(); //--- solicita o histórico de ordens e posições HistorySelect(now-PeriodSeconds(PERIOD_H1),now); //--- Tentativa de encontrar um negócio para a ordem 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; //--- se o negócio não for encontrado if(!is_found) { is_to_reset_cnt=true; //--- PrintFormat("Ordem cancelada: #%d",trans.order); } } //--- se é o quarto passo if(gTransCnt==3) { is_to_reset_cnt=true; PrintFormat("Ordem removida: #%d",trans.order); } } //--- break; }
Além do registro de que a ordem foi adicionada ao histórico, este módulo realiza uma verificação se inicialmente viemos trabalhando com uma ordem pendente. Se assim for, temos de descobrir qual o número do passo atual que o manipulador possui. O fato é que esse tipo de transação pode aparecer no terceiro passo quando se trabalha com a ordem, caso uma ordem pendente seja cancelada. No quarto passo, este tipo pode aparecer quando uma ordem pendente for eliminada.
Nas strings do módulo de verificação do terceiro passo, é necessário consultar o histórico de transações novamente. Se a transação para a ordem atual não foi encontrado, então consideraremos como uma ordem cancelada.
O quinto módulo do caso processa o tipo TRADE_TRANSACTION_DEAL_ADD. Ele é o maior bloco do programa pelo tamanho das strings.
O negócio é verificado neste bloco. É importante escolher uma transação pelo ticket para obter acesso às suas propriedades. Um tipo de transação pode fornecer informações se a posição foi aberta, fechada, etc Informações sobre o acionamento de uma ordem pendente pode ser recuperada lá também. Ela é o único caso em que uma ordem pendente poderia gerar uma transação no contexto do trabalho do manipulador de eventos TradeTransaction.
//--- 5) no caso da adição de uma operação ao histórico 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("transação adicionada ao histórico: #%d, "+EnumToString(deal_type),deal_ticket); if(deal_ticket>0) { datetime now=TimeCurrent(); //--- solicitar o histórico de ordens e transações HistorySelect(now-PeriodSeconds(PERIOD_H1),now); //--- selecionar uma transação pelos seu ticket if(HistoryDealSelect(deal_ticket)) { //--- verificar a transação CDealInfo myDealInfo; myDealInfo.Ticket(deal_ticket); long order=myDealInfo.Order(); //--- parâmetros da transação 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)) { //--- posição CPositionInfo myPos; double pos_vol=WRONG_VALUE; //--- if(myPos.Select(deal_symbol)) pos_vol=myPos.Volume(); //--- se houve uma entrada no mercado if(deal_entry==DEAL_ENTRY_IN) { //--- 1) abertura de uma posição if(deal_vol==pos_vol) PrintFormat("\n%s: nova posição aberta",deal_symbol); //--- 2) adição de uma posição em aberto else if(deal_vol<pos_vol) PrintFormat("\n%s: adição para a posição atual",deal_symbol); } //--- se houve a saída do mercado 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: posição fechada",deal_symbol); //--- 2) fechamento parcial de uma posição em aberto else if(pos_vol>0.0) PrintFormat("\n%s: fechamento parcial da posição atual",deal_symbol); } } //--- se a posição for reversa else if(deal_entry==DEAL_ENTRY_INOUT) { if(deal_vol>0.0) if(pos_vol>0.0) PrintFormat("\n%s: posição reversa",deal_symbol); } } //--- ativação da ordem if(trade_obj==TRADE_OBJ_ORDER) PrintFormat("ativação da ordem pendente: %d",order); } } //--- break; }
O tipo de Transação TRADE_TRANSACTION_POSITION é único e só é processada quando uma posição é modificada:
//--- 6) se houve uma modificação da posição case TRADE_TRANSACTION_POSITION: { is_to_reset_cnt=true; //--- PrintFormat("Modificação da posição: %s",deal_symbol); //--- if(InpIsLogging) { PrintFormat("Novo preço de stop loss: %0."+ IntegerToString(_Digits)+"f",trans.price_sl); PrintFormat("Novo preço de take profit: %0."+ IntegerToString(_Digits)+"f",trans.price_tp); } //--- break; }
O último caso do módulo fica habilitado a processar o tipo TRADE_TRANSACTION_ORDER_UPDATE.
Este tipo aparece apenas para o trabalho com uma ordem pendente. Ele se incia ao acionamento de qualquer operação de negociação, em relação às ordens pendentes, no entanto, o estágio pode variar.
//--- 7) se houve uma modificação de uma posição em aberto case TRADE_TRANSACTION_ORDER_UPDATE: { //--- se é o primeiro passo if(gTransCnt==0) { trade_obj=TRADE_OBJ_ORDER; PrintFormat("Cancelando a ordem: #%d",trans.order); } //--- se é o segundo passo if(gTransCnt==1) { //--- se é uma modificação de ordem if(last_action==TRADE_ACTION_MODIFY) { PrintFormat("Ordem pendente modificada: #%d",trans.order); //--- limpa contador is_to_reset_cnt=true; } //--- se é uma remoção da ordem if(last_action==TRADE_ACTION_REMOVE) { PrintFormat("Remoção da ordem pendente: #%d",trans.order); } } //--- se é o terceiro passo if(gTransCnt==2) { PrintFormat("Uma nova ordem pendente foi colocada: #%d, "+ EnumToString(trans.order_type),trans.order); //--- limpa contador is_to_reset_cnt=true; } //--- break; }
Em suma, se este tipo apareceu no primeiro acionamento da OnTradeTransaction(), então, a ordem foi cancelada ou executada.
Se o tipo apareceu no segundo lançamento do manipulador de eventos, então, a ordem foi excluída ou modificada. Para descobrir exatamente qual ordem foi resultante, consulte a variável estática last_action que contém os dados sobre a última operação de negociação.
O terceiro lançamento do manipulador de eventos é o último caso, na qual este tipo pode aparecer. O terceiro lançamento conclui o procedimento de colocar uma ordem pendente.
Uma variável booleana is_to_reset_cnt é também utilizada no código. Ela desempenha o papel de uma flag para limpar o contador dos passos do manipulador OnTradeTransaction().
Basicamente, isso é tudo o que diz respeito sobre o processamento do evento TradeTransaction. Eu gostaria de acrescentar também uma pausa no início da chamada para o manipulador. Ela iria minimizar as chances de atraso de um negócio ou de uma ordem ao obter seu histórico.
Conclusão
Neste artigo eu tentei ilustrar como as diferentes operações de negociação podem ser trabalhadas e como se pode recuperar informações sobre as coisas que aconteceram no terminal.
A grande vantagem dessa abordagem está na possibilidade do programa receber informações por etapas sobre a implementação das operações de negociação. Em minha opinião, esta abordagem pode ser usada para copiar as ordens de um terminal para outro.
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/1111
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso