Este artículo escrito por The Market Bull para el blog de Darwinex parte de la base que vimos en el anterior artículo titulado Conectando Python y R con MetaTrader 4. En dicho artículo se proponía una solución para crear estrategias de trading usando lenguajes de programación soportados por ZeroMQ desde entornos externos a MetaTrader, haciendo así que esta última fuera un mero intermediario que envía las órdenes al mercado.

Aprovechando convenientemente los patrones de comunicación Request (REQ) / Reply (REP) y PUSH/PULL, disponibles en ZeroMQ, os mostrábamos cómo planificar y desarrollar una sencilla, aunque potente arquitectura distribuida de trading que abría la puerta al desarrollo de estrategias más sofisticadas que no serían posibles dentro de los confines de MetaTrader.

En este artículo vamos a describir como ejecutar nuevas órdenes y gestionar las posiciones abiertas vía ZeroMQ, usando cualquier lenguaje soportado como Python o R. Es decir, las órdenes serán lanzadas al mercado por MetaTrader 4 pero todas las decisiones que generan dichas órdenes serán tomadas desde fuera de esa plataforma.

Adoptando una terminología más informática, diríamos que las estrategias de trading se convierten en Cliente y MetaTrader actúa como Servidor.

Asimismo, desarrollaremos una topología sencilla de mensajes para realizar las funciones de ejecución y reporting, de tal forma que la misma topología sea comprendida tanto por los Clientes (estrategias de trading) como por el Servidor (MetaTrader).

En particular, nos interesa:

  1. Topología de Mensaje.
  2. Abrir, Modificar y Cerrar Operaciones.
  3. Obtener Información de Mercado y de la Cuenta.
  4. Obtener Informes de las Operaciones Realizadas.

Vamos a ver los dos primeros apartados, dejando la tercera y cuarta sección para el siguiente artículo.

1. Topología de Mensaje
Antes de nada, primero debemos definir algunas reglas discretas de mensajería que entiendan tanto nuestras estrategias de trading como MetaTrader.

En el código en MQL que os proporcionamos en el artículo anterior, estas reglas debemos implementarlas en la función InterpretZmqMessage cuya definición es:

void InterpretZmqMessage(Socket &pSocket, string& compArray[])

Estas reglas relacionarán básicamente mensajes con acciones. Por ejemplo:

1.     “TRADE” -> Abrir una orden a Mercado en EUR/USD de 0.01 lotes, con Stop Loss x y Take Profit y.
2.    “RATES” -> Consulta cuáles son los valores actuales del Bid y el Ask para EUR/USD.
3.    “ACCOUNT” -> Obtiene cuál es el valor neto actual de la cuenta
4.    “HISTORY” -> Nos dice cuántas órdenes hay abiertas ahora mismo.

Etc.

Para el ejemplo que vamos a ver aquí, definimos los siguientes formatos de mensaje:

Abrir, Modificar y Cerrar Órdenes:
TRADE|ACTION|TYPE|SYMBOL|PRICE|SL|TP|COMMENT|TICKET

Información de Mercado:
RATES|SYMBOL
DATA|SYMBOL|TIMEFRAME|START_DATETIME|END_DATETIME

Información de la Cuenta:
ACCOUNT|ACTION

Informe de Operaciones:
HISTORY|ACTION
 
Con la topología de mensaje anterior, ahora podemos construir mensajes que contengan instrucciones operativas e informativas.

Así, el servidor ZeroMQ activado en MetaTrader recibirá y ejecutará las instrucciones vía el socket REQ/REP tal y como lo definimos en el artículo anterior, y enviará la información de vuelta a los clientes que lo soliciten usando el socket REQ/REP o PUSH/PULL dependiendo de la instrucción recibida.

Por ejemplo, podemos utilizar REQ/REP para mensajes críticos (por ejemplo, abrir, cerrar o modificar órdenes y conocer el resultado de dichas acciones), mientras que las instrucciones que no sean críticas tales como conocer el saldo de la cuenta pueden ser realizadas usando el socket PUSH/PULL.

La elección del patrón de comunicación (REQ/REP o PUSH/PULL) dependerá por completo de lo crítica que consideremos una determinada instrucción.

Generalmente merece la pena planificar esto antes de realizar el desarrollo de la estrategia, ya que el uso de diferentes flujos de control producirá un rendimiento diferente y presentará diferentes problemas.
Pasamos a ver algunos ejemplos que nos permitirán entender mejor como cada tipo de mensaje puede ser usado en la práctica.

La plantilla de Expert Advisor para MT4 usando ZeroMQ que vimos en el artículo anterior ya está preparada con los contenedores de código apropiados en la función InterpretZmqMessage() de tal forma que los lectores pueden rellenarlas con su propio código fácilmente.


2. Abriendo, Modificando y Cerrando Operaciones
Tal y como acabamos de ver, usaremos el siguiente formato para las instrucciones relacionadas con órdenes:

TRADE|ACTION|TYPE|SYMBOL|PRICE|SL|TP|COMMENT|TICKET

Veamos más en detalle esto, desglosando cada componente que puede contener este mensaje:

[0] = TRADE
[1] = ACTION (e.g. OPEN, MODIFY, CLOSE)
[2] = TYPE (e.g. OP_BUY, OP_SELL, etc. - only used when ACTION=OPEN)
         
// ORDER TYPES:
// https://docs.mql4.com/constants/tradingconstants/orderproperties
         
// OP_BUY = 0
// OP_SELL = 1
// OP_BUYLIMIT = 2
// OP_SELLLIMIT = 3
// OP_BUYSTOP = 4
// OP_SELLSTOP = 5
         
[3] = Symbol (e.g. EURUSD, etc.)
[4] = Open/Close Price (ignored if ACTION = MODIFY)
[5] = SL
[6] = TP
[7] = Trade Comment
[8] = Trade Ticket ID

 

Por ejemplo, nuestra estrategia de trading en Python o R podría enviar el siguiente mensaje al EA ZeroMQ EA:

"TRADE|OPEN|1|EURUSD|0|50|50|R-to-MetaTrader4|0"

Aquí, nuestra estrategia de trading está pidiendo que:

  1. Se ejecute una operación (OPEN),
  2. El tipo de orden (1) es OP_SELL (Vender a Mercado)
  3. El símbolo a operar es EURUSD
  4. El Precio de Apertura/Cierre es 0 (lo que indica que la orden se ejecute al precio disponible en el Mercado en ese momento).
  5. El stop loss es de 50 pips.
  6. El take profit es de 50 pips también.
  7. El comentario de la operación es "R-to-MetaTrader4"
  8. El nº de ticket es 0 (ya que los IDs de ticket no se especifican cuando ejecutamos operaciones en MetaTrader 4).

Implementando está lógica en InterpretZmqMessage() dentro del EA proporcionado, podemos llamar a la función OrderSend() de MetaTrader y enviar la orden a mercado.


Órdenes Pendientes
En el caso de órdenes pendientes (Buy Stop, Buy Limit, Sell Stop Sell Limit), el código que escribamos no debería ignorar ahora el campo de Precio de Apertura/Cierre.

Necesitamos realizar una llamada a la función OrderSend() con "price" fijado en ese valor, y “cmd” fijado al valor apropiado tal y como se recibe en el mensaje a través de ZeroMQ (esto es, OP_BUYLIMIT (si es 2) , OP_SELLLIMIT (si es 3), OP_BUYSTOP (si es 4) y OP_SELLSTOP (si es 5).

Nota: Los valores numéricos (1,2,3,4,5) han sido elegidos de forma arbitraria, por supuesto podemos elegir aquellos que nos gusten más y tengan sentido para nosotros, siempre y cuando implementemos su correspondiente lógica de la misma manera en MetaTrader y en nuestra estrategia ejecutada de forma externa vía Python o R.


Ejemplo:


"TRADE|MODIFY|1|EURUSD|0|70|90|R-to-MetaTrader4|12345678"


Modificando Órdenes
En este caso, nuestra lógica en la función InterpretZmqMessage() necesitará ignorar de nuevo el Precio de Apertura/Cierre (estamos modificando una orden ya existente) y en su lugar realizar una llamada a la función OrderModify() con sus parámetros de stop loss y take profit ajustados a los recibidos en el mensaje de ZeroMQ.

Asimismo, necesitaremos leer el campo de Ticket ID y especificarlo en el parámetro “ticket” de OrderModify(), de tal forma que MetaTrader sepa qué operación debe modificar, si miramos el ejemplo anterior dicho valor es "12345678".


Cerrando / Borrando Órdenes
El procedimiento para cerrar órdenes en MetaTrader 4 es bastante sencillo.

Todo lo que necesitamos hacer es pasar el Ticket ID recibido vía ZeroMQ a la función OrderClose(), junto con los valores para los parámetros “lots” especificando el tamaño a cerrar, el “Price” al que queremos cerrar (Bid o Ask) y el “slippage” máximo que deseamos permitir en la transacción.

Borrar órdenes pendientes es incluso más sencillo: simplemente debemos pasar el Ticket ID recibido vía ZeroMQ a la función OrderDelete(), introduciendo el valor del parámetro “ticket”.

En el siguiente artículo veremos cómo implementar la obtención de información sobre la cuenta y las operaciones vía ZeroMQ.