
Recetas MQL5 - procesamiento del evento TradeTransaction
Introducción
En este artículo me gustaría familiarizar al lector con uno de los métodos para controlar eventos comerciales con los medios de MQL5. Me gustaría decir de primeras que ya se han dedicado artículos a este tema, por ejemplo "Procesando los eventos de transacciones en el Expert Advisor por medio de la función OnTrade()". Pero a diferencia del material que acabamos de mencionar, yo utilizaré otro procesador, el OnTradeTransaction().
Me gustaría destacar el momento siguiente. En la versión actual del lenguaje MQL5, formalmente hay 14 procesadores de eventos del terminal de cliente. Además, el programador tiene la posibilidad de crear sus eventos personalizados mediante EventChartCustom() y procesarlos con ayuda de OnChartEvent(). Pero en ningún lugar de la Documentación se hace referencia a un término tal como «programación dirigida por eventos» (PED). Y es que precisamente teniendo en cuenta los principios de la PED se crea cualquier programa de MQL5. Tome cualquier plantilla de un futuro asesor, cuando en el paso «Procesadores de eventos para el asesor» se le propone al usuario que elija.
Resulta obvio que en MQL5, de una u otra forma, se utiliza un mecanismo de programación dirigida por eventos. En el lenguaje pueden haber bloques de programa que consten de dos partes: elección de evento y procesamiento de evento. Además, si se trata de eventos del terminal de cliente, entonces el programador solo tiene disponible la segunda parte, el procesador de eventos. Es cierto que para algunos eventos hay excepciones. A dichas excepciones pertenecen el temporizador y los eventos personalizados. El control de dichos eventos se cede por completo a los programadores.
1. Evento TradeTransaction
Y bien, vamos a reducir el objeto de nuestra atención al tema que ya hemos mencionado, recurramos a infomación oficial.
De acuerdo con la Documentación, el evento TradeTransaction es el resultado de la ejecución de determinadas acciones con la cuenta comercial. La propia acción consta de varias etapas, que son determinadas por las transacciones. Por ejemplo, una de las acciones más populares con la cuenta comercial - la apertura de posición mediante una orden de mercado - se realiza de la siguiente forma:
- Crear una orden comercial;
- Comprobar una orden comercial;
- Enviar la orden comercial al servidor;
- Obtener una respuesta sobre la ejecución de la orden comercial en el servidor.
Pero una secuencia así refleja más bien la lógica de trabajo de las conexiones terminal-servidor, lo cual se expresa en las líneas de código del asesor. Desde el punto de vista del evento comercial TradeTransaction, la apertura de posición según el mercado tiene lugar de la forma siguiente:
- El programa MQL5 recibe la notificación del servidor sobre el resultado de la realización de la solicitud;
- La solicitud en forma de orden, con un tiquet único, entra en la lista de órdenes abiertas;
- Tras ejecutarse, la orden es eliminada de la lista de órdenes abiertas;
- Después la orden pasa al historial;
- En la historia aparece la operación que constituye el resultado de la ejecución de la orden.
Al final, para abrir una posición se necesitaron 5 llamadas del procesador OnTradeTransaction().
Algo más tarde nos ocuparemos del código del programa, pero por ahora propongo dedicarnos al encabezado de la función-procesadora. Tiene 3 parámetros de entrada.
void OnTradeTransaction( const MqlTradeTransaction& trans, // estructura de la transacción comercial const MqlTradeRequest& request, // estructura de la petitición const MqlTradeResult& result // estructura de la respuesta );
Hay información detallada sobre los parámetros en la Documentación. Me gustaría destacar aquí que el parámetro de la estructura de la transacción comercial es una especie de molde de la información que el procesador de la transacción pudo recibir en la llamada actual.
Pienso que hay que decir unas cuantas palabras más sobre el tipo de transacción comercial, ya que nos lo encontraremos con frecuencia.
En el lenguaje MQL5 hay una enumeración especial, responsable del tipo de transacción comercial, la ENUM_TRADE_TRANSACTION_TYPE. Para saber a qué tipo pertenece esta u otra transacción comercial, hay que recurrir al parámetro-constante del tipo MqlTradeTransaction.
struct MqlTradeTransaction { ulong deal; // Tipo de operación ulong order; // Tiquet de la orden string symbol; // Nombre del instrumento comercial ENUM_TRADE_TRANSACTION_TYPE type; // Tipo de transacción comercial ENUM_ORDER_TYPE order_type; // Tipo de orden ENUM_ORDER_STATE order_state; // Estado de la orden ENUM_DEAL_TYPE deal_type; // Tipo de operación ENUM_ORDER_TYPE_TIME time_type; // Tipo de orden según su duración datetime time_expiration; // Tiempo de expiración de la orden double price; // Precio double price_trigger; // Precio de activación de la orden stop-limit double price_sl; // Nivel de Stop Loss double price_tp; // Nivel de Take Profit double volume; // Volumen en lotes };
El cuarto campo de la estructura es precisamente la enumeración buscada.
2. Procesamiento de la posición
Prácticamente todas los operaciones comerciales que están relacionadas con el procesamiento de las posiciones conllevan 5 llamadas del procesador OnTradeTransaction(). A este tipo de operaciones pertenecen:
- la apertura de posición;
- las posiciones;
- el viraje de posición;
- el añadido a una posición;
- la abreviación de una posición.
Solo una operación, la modificación de posición, llamará al procesador TradeTransactiondos veces.
Dado que en la documentación no hay información sobre qué tipo de transacciones son responsables de ciertos tipos concretos de acciones comerciales, podemos ponerlas a prueba independientemente con el método de prueba y error.
De manera preliminar habrá que crear la plantilla del futuro asesor, en el que debe estar presente necesariamente el procesador de eventos TradeTransaction. He llamado a mi versión de ese tipo de plantilla TradeProcessor.mq5. Le he añadido la posibilidad de mostrar información en el registro sobre los valores de los campos de estructura que sean parámetros de la función-desarrolladora. Con estas anotaciones habra que traérselas tiesas, como se dice, mientras las estemos analizando. Sin embargo, compensaremos los gastos posteriormente, ya que será posible ver la imagen general de lo que sucede.
En cualquier gráfico del terminal MetaTrader 5 hay que poner en marcha el asesor en el modo de depuración.
Abrimos de manera manual la posición y echamos un vistazo al código. La primera llamada del procesador será así (fig. 1).
Fig. 1. El campo type es igual a TRADE_TRANSACTION_REQUEST
En el registro aparecerán las siguientes anotaciones:
IO 0 17:37:53.233 TradeProcessor (EURUSD,H1) ---===Transacción===--- NK 0 17:37:53.233 TradeProcessor (EURUSD,H1) Tiquet de la operación: 0 RR 0 17:37:53.233 TradeProcessor (EURUSD,H1) Tipo de operación: DEAL_TYPE_BUY DE 0 17:37:53.233 TradeProcessor (EURUSD,H1) Tiquet de la orden: 0 JS 0 17:37:53.233 TradeProcessor (EURUSD,H1) Estado de la orden: ORDER_STATE_STARTED JN 0 17:37:53.233 TradeProcessor (EURUSD,H1) Tipo de la orden: ORDER_TYPE_BUY FD 0 17:37:53.233 TradeProcessor (EURUSD,H1) Precio: 0.0000 FN 0 17:37:53.233 TradeProcessor (EURUSD,H1) Nivel de Stop Loss: 0.0000 HF 0 17:37:53.233 TradeProcessor (EURUSD,H1) Nivel de Take Profit: 0.0000 FQ 0 17:37:53.233 TradeProcessor (EURUSD,H1) Precio de activación de la orden stop-limit: 0.0000 RR 0 17:37:53.233 TradeProcessor (EURUSD,H1) Instrumento comercial: HD 0 17:37:53.233 TradeProcessor (EURUSD,H1) Fecha de expiración de la orden pendiente: 1970.01.01 00:00 GS 0 17:37:53.233 TradeProcessor (EURUSD,H1) Tipo de orden según el tiempo de duración: ORDER_TIME_GTC DN 0 17:37:53.233 TradeProcessor (EURUSD,H1) Tipo de transacción comercial: TRADE_TRANSACTION_REQUEST FK 0 17:37:53.233 TradeProcessor (EURUSD,H1) Volumen en lotes: 0.00
En este bloque resulta interesante solo la anotación que está relacionada con el tipo de transacción. Vemos que el tipo se refería a la petición (TRADE_TRANSACTION_REQUEST).
En el bloque «Petición» podemos obtener información sobre los detalles de la solicitud.
QG 0 17:37:53.233 TradeProcessor (EURUSD,H1) ---===Petición===--- HL 0 17:37:53.233 TradeProcessor (EURUSD,H1) Tipo de acción ejecutada: TRADE_ACTION_DEAL EE 0 17:37:53.233 TradeProcessor (EURUSD,H1) Cometarios a la orden: JP 0 17:37:53.233 TradeProcessor (EURUSD,H1) Desviación con respecto al precio solicitado: 0 GS 0 17:37:53.233 TradeProcessor (EURUSD,H1) Plazo de expiración de la orden: 1970.01.01 00:00 LF 0 17:37:53.233 TradeProcessor (EURUSD,H1) Mágico del asesor: 0 FM 0 17:37:53.233 TradeProcessor (EURUSD,H1) Tiquet de la orden: 22535869 EJ 0 17:37:53.233 TradeProcessor (EURUSD,H1) Precio: 1.3137 QR 0 17:37:53.233 TradeProcessor (EURUSD,H1) Nivel de la orden Stop Loss: 0.0000 IJ 0 17:37:53.233 TradeProcessor (EURUSD,H1) Nivel de la orden Take Profit: 0.0000 KK 0 17:37:53.233 TradeProcessor (EURUSD,H1) Nivel de la orden StopLimit: 0.0000 FS 0 17:37:53.233 TradeProcessor (EURUSD,H1) Instrumento comercial: EURUSD RD 0 17:37:53.233 TradeProcessor (EURUSD,H1) Tipo de orden: ORDER_TYPE_BUY
Al bloque «Respuesta» llegarán los datos sobre el resultado de la ejecución de la solicitud.
KG 0 17:37:53.233 TradeProcessor (EURUSD,H1) ---===Respuesta===--- JR 0 17:37:53.233 TradeProcessor (EURUSD,H1) Código del resultado de la operación: 10009 GD 0 17:37:53.233 TradeProcessor (EURUSD,H1) Tiquet de la operación: 15258202 NR 0 17:37:53.233 TradeProcessor (EURUSD,H1) Tiquet de la orden: 22535869 EF 0 17:37:53.233 TradeProcessor (EURUSD,H1) Volumen de la operación: 0.11 MN 0 17:37:53.233 TradeProcessor (EURUSD,H1) Precio en la operación: 1.3137 HJ 0 17:37:53.233 TradeProcessor (EURUSD,H1) Precio de la demanda: 1.3135 PM 0 17:37:53.233 TradeProcessor (EURUSD,H1) Precio de la oferta: 1.3137 OG 0 17:37:53.233 TradeProcessor (EURUSD,H1) Comentarios sobre la operación: RQ 0 17:37:53.233 TradeProcessor (EURUSD,H1) Identificador de la petición: 1
Precisamente en la primera llamada se puede conocer información adicional sobre la petición, analizando otros parámetros del procesador, las estructuras de la petición y la respuesta.
La segunda llamada del procesador se refiere a la adición de la orden a la lista de órdenes abiertas (fig. 2).
Fig.2. El campo type es igual a TRADE_TRANSACTION_ORDER_ADD
En el registro solo resulta de interés el bloque «Transacción».
MJ 0 17:41:12.280 TradeProcessor (EURUSD,H1) ---===Transacción===--- JN 0 17:41:12.280 TradeProcessor (EURUSD,H1) Tiquet de la operación: 0 FG 0 17:41:12.280 TradeProcessor (EURUSD,H1) Tipo de operación: DEAL_TYPE_BUY LM 0 17:41:12.280 TradeProcessor (EURUSD,H1) Tiquet de la orden: 22535869 LI 0 17:41:12.280 TradeProcessor (EURUSD,H1) Estado de la orden: ORDER_STATE_STARTED LP 0 17:41:12.280 TradeProcessor (EURUSD,H1) Tipo de orden: ORDER_TYPE_BUY QN 0 17:41:12.280 TradeProcessor (EURUSD,H1) Precio: 1.3137 PD 0 17:41:12.280 TradeProcessor (EURUSD,H1) Nivel de Stop Loss: 0.0000 NL 0 17:41:12.280 TradeProcessor (EURUSD,H1) Nivel de Take Profit: 0.0000 PG 0 17:41:12.280 TradeProcessor (EURUSD,H1) Precio de activación de la orden stop-limit: 0.0000 DL 0 17:41:12.280 TradeProcessor (EURUSD,H1) Instrumento comercial: EURUSD JK 0 17:41:12.280 TradeProcessor (EURUSD,H1) Plazo de expiración de la orden pendiente: 1970.01.01 00:00 QD 0 17:41:12.280 TradeProcessor (EURUSD,H1) Tipo de orden según el tiempo de acción: ORDER_TIME_GTC IQ 0 17:41:12.280 TradeProcessor (EURUSD,H1) Tipo de transacción comercial: TRADE_TRANSACTION_ORDER_ADD PL 0 17:41:12.280 TradeProcessor (EURUSD,H1) Volumen en lotes: 0.11
Aquí podemos ver que la orden ya ha obtenido su tiquet y los parámetros por el estilo (símbolo, precio, volumen), y se encuentra en la lista de órdenes abiertas.
La tercera llamada del procesador está relacionada con la eliminación de la orden de la lista de órdenes abiertas (fig. 3).
Fig.3. El campo type es igual a TRADE_TRANSACTION_ORDER_DELETE
En el registro solo resulta de interés el bloque «Transacción».
PF 0 17:52:36.722 TradeProcessor (EURUSD,H1) ---===Transacción===--- OE 0 17:52:36.722 TradeProcessor (EURUSD,H1) Tiquet de la operación: 0 KL 0 17:52:36.722 TradeProcessor (EURUSD,H1) Tipo de operación: DEAL_TYPE_BUY EH 0 17:52:36.722 TradeProcessor (EURUSD,H1) Tiquet de la orden: 22535869 QM 0 17:52:36.722 TradeProcessor (EURUSD,H1) Estado de la orden: ORDER_STATE_STARTED QK 0 17:52:36.722 TradeProcessor (EURUSD,H1) Tipo de orden: ORDER_TYPE_BUY HS 0 17:52:36.722 TradeProcessor (EURUSD,H1) Precio: 1.3137 MH 0 17:52:36.722 TradeProcessor (EURUSD,H1) Nivel de Stop Loss: 0.0000 OP 0 17:52:36.722 TradeProcessor (EURUSD,H1) Nivel de Take Profit: 0.0000 EJ 0 17:52:36.722 TradeProcessor (EURUSD,H1) Precio de activación de la orden stop-limit: 0.0000 IH 0 17:52:36.722 TradeProcessor (EURUSD,H1) Instrumento comercial: EURUSD KP 0 17:52:36.722 TradeProcessor (EURUSD,H1) Plazo de expiración de la orden pendiente: 1970.01.01 00:00 LO 0 17:52:36.722 TradeProcessor (EURUSD,H1) Tipo de orden según el tiempo de acción: ORDER_TIME_GTC HG 0 17:52:36.722 TradeProcessor (EURUSD,H1) Tipo de transacción comercial: TRADE_TRANSACTION_ORDER_DELETE CG 0 17:52:36.722 TradeProcessor (EURUSD,H1) Volumen en lotes: 0.11
Aquí no hay nada nuevo, excepto el tipo de transacción.
El procesador se llama por cuarta vez cuando en la historia aparece una orden «histórica» nueva (fig. 4).
Fig.4. El campo type es igual a TRADE_TRANSACTION_HISTORY_ADD
Veamos el registro en el bloque «Transacción».
QO 0 17:57:32.234 TradeProcessor (EURUSD,H1) ---===Transacción===--- RJ 0 17:57:32.234 TradeProcessor (EURUSD,H1) Tiquet de la operación: 0 NS 0 17:57:32.234 TradeProcessor (EURUSD,H1) Tipo de operación: DEAL_TYPE_BUY DQ 0 17:57:32.234 TradeProcessor (EURUSD,H1) Tiquet de la orden: 22535869 EH 0 17:57:32.234 TradeProcessor (EURUSD,H1) Estado de la orden: ORDER_STATE_FILLED RL 0 17:57:32.234 TradeProcessor (EURUSD,H1) Tipo de orden: ORDER_TYPE_BUY KJ 0 17:57:32.234 TradeProcessor (EURUSD,H1) Precio: 1.3137 NO 0 17:57:32.234 TradeProcessor (EURUSD,H1) Nivel de Stop Loss: 0.0000 PI 0 17:57:32.234 TradeProcessor (EURUSD,H1) Nivel de Take Profit: 0.0000 FS 0 17:57:32.234 TradeProcessor (EURUSD,H1) Precio de activación de la orden stop-limit: 0.0000 JS 0 17:57:32.234 TradeProcessor (EURUSD,H1) Instrumento comercial: EURUSD LG 0 17:57:32.234 TradeProcessor (EURUSD,H1) Plazo de expiración de la orden pendiente: 1970.01.01 00:00 KP 0 17:57:32.234 TradeProcessor (EURUSD,H1) Tipo de orden según el tiempo de acción: ORDER_TIME_GTC OL 0 17:57:32.234 TradeProcessor (EURUSD,H1) Tipo de transacción comercial: TRADE_TRANSACTION_HISTORY_ADD JH 0 17:57:32.234 TradeProcessor (EURUSD,H1) Volumen en lotes: 0.00
En esta etapa vemos que la orden ha sido ejecutada.
Por última (y quinta) vez tiene lugar la llamada al añadir una operación a la historia (fig. 5).
Fig.5. El campo type es igual a TRADE_TRANSACTION_DEAL_ADD
En el registro de nuevo solo miramos el bloque «Transacción».
OE 0 17:59:40.718 TradeProcessor (EURUSD,H1) ---===Transacción===--- MS 0 17:59:40.718 TradeProcessor (EURUSD,H1) Tiquet de la operación: 15258202 RJ 0 17:59:40.718 TradeProcessor (EURUSD,H1) Tipo de operación: DEAL_TYPE_BUY HN 0 17:59:40.718 TradeProcessor (EURUSD,H1) Tiquet de la orden: 22535869 LK 0 17:59:40.718 TradeProcessor (EURUSD,H1) Estado de la orden: ORDER_STATE_STARTED LE 0 17:59:40.718 TradeProcessor (EURUSD,H1) Tipo de orden: ORDER_TYPE_BUY MM 0 17:59:40.718 TradeProcessor (EURUSD,H1) Precio: 1.3137 PF 0 17:59:40.718 TradeProcessor (EURUSD,H1) Nivel de Stop Loss: 0.0000 NN 0 17:59:40.718 TradeProcessor (EURUSD,H1) Nivel de Take Profit: 0.0000 PI 0 17:59:40.718 TradeProcessor (EURUSD,H1) Precio de activación de la orden stop-limit: 0.0000 DJ 0 17:59:40.718 TradeProcessor (EURUSD,H1) Instrumento comercial: EURUSD JM 0 17:59:40.718 TradeProcessor (EURUSD,H1) Plazo de expiración de la orden pendiente: 1970.01.01 00:00 QI 0 17:59:40.718 TradeProcessor (EURUSD,H1) Tipo de orden según el tiempo de acción: ORDER_TIME_GTC CK 0 17:59:40.718 TradeProcessor (EURUSD,H1) Tipo de transacción comercial: TRADE_TRANSACTION_DEAL_ADD RQ 0 17:59:40.718 TradeProcessor (EURUSD,H1) Volumen en lotes: 0.11
Un punto importante aquí es el tiquet de la operación.
Adjunto las plantillas de las conexiones de los tipos de transacción. Para las posiciones serán dos en total. La primera tiene el aspecto siguiente (fig. 6).
Fig.6. Primera plantilla de conexiones de los tipos de transacción
A esta plantilla se subordinan todas las operaciones comerciales relacionadas con el procesamiento de la posición, excepto una sola, la modificación de posición. La última operación incluye entre sus componentes el procesamiento de las dos transacciones siguientes (fig. 7).
Fig.7. Segunda plantilla de conexiones de los tipos de transacción
De esta forma, no es posible realizar un seguimiento de la modificación de posición en la historia de órdenes y operaciones.
En general, esto es todo en lo que respecta a las posiciones.
3. Procesamiento de órdenes pendientes
En lo que respecta a las órdenes pendientes, hay que destacar que se invierte un menor número de transacciones a la hora de operar con ellas. Pero, por otra parte, al trabajar con órdenes hay más combinaciones de tipos de transacciones.
Al modificar una orden, como en el caso de la modificación de la posición, se llamará dos veces al procesador. Aparecerán tres llamadas al establecer y cancelar una orden. El evento TradeTransaction ocurrirá cuatro veces al eliminar una orden o al activarse la misma.
Probemos a establecer una orden pendiente. En cualquier gráfico del terminal MetaTrader 5 hay que poner en marcha de nuevo el asesor en el modo de depuración.
La primera llamada del procesador estará relacionada con la petición (fig. 8).
Fig.8. El campo type es igual a TRADE_TRANSACTION_REQUEST
En el registro veremos las anotaciones siguientes:
IO 0 18:13:33.195 TradeProcessor (EURUSD,H1) ---===Transacción===--- NK 0 18:13:33.195 TradeProcessor (EURUSD,H1) Tiquet de la operacion: 0 RR 0 18:13:33.195 TradeProcessor (EURUSD,H1) Tipo de operación: DEAL_TYPE_BUY DE 0 18:13:33.195 TradeProcessor (EURUSD,H1) Tiquet de la orden: 0 JS 0 18:13:33.195 TradeProcessor (EURUSD,H1) Estado de la orden: ORDER_STATE_STARTED JN 0 18:13:33.195 TradeProcessor (EURUSD,H1) Tipo de orden: ORDER_TYPE_BUY FD 0 18:13:33.195 TradeProcessor (EURUSD,H1) Precio: 0.0000 FN 0 18:13:33.195 TradeProcessor (EURUSD,H1) Nivel de Stop Loss: 0.0000 HF 0 18:13:33.195 TradeProcessor (EURUSD,H1) Nivel de Take Profit: 0.0000 FQ 0 18:13:33.195 TradeProcessor (EURUSD,H1) Precio de activación de la orden stop-limit: 0.0000 RR 0 18:13:33.195 TradeProcessor (EURUSD,H1) Instrumento comercial: HD 0 18:13:33.195 TradeProcessor (EURUSD,H1) Plazo de expiración de la orden pendiente: 1970.01.01 00:00 GS 0 18:13:33.195 TradeProcessor (EURUSD,H1) Tipo de orden según el tiempo de acción: ORDER_TIME_GTC DN 0 18:13:33.195 TradeProcessor (EURUSD,H1) Tipo de transacción comercial: TRADE_TRANSACTION_REQUEST FK 0 18:13:33.195 TradeProcessor (EURUSD,H1) Volumen en lotes: 0.00 NS 0 18:13:33.195 TradeProcessor (EURUSD,H1) QG 0 18:13:33.195 TradeProcessor (EURUSD,H1) ---===Petición===--- IQ 0 18:13:33.195 TradeProcessor (EURUSD,H1) Tipo de acción realizada: TRADE_ACTION_PENDING OE 0 18:13:33.195 TradeProcessor (EURUSD,H1) Comentarios a la orden: PQ 0 18:13:33.195 TradeProcessor (EURUSD,H1) Desviación con respecto al precio requerido: 0 QS 0 18:13:33.195 TradeProcessor (EURUSD,H1) Plazo de expiración de la orden: 1970.01.01 00:00 FI 0 18:13:33.195 TradeProcessor (EURUSD,H1) Mágico del asesor: 0 CM 0 18:13:33.195 TradeProcessor (EURUSD,H1) Tiquet de la orden: 22535983 PK 0 18:13:33.195 TradeProcessor (EURUSD,H1) Precio: 1.6500 KR 0 18:13:33.195 TradeProcessor (EURUSD,H1) Nivel de la orden Stop Loss: 0.0000 OI 0 18:13:33.195 TradeProcessor (EURUSD,H1) Nivel de la ordenTake Profit: 0.0000 QK 0 18:13:33.195 TradeProcessor (EURUSD,H1) Nivel de la orden StopLimit: 0.0000 QQ 0 18:13:33.195 TradeProcessor (EURUSD,H1) Instrumento comercial: GBPUSD RD 0 18:13:33.195 TradeProcessor (EURUSD,H1) Tipo de orden: ORDER_TYPE_BUY_LIMIT LS 0 18:13:33.195 TradeProcessor (EURUSD,H1) Tipo de orden según la ejecución: ORDER_FILLING_RETURN MN 0 18:13:33.195 TradeProcessor (EURUSD,H1) Tipo de orden según el tiempo de acción: ORDER_TIME_GTC IK 0 18:13:33.195 TradeProcessor (EURUSD,H1) Volumen en lotes: 0.14 NS 0 18:13:33.195 TradeProcessor (EURUSD,H1) CD 0 18:13:33.195 TradeProcessor (EURUSD,H1) ---===Respuesta===--- RQ 0 18:13:33.195 TradeProcessor (EURUSD,H1) Código del resultado de la operación: 10009 JI 0 18:13:33.195 TradeProcessor (EURUSD,H1) Tiquet de la operación: 0 GM 0 18:13:33.195 TradeProcessor (EURUSD,H1) Tiquet de la orden: 22535983 LF 0 18:13:33.195 TradeProcessor (EURUSD,H1) Volumen de la operación: 0.14 JN 0 18:13:33.195 TradeProcessor (EURUSD,H1) Precio en la operación: 0.0000 MK 0 18:13:33.195 TradeProcessor (EURUSD,H1) Precio de demanda: 0.0000 CM 0 18:13:33.195 TradeProcessor (EURUSD,H1) Precio de oferta: 0.0000 IG 0 18:13:33.195 TradeProcessor (EURUSD,H1) Comentarios a la operación: DQ 0 18:13:33.195 TradeProcessor (EURUSD,H1) Identificador de la petición: 1
La segunda llamada al procesador añade la orden a la lista de órdenes abiertas (fig. 9).
Fig.9. El campo type es igual a TRADE_TRANSACTION_ORDER_ADDED
En el registro solo nos interesa el bloque «Transacción».
HJ 0 18:17:02.886 TradeProcessor (EURUSD,H1) ---===Transacción===--- GQ 0 18:17:02.886 TradeProcessor (EURUSD,H1) Tiquet de la operación: 0 CH 0 18:17:02.886 TradeProcessor (EURUSD,H1) Tipo de operación: DEAL_TYPE_BUY RL 0 18:17:02.886 TradeProcessor (EURUSD,H1) Tiquet de la orden: 22535983 II 0 18:17:02.886 TradeProcessor (EURUSD,H1) Estado de la orden: ORDER_STATE_STARTED OG 0 18:17:02.886 TradeProcessor (EURUSD,H1) Tipo de orden: ORDER_TYPE_BUY_LIMIT GL 0 18:17:02.886 TradeProcessor (EURUSD,H1) Precio: 1.6500 IE 0 18:17:02.886 TradeProcessor (EURUSD,H1) Nivel de Stop Loss: 0.0000 CO 0 18:17:02.886 TradeProcessor (EURUSD,H1) Nivel de Take Profit: 0.0000 IF 0 18:17:02.886 TradeProcessor (EURUSD,H1) Precio de activación de la orden stop-limit: 0.0000 PL 0 18:17:02.886 TradeProcessor (EURUSD,H1) Instrumento comercial: GBPUSD OL 0 18:17:02.886 TradeProcessor (EURUSD,H1) Plazo de expiración de la orden pendiente: 1970.01.01 00:00 HJ 0 18:17:02.886 TradeProcessor (EURUSD,H1) Tipo de orden según tiempo de acción: ORDER_TIME_GTC LF 0 18:17:02.886 TradeProcessor (EURUSD,H1) Tipo de transacción comercial: TRADE_TRANSACTION_ORDER_ADD FR 0 18:17:02.886 TradeProcessor (EURUSD,H1) Volumen en lotes: 0.14
La tercera llamada del procesador actualiza los datos sobre la orden establecida (fig. 10).
En concreto, el estado de la orden obtiene el valor ORDER_STATE_PLACED.
Fig.10. El campo type es igual a TRADE_TRANSACTION_ORDER_UPDATE
En el registro veremos las anotaciones sobre el bloque «Transacciones».
HS 0 18:21:27.004 TradeProcessor (EURUSD,H1) ---===Transacción===--- GF 0 18:21:27.004 TradeProcessor (EURUSD,H1) Tiquet de la operación: 0 CO 0 18:21:27.004 TradeProcessor (EURUSD,H1) Tipo de operación: DEAL_TYPE_BUY RE 0 18:21:27.004 TradeProcessor (EURUSD,H1) Tiquet de la orden: 22535983 KM 0 18:21:27.004 TradeProcessor (EURUSD,H1) Estado de la orden: ORDER_STATE_PLACED QH 0 18:21:27.004 TradeProcessor (EURUSD,H1) Tipo de orden: ORDER_TYPE_BUY_LIMIT EG 0 18:21:27.004 TradeProcessor (EURUSD,H1) Precio: 1.6500 GL 0 18:21:27.004 TradeProcessor (EURUSD,H1) Nivel de Stop Loss: 0.0000 ED 0 18:21:27.004 TradeProcessor (EURUSD,H1) NIvel de Take Profit: 0.0000 GO 0 18:21:27.004 TradeProcessor (EURUSD,H1) Precio de activación de la orden stop-limit: 0.0000 RE 0 18:21:27.004 TradeProcessor (EURUSD,H1) Instrumento comercial: GBPUSD QS 0 18:21:27.004 TradeProcessor (EURUSD,H1) Plazo de expiración de la orden pendiente: 1970.01.01 00:00 JS 0 18:21:27.004 TradeProcessor (EURUSD,H1) Tipo de orden según el tiempo de acción: ORDER_TIME_GTC RD 0 18:21:27.004 TradeProcessor (EURUSD,H1) Tipo de transacción comercial: TRADE_TRANSACTION_ORDER_UPDATE JK 0 18:21:27.004 TradeProcessor (EURUSD,H1) Volumen en lotes: 0.14
Una línea muy importante aquí es la del estado de la orden.
A diferencia de las posiciones, las órdenes pendientes, o más bien su procesamiento, no se pueden adaptar a una plantilla. Cada acción comercial relacionada con una orden pendiente será única desde el punto de vista del conjunto de tipos de transacciones comerciales.
Para el establecimiento de una orden pendiente será necesario realizar 3 transacciones (fig. 11).
Fig.11. Transacciones que procesan la creación de una orden pendiente
La modificación de una orden pendiente generará 2 transacciones (fig. 12).
Fig.12. Transacciones que procesan el cambio de una orden pendiente
Si es necesario eliminar una orden pendiente, enotnces el procesador OnTradeTransaction() será llamado 4 veces (fig. 13).
Fig.13. Transacciones que procesan la eliminación de una orden pendiente
La cancelación de una orden pendiente tiene lugar según el siguiente esquema (fig. 14).
Fig.14. Transacciones que procesan la cancelación de una orden pendiente
Y la última operación comercial - la activación de una orden pendiente - da lugar a 4 transacciones diferentes (fig. 15).
Fig.15. Transacciones que procesan la activación de una orden pendiente
No voy a mostrar anotaciones del registro sobre cada combinación de las transacciones. Si así lo desea el lector, puede estudiarlas por sí mismo, poniendo en marcha el código para su ejecución.
4. Procesador universal
Vamos a ver con los ojos del usuairio final un programa que sabe cómo trabajar con el evento TradeTransaction. Seguramente, el usuario necesitará justamente aquel que pueda trabajar bien tanto con órdenes, como con posiciones. Entones el programador debe escribir el código para el procesador OnTradeTransaction() de tal forma que el último sepa identificar todas las transacciones y sus combinaciones, independientemente de qué sea lo que se ha procesado, una orden o una posición. Además, es preferible que al terminar el procesamiento de la serie de transacciones, el programa pueda decir qué operación comercial se ha ejecutado.
En mi ejemplo se usa el procesamiento consecutivo de transacciones. Sin embargo, un desarrollador del lenguaje MQL5 afirma lo siguiente:
Por eso surge la necesidad de crear algo que funcione de manera casi ideal, hay que perfeccionar el ejemplo que propongo aquí y realizar el procesamiento de las transacciones independientemente de su sucesión en la llegada.
Hablando en general, las posiciones y órdenes pueden tener tipos de transacción comunes. Hay en total 11 tipos de transacciones. De ellas, 4 tipos tienen poca relación con el comercio desde el terminal:
- TRADE_TRANSACTION_DEAL_UPDATE;
- TRADE_TRANSACTION_DEAL_DELETE;
- TRADE_TRANSACTION_HISTORY_UPDATE;
- TRADE_TRANSACTION_HISTORY_DELETE.
Sobre estos tipos no se hablará en el artículo. Estos tipos, como anuncia el desarrollador, están contemplados para ampliar la funcionalidad por parte del servidor comercial. El autor del artículo reconoce que no se ha encontrado con dichos tipos de datos.
Solo quedan 7 tipos de pleno valor, que se suelen procesar en el bloque OnTradeTransaction().
En el cuerpo del procesador ocupará un lugar importante el apartado que determina el tipo de transacción actual.
//--- ========== Tipos de transacciones [START] switch(trans_type) { //--- 1) si se trata de una petición case TRADE_TRANSACTION_REQUEST: { //--- break; } //--- 2) si se trata de la adición de una nueva orden abierta case TRADE_TRANSACTION_ORDER_ADD: { //--- break; } //--- 3) si se trata de la eliminación de una orden de la lista de órdenes abiertas case TRADE_TRANSACTION_ORDER_DELETE: { //--- break; } //--- 4) si se trata de la adición de una orden a la historia case TRADE_TRANSACTION_HISTORY_ADD: { //--- break; } //--- 5) si se trata de la adición de una operación a la historia case TRADE_TRANSACTION_DEAL_ADD: { //--- break; } //--- 6) si trata de la modificación de una posición case TRADE_TRANSACTION_POSITION: { //--- break; } //--- 7) si se trata del cambio de una posición abierta case TRADE_TRANSACTION_ORDER_UPDATE: { //--- break; } } //--- ========== Tipos de transacciones [END]
Dependiendo de el tipo actual de transacción, probaremos a diagnosticar la operación comercial procesada. Para determinar con qué estamos trabajando, con una posición o con una orden, encargaremos al módulo case del procesamiento de la petición recordar el tipo de operación comercial.
Entonces, ese módulo tendrá el siguiente aspecto:
//--- 1) si se trata de una petición case TRADE_TRANSACTION_REQUEST: { //--- last_action=request.action; string action_str; //--- ¿una petición de qué? switch(last_action) { //--- а) según el mercado case TRADE_ACTION_DEAL: { action_str="poner una orden de mercado"; trade_obj=TRADE_OBJ_POSITION; break; } //--- б) establecer una orden pendiente case TRADE_ACTION_PENDING: { action_str="establecer una orden pendiente"; trade_obj=TRADE_OBJ_ORDER; break; } //--- в) cambiar la posición case TRADE_ACTION_SLTP: { trade_obj=TRADE_OBJ_POSITION; //--- StringConcatenate(action_str,request.symbol,": cambiar el valor de Stop Loss", " y Take Profit"); //--- break; } //--- г) cambiar una orden case TRADE_ACTION_MODIFY: { action_str="cambiar los parámetros de una orden pendiente"; trade_obj=TRADE_OBJ_ORDER; break; } //--- д) eliminar una orden case TRADE_ACTION_REMOVE: { action_str="eliminar una orden pendiente"; trade_obj=TRADE_OBJ_ORDER; break; } } //--- if(InpIsLogging) Print("Ha llegado una petición: "+action_str); //--- break; }
No es complicado notar varias variables.
static ENUM_TRADE_REQUEST_ACTIONS last_action; // acción de mercado en la primera pasada
La variable last_action recordará para qué se inició el funcionamiento del procesador.
static ENUM_TRADE_OBJ trade_obj; // establece un objeto comercial en la primera pasada
La variable trade_obj recordará qué se ha procesado, una posición o una orden. Para ello creará la enumeración ENUM_TRADE_OBJ.
A continuación, nos trasladamos al módulo que se ocuapará del procesamiento de la transacción del tipo TRADE_TRANSACTION_ORDER_ADD:
//--- 2) si se trata de la adición de una nueva orden abierta case TRADE_TRANSACTION_ORDER_ADD: { if(InpIsLogging) { if(trade_obj==TRADE_OBJ_POSITION) Print("Abrir una nueva orden de mercado: "+ EnumToString(trans.order_type)); //--- else if(trade_obj==TRADE_OBJ_ORDER) Print("Establecer una nueva orden pendiente: "+ EnumToString(trans.order_type)); } //--- break; }
Aquí todo es bastante sencillo. Si en el primer paso se ha procesado la posición, entonces en el paso actual aparecerá la entrada en el registro "Abrir una nueva orden de mercado: ", de lo contrario, aparecerá "Establecer una nueva orden pendiente:". Aparte de las acciones informativas, en este bloque no hay ningunas otras acciones.
Ahora echemos un vistazo al tercer módulo, el procesamiento del tipo TRADE_TRANSACTION_ORDER_DELETE:
//--- 3) si se trata de la eliminación de una orden de la lista de órdenes abiertas case TRADE_TRANSACTION_ORDER_DELETE: { if(InpIsLogging) PrintFormat("Eliminado de la lista de órdenes abiertas: #%d, "+ EnumToString(trans.order_type),trans.order); //--- break; }
El módulo, igualmente, lleva solo contenido de tipo informativo.
El cuarto módulo case procesa el tipo TRADE_TRANSACTION_HISTORY_ADD:
//--- 4) si se trata de la adición de una orden a la historia case TRADE_TRANSACTION_HISTORY_ADD: { if(InpIsLogging) PrintFormat("Se ha añadido a la historia una orden: #%d, "+ EnumToString(trans.order_type),trans.order); //--- si se procesa una orden pendiente if(trade_obj==TRADE_OBJ_ORDER) { //--- si se trata de la tercera pasada if(gTransCnt==2) { //--- si la orden ha sido cancelada, comprobar las operaciones datetime now=TimeCurrent(); //--- solicitar la historia de las órdenes y posiciones HistorySelect(now-PeriodSeconds(PERIOD_H1),now); //--- intento de encontrar una orden o posición 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; //--- si no se ha encontrado la operación if(!is_found) { is_to_reset_cnt=true; //--- PrintFormat("La orden ha sido cancelada: #%d",trans.order); } } //--- si se trata de la cuarta pasada if(gTransCnt==3) { is_to_reset_cnt=true; PrintFormat("La orden ha sido eliminada: #%d",trans.order); } } //--- break; }
En ella, además de la anotación acerca de la adición de la orden a la historia, existe la comprobación de si nos hallamos ya de por sí trabajando con una orden pendiente. De ser así, entonces comprobamos en qué pasada se encuentra el procesador actualmente. La cuestión es que este tipo de transacción puede aparecer al trabajar con una orden en la tercera pasada, si la orden pendiente ha sido cancelada o se ha activado. En la cuarta pasada este tipo puede aparecer cuando la orden pendiente sea eliminada por fuerza.
En las líneas de comprobación de la tercera pasada hay que recurrir aún a la historia de operaciones. Si para la orden actual no se va a encontrar operación, entonces tal orden se considerará cancelada.
El quinto módulo case procesa el tipo TRADE_TRANSACTION_DEAL_ADD. Se trata del mayor bloque del programa en cuanto a tamaño de líneas de código.
En él comprobamos la operación. Es importante elegir la operación según el tiquet, para obtener acceso a sus propiedades. Según el tipo de operación, se puede saber si la operación ha sido abierta, cerrada, etc. Asimismo, se puede obtener información sobre si se ha activado una orden pendiente. Este es el único caso cuando una orden pendiente puede dar lugar a una operación en el contexto de trabajo del procesador de eventos TradeTransaction.
//--- 5) si se trata de la adición de una operación a la historia 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("Se ha añadido a la historia una operación: #%d, "+EnumToString(deal_type),deal_ticket); if(deal_ticket>0) { datetime now=TimeCurrent(); //--- solicitar la historia de operaciones y órdenes HistorySelect(now-PeriodSeconds(PERIOD_H1),now); //--- elegir la operacion según el tiquet if(HistoryDealSelect(deal_ticket)) { //--- comprobar la operación CDealInfo myDealInfo; myDealInfo.Ticket(deal_ticket); long order=myDealInfo.Order(); //--- parámetros de la operacion 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)) { //--- posición CPositionInfo myPos; double pos_vol=WRONG_VALUE; //--- if(myPos.Select(deal_symbol)) pos_vol=myPos.Volume(); //--- si se ha realizado una entrada al mercado if(deal_entry==DEAL_ENTRY_IN) { //--- 1) apertura de posición if(deal_vol==pos_vol) PrintFormat("\n%s: se ha abierto una nueva posición",deal_symbol); //--- 2) adición a la posición abierta else if(deal_vol<pos_vol) PrintFormat("\n%s: adición a la posición actual",deal_symbol); } //--- si se ha realizado una salida del mercado else if(deal_entry==DEAL_ENTRY_OUT) { if(deal_vol>0.0) { //--- 1) cierre de posición if(pos_vol==WRONG_VALUE) PrintFormat("\n%s: posición cerrada",deal_symbol); //--- 2) reducción de la posición abierta else if(pos_vol>0.0) PrintFormat("\n%s: reducción de la posición actual",deal_symbol); } } //--- si se ha dado un viraje else if(deal_entry==DEAL_ENTRY_INOUT) { if(deal_vol>0.0) if(pos_vol>0.0) PrintFormat("\n%s: viraje de posición",deal_symbol); } } //--- activación de una orden if(trade_obj==TRADE_OBJ_ORDER) PrintFormat("Activación de una orden pendiente: %d",order); } } //--- break; }
El tipo de transacción TRADE_TRANSACTION_POSITION es único y se procesa solo cuando se modifica la posición:
//--- 6) si se trata de la modificación de una posición case TRADE_TRANSACTION_POSITION: { is_to_reset_cnt=true; //--- PrintFormat("Modificación de posición: %s",deal_symbol); //--- if(InpIsLogging) { PrintFormat("Nuevo precio stop loss: %0."+ IntegerToString(_Digits)+"f",trans.price_sl); PrintFormat("Nuevo precio take profit: %0."+ IntegerToString(_Digits)+"f",trans.price_tp); } //--- break; }
El último módulo case se incluye durante el procesamiento del tipo TRADE_TRANSACTION_ORDER_UPDATE.
La aparición de este tipo puede estar condicionada solo por el trabajo con una orden pendiente. Además, aparece al activarse cualquier operación comercial que esté relacionada con órdenes pendientes, pero en diferentes etapas.
//--- 7) si se trata del cambio de una orden pendiente case TRADE_TRANSACTION_ORDER_UPDATE: { //--- si se trataba de la primera pasada if(gTransCnt==0) { trade_obj=TRADE_OBJ_ORDER; PrintFormat("Quitar la orden: #%d",trans.order); } //--- si se trataba de la segunda pasada if(gTransCnt==1) { //--- si se trata de la modificación de la orden if(last_action==TRADE_ACTION_MODIFY) { PrintFormat("Orden pendiente modificada: #%d",trans.order); //--- poner contador a cero is_to_reset_cnt=true; } //--- si se trata de la eliminación de una orden if(last_action==TRADE_ACTION_REMOVE) { PrintFormat("Orden pendiente eliminada: #%d",trans.order); } } //--- si se trataba de la tercera pasada if(gTransCnt==2) { PrintFormat("Nueva orden pendiente establecida: #%d, "+ EnumToString(trans.order_type),trans.order); //--- poner contador a cero is_to_reset_cnt=true; } //--- break; }
Bien, si este tipo aparece al activarse por primera vez OnTradeTransaction(), entonces la orden, o bien ha sido cancelada, o bien se ha activado.
Si el tipo ha aparecido en la segunda activación del procesador, entonces la orden, o bien ha sido eliminada, o bien ha sido modificada. Para saber qué ha sucedido precisamente, hay que recurrir a la variable estadística last_action, que recuerda la última acción comercial.
Y el último caso en el que puede aparecer este tipo, está relacionado con la tercera activación del procesador. Este efectúa el procedimiento de establecimiento de una orden pendiente.
Es fácil percibir que en el codigo se usa la variable booleana is_to_reset_cnt. Esta actúa como bandera para poner a cero el contador de pasadas del procesador OnTradeTransaction().
En principio, esto es todo en lo que respecta al procesamiento del evento TradeTransaction. Sí, añadiría además la pausa al principio de la llamada del procesador. Entonces se minimizará la probabilidad de que una operación u orden no haya entrado todavía en la historia.
Conclusión
En este artículo he intentado demostrar cómo se puede trabajar con diferentes operaciones comerciales y obtener información sobre lo que sucede en el terminal.
La ventaja de este enfoque consiste en que el programa puede obtener información sobre la ejecución por etapas de la operación comercial. Pienso que este enfoque se puede aplicar con toda tranquilidad para copiar las operaciones comerciales desde un terminal a otro.
Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/1111





- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso