- Evento principal de Asesores Expertos: OnTick
- Principios y conceptos básicos: orden, transacción y posición
- Tipos de operaciones de trading
- Tipos de órdenes
- Modos de ejecución de órdenes por precio y volumen
- Fechas de vencimiento de órdenes pendientes
- Cálculo del margen para una orden futura: OrderCalcMargin
- Estimación del beneficio de una operación de trading: OrderCalcProfit
- Estructura MqlTradeRequest
- Estructura MqlTradeCheckResult
- Solicitar validación: OrderCheck
- Solicitar resultado del envío: estructura MqlTradeResult
- Enviar una solicitud de trading: OrderSend y OrderSendAsync
- Operaciones de compraventa
- Modificar los niveles de Stop Loss y/o Take Profit de una posición
- Trailing stop
- Cierre de una posición: total y parcial
- Cierre de posiciones opuestas: total y parcial
- Colocar una orden pendiente
- Modificar una orden pendiente
- Borrar una orden pendiente
- Obtener una lista de órdenes activas
- Propiedades de una orden (activas e históricas)
- Funciones para leer las propiedades de órdenes activas
- Seleccionar órdenes por propiedades
- Obtener la lista de posiciones
- Propiedades de posiciones
- Funciones de lectura de propiedades de posición
- Propiedades de transacción
- Seleccionar órdenes y transacciones del historial
- Funciones para leer propiedades de órdenes del historial
- Funciones para leer propiedades de transacciones del historial
- Tipos de transacciones de trading
- Evento OnTradeTransaction
- Peticiones síncronas y asíncronas
- Evento OnTrade
- Seguimiento de los cambios en el entorno de trading
- Crear Asesores Expertos multisímbolo
- Limitaciones y ventajas de los Asesores Expertos
- Crear Asesores Expertos en el Asistente MQL
Colocar una orden pendiente
En Tipos de órdenes hemos considerado, en teoría, todas las opciones de colocación de órdenes pendientes que admite la plataforma. Desde un punto de vista práctico, las órdenes se crean utilizando las funciones OrderSend/OrderSendAsync, para las que la estructura de solicitud MqlTradeRequest se rellena previamente de acuerdo con reglas especiales. En concreto, el campo action debe contener el valor TRADE_ACTION_PENDING de la enumeración ENUM_TRADE_REQUEST_ACTIONS. Teniendo esto en cuenta, los siguientes campos son obligatorios:
- action
- symbol
- volume
- price
- type (el valor por defecto 0 corresponde a ORDER_TYPE_BUY)
- type_filling (por defecto 0 corresponde a ORDER_FILLING_FOK)
- type_time (el valor por defecto 0 corresponde a ORDER_TIME_GTC)
- expiration (por defecto 0, no se utiliza para ORDER_TIME_GTC)
Si los valores predeterminados cero son adecuados para la tarea, pueden omitirse algunos de los cuatro últimos campos.
El campo stoplimit es obligatorio sólo para las órdenes de los tipos ORDER_TYPE_BUY_STOP_LIMIT y ORDER_TYPE_SELL_STOP_LIMIT.
Los siguientes campos son opcionales:
- sl
- tp
- magic
- comment
Los valores cero en sl y tp indican la ausencia de niveles protectores.
Añadamos los métodos para comprobar valores y rellenar campos en nuestras estructuras en el archivo MqlTradeSync.mqh. El principio de formación de todos los tipos de órdenes es el mismo, así que analicemos un par de casos especiales de colocación de órdenes de compra y venta limitadas. El resto de tipos sólo se diferenciarán en el valor del tipo de campo. Los métodos públicos con un conjunto completo de campos obligatorios, así como los niveles de protección, se denominan según los tipos: buyLimit y sellLimit.
ulong buyLimit(const string name, const double lot, const double p,
|
Dado que la estructura contiene el campo symbol que se inicializa opcionalmente en el constructor, existen métodos similares sin el parámetro name: llaman a los métodos anteriores pasando symbol como primer parámetro. Así, para crear una orden con el mínimo esfuerzo, escriba lo siguiente:
MqlTradeRequestSync request; // by default uses the current chart symbol
|
La parte general del código para comprobar los valores pasados, normalizarlos, guardarlos en campos de estructura y crear una orden pendiente se ha trasladado al método de ayuda _pending. Devuelve el ticket de orden en caso de éxito, o 0 en caso de fallo.
ulong _pending(const string name, const double lot, const double p,
|
Ya sabemos cómo rellenar el campo action y cómo llamar a los métodos setSymbol y setVolumePrices desde operaciones de trading anteriores.
El operador multilínea if garantiza que la operación que se está preparando está presente entre las operaciones de símbolos permitidas especificadas en la propiedad SYMBOL_ORDER_MODE. La división de tipo entero type que divide por la mitad y desplaza el valor resultante en 1, establece el bit correcto en la máscara de tipos de orden permitidos. Esto se debe a la combinación de constantes en la enumeración ENUM_ORDER_TYPE y la propiedad SYMBOL_ORDER_MODE. Por ejemplo, ORDER_TYPE_BUY_STOP y ORDER_TYPE_SELL_STOP tienen los valores 4 y 5, que divididos por 2 dan ambos 2 (sin decimales). La operación 1 << 2 tiene un resultado 4 igual a SYMBOL_ORDER_STOP.
Una característica especial de las órdenes pendientes es el tratamiento de la fecha de vencimiento. El método setExpiration se ocupa de ello. En este método hay que asegurarse de que el modo de vencimiento especificado ENUM_ORDER_TYPE_TIME de duration se permite para el símbolo y la fecha y hora en until se rellenan correctamente.
bool setExpiration(ENUM_ORDER_TYPE_TIME duration = ORDER_TIME_GTC, datetime until = 0)
|
La máscara de bits de los modos permitidos está disponible en la propiedad SYMBOL_EXPIRATION_MODE. La combinación de bits en la máscara y las constantes ENUM_ORDER_TYPE_TIME es tal que basta con evaluar la expresión 1 << duration y superponerla a la máscara: un valor distinto de cero indica la presencia del modo.
Para los modos ORDER_TIME_SPECIFIED y ORDER_TIME_SPECIFIED_DAY, el campo expiration con el valor específico datetime no puede estar vacío. Además, la fecha y hora especificadas no pueden estar en el pasado.
Dado que el método _pending presentado anteriormente envía una solicitud al servidor utilizando OrderSend al final, nuestro programa debe asegurarse de que la orden con el ticket recibido fue realmente creada (esto es especialmente importante para las órdenes Limit que pueden ser emitidas a un sistema de trading externo). Por lo tanto, en el método completed, que se utiliza para el control de «bloqueo» del resultado, añadiremos una rama para la operación TRADE_ACTION_PENDING.
bool completed()
|
En la estructura MqlTradeResultSync, añadimos el método placed.
bool placed(const ulong msc = 1000)
|
Su tarea principal es esperar a que aparezca la orden utilizando la espera en la función orderExist: ya se ha utilizado en la primera fase de verificación de apertura de posición.
Para probar la nueva funcionalidad, vamos a implementar el Asesor Experto PendingOrderSend.mq5. Ello permite seleccionar el tipo de orden pendiente y todos sus atributos mediante variables de entrada, tras lo cual se ejecuta una solicitud de confirmación.
enum ENUM_ORDER_TYPE_PENDING
|
El Asesor Experto creará una nueva orden cada vez que se inicie o se cambien los parámetros. La eliminación de orden automática no se ofrece todavía. Hablaremos de este tipo de operación más adelante. A este respecto, no olvide borrar las órdenes manualmente.
La colocación de una orden única se realiza, como en algunos ejemplos anteriores, basándose en un temporizador (por lo tanto, primero debe asegurarse de que el mercado esté abierto).
void OnTimer()
|
La función PlaceOrder acepta todos los ajustes como parámetros, envía una solicitud y devuelve un indicador de éxito (ticket distinto de cero). Las órdenes de todos los tipos admitidos se ofrecen con distancias preestablecidas desde el precio actual que se calculan como parte del rango diario de cotizaciones.
ulong PlaceOrder(const ENUM_ORDER_TYPE type,
|
Por ejemplo, el coeficiente de -0.5 para ORDER_TYPE_BUY_LIMIT significa que la orden se colocará por debajo del precio actual en la mitad del rango diario (rebote dentro del rango), y el coeficiente de +1.0 para ORDER_TYPE_BUY_STOP significa que la orden se situará en el límite superior del rango (ruptura).
El rango diario propiamente dicho se calcula del siguiente modo:
const double range = iHigh(symbol, PERIOD_D1, 1) - iLow(symbol, PERIOD_D1, 1);
|
A continuación se indican los valores de punto y volumen que serán necesarios.
const double volume = lot == 0 ? SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN) : lot;
|
El nivel de precios para colocar una orden se calcula en la variable price a partir de los coeficientes dados del rango total.
const double price = TU::GetCurrentPrice(type, symbol) + range * coefficients[type]; |
El campo stoplimit sólo debe rellenarse para las órdenes *_STOP_LIMIT. Sus valores se almacenan en la variable origin.
const bool stopLimit =
|
Cuando se activan estos dos tipos de órdenes se coloca una nueva orden pendiente al precio actual. De hecho, en este escenario, el precio se mueve desde el valor actual hasta el nivel price, donde se activa la orden, y por lo tanto el precio «actual anterior» se convierte en el nivel de rebote correcto indicado por una orden Limit. A continuación ilustraremos esta situación.
Los niveles de protección se determinan utilizando el objeto TU::TradeDirection. Para las órdenes Stop-Limit, calculamos a partir de origin.
TU::TradeDirection dir(type);
|
A continuación, se describe la estructura y se rellenan los campos opcionales.
MqlTradeRequestSync request(symbol);
|
Aquí puede seleccionar el modo de relleno. Por defecto, MqlTradeRequestSync selecciona automáticamente el primero de los modos permitidos, ENUM_ORDER_TYPE_FILLING.
Dependiendo del tipo de orden elegido por el usuario, llamamos a uno u otro método de trading.
ResetLastError();
|
Si el ticket se ha recibido, esperamos a que aparezca en el entorno de trading del terminal.
if(order != 0)
|
Vamos a ejecutar el Asesor Experto en el gráfico EURUSD con la configuración predeterminada y, además, seleccionamos la distancia a los niveles de protección de 1000 puntos. Veremos las siguientes entradas en el registro (suponiendo que la configuración por defecto coincide con los permisos para EURUSD de su cuenta).
Autodetected daily range: 0.01413
|
Este es el aspecto que tiene en el gráfico:

Orden ORDER_TYPE_BUY_STOP pendiente
Eliminemos la orden manualmente y cambiemos el tipo de orden a ORDER_TYPE_BUY_STOP_LIMIT. El resultado es una imagen más compleja:

Orden ORDER_TYPE_BUY_STOP_LIMIT pendiente
El precio en el que se encuentra el par superior de líneas discontinuas es el precio de activación de la orden, como resultado de lo cual se colocará una orden ORDER_TYPE_BUY_LIMIT en el nivel de precios actual, con los valores Stop Loss y Take Profit marcados con líneas rojas. El nivel Take Profit de la futura orden ORDER_TYPE_BUY_LIMIT coincide prácticamente con el nivel de activación de la orden preliminar recién creada ORDER_TYPE_BUY_STOP_LIMIT.
Como ejemplo adicional para el autoaprendizaje, se incluye con el libro un Asesor Experto AllPendingsOrderSend.mq5; el Asesor Experto establece 6 órdenes pendientes a la vez: una de cada tipo.

Órdenes pendientes de todo tipo
Como resultado de ejecutarlo con la configuración predeterminada, puede obtener entradas de registro como las siguientes:
Autodetected daily range: 0.01413
|