Capítulo 6: Gestión de Posiciones y Órdenes
La gestión de posiciones y órdenes es una parte fundamental del desarrollo de Expert Advisors (EAs) en MQL5. En este capítulo, exploraremos los diferentes tipos de órdenes disponibles, cómo enviarlas al mercado, modificarlas o cerrarlas, y cómo consultar las posiciones abiertas.
6.1. Tipos de Órdenes: Market, Pending, Stop Loss, Take Profit
En MQL5, existen varios tipos de órdenes que permiten ejecutar estrategias comerciales con flexibilidad:
- Órdenes Market: Se ejecutan inmediatamente al precio actual del mercado.
- Órdenes Pending: Son órdenes condicionales que se activan cuando el precio alcanza un nivel específico.
- Stop Loss: Es una orden automática para cerrar una posición si el precio se mueve en contra de la posición.
- Take Profit: Es una orden automática para cerrar una posición si el precio alcanza un objetivo de ganancia.
Ejemplo Práctico: Envío de una Orden Market
A continuación, mostramos cómo enviar una orden de compra al mercado:
//+------------------------------------------------------------------+
//| Ejemplo de envío de una orden Market |
//+------------------------------------------------------------------+
#property strict
void OnStart() {
string symbol = "EURUSD"; // Símbolo
double lotSize = 0.1; // Tamaño de lote
int slippage = 10; // Deslizamiento máximo permitido
double stopLoss = 0; // Nivel de stop loss (opcional)
double takeProfit = 0; // Nivel de take profit (opcional)
// Calcular precios de stop loss y take profit (ejemplo)
double ask = SymbolInfoDouble(symbol, SYMBOL_ASK);
stopLoss = ask - 50 * Point(); // Stop loss a 50 pips
takeProfit = ask + 100 * Point(); // Take profit a 100 pips
// Enviar la orden de compra
if (OrderSend(symbol, OP_BUY, lotSize, ask, slippage, stopLoss, takeProfit)) {
Print("Orden de compra enviada correctamente.");
} else {
Print("Error al enviar la orden. Código de error: ", GetLastError());
}
}
Explicación del código:
- Usamos
OrderSendpara enviar una orden de compra (OP_BUY) al mercado. - Calculamos los niveles de stop loss y take profit basados en el precio actual (
SYMBOL_ASK). - Mostramos un mensaje de éxito o error según el resultado de la operación.
6.2. Funciones Clave: OrderSend(), OrderClose(), OrderModify()
Las funciones clave para gestionar órdenes en MQL5 son OrderSend(), OrderClose() y OrderModify(). A continuación, explicamos cada una de ellas con ejemplos prácticos.
OrderSend()
Se utiliza para enviar nuevas órdenes al mercado.
Ejemplo Práctico: Envío de una Orden Pending Buy Limit
//+------------------------------------------------------------------+
//| Ejemplo de envío de una orden Pending Buy Limit |
//+------------------------------------------------------------------+
#property strict
void OnStart() {
string symbol = "EURUSD"; // Símbolo
double lotSize = 0.1; // Tamaño de lote
int slippage = 10; // Deslizamiento máximo permitido
double price = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_BID) - 50 * Point(), _Digits); // Precio de activación
double stopLoss = 0; // Nivel de stop loss (opcional)
double takeProfit = 0; // Nivel de take profit (opcional)
// Enviar la orden Buy Limit
if (OrderSend(symbol, OP_BUYLIMIT, lotSize, price, slippage, stopLoss, takeProfit)) {
Print("Orden Buy Limit enviada correctamente. Precio de activación: ", DoubleToString(price, _Digits));
} else {
Print("Error al enviar la orden Buy Limit. Código de error: ", GetLastError());
}
}
OrderClose()
Se utiliza para cerrar posiciones abiertas.
Ejemplo Práctico: Cierre de una Posición Larga
//+------------------------------------------------------------------+
//| Ejemplo de cierre de una posición larga |
//+------------------------------------------------------------------+
#property strict
void OnStart() {
// Verificar si hay posiciones abiertas
if (PositionsTotal() > 0) {
for (int i = 0; i < PositionsTotal(); i++) {
uint ticket = PositionGetTicket(i); // Obtener el ticket de la posición
string symbol = PositionGetString(POSITION_SYMBOL); // Obtener el símbolo
int type = PositionGetInteger(POSITION_TYPE); // Obtener el tipo de posición
// Cerrar solo posiciones largas
if (type == POSITION_TYPE_BUY) {
double volume = PositionGetDouble(POSITION_VOLUME); // Obtener el volumen
double price = SymbolInfoDouble(symbol, SYMBOL_BID); // Precio de venta
if (OrderClose(ticket, volume, price, 10)) {
Print("Posición larga cerrada correctamente.");
} else {
Print("Error al cerrar la posición larga. Código de error: ", GetLastError());
}
}
}
} else {
Print("No hay posiciones abiertas para cerrar.");
}
}
OrderModify()
Se utiliza para modificar órdenes pendientes o ajustar niveles de stop loss y take profit en posiciones abiertas.
Ejemplo Práctico: Modificación de un Stop Loss
//+------------------------------------------------------------------+
//| Ejemplo de modificación de un stop loss |
//+------------------------------------------------------------------+
#property strict
void OnStart() {
// Verificar si hay posiciones abiertas
if (PositionsTotal() > 0) {
for (int i = 0; i < PositionsTotal(); i++) {
uint ticket = PositionGetTicket(i); // Obtener el ticket de la posición
string symbol = PositionGetString(POSITION_SYMBOL); // Obtener el símbolo
double currentSL = PositionGetDouble(POSITION_SL); // Obtener el stop loss actual
// Modificar el stop loss si no está configurado
if (currentSL == 0) {
double newSL = SymbolInfoDouble(symbol, SYMBOL_BID) - 30 * Point(); // Nuevo stop loss
if (OrderModify(ticket, 0, newSL, 0, 0)) {
Print("Stop loss modificado correctamente.");
} else {
Print("Error al modificar el stop loss. Código de error: ", GetLastError());
}
}
}
} else {
Print("No hay posiciones abiertas para modificar.");
}
}
6.3. Consulta de Posiciones Abiertas (PositionsTotal(), PositionGetTicket())
Para gestionar posiciones abiertas, es necesario saber cuántas posiciones están activas y obtener información sobre ellas.
Ejemplo Práctico: Listado de Posiciones Abiertas
//+------------------------------------------------------------------+
//| Ejemplo de listado de posiciones abiertas |
//+------------------------------------------------------------------+
#property strict
void OnStart() {
// Verificar si hay posiciones abiertas
if (PositionsTotal() > 0) {
Print("Posiciones abiertas:");
for (int i = 0; i < PositionsTotal(); i++) {
uint ticket = PositionGetTicket(i); // Obtener el ticket de la posición
string symbol = PositionGetString(POSITION_SYMBOL); // Obtener el símbolo
int type = PositionGetInteger(POSITION_TYPE); // Obtener el tipo de posición
double volume = PositionGetDouble(POSITION_VOLUME); // Obtener el volumen
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); // Obtener el precio de apertura
// Mostrar detalles de la posición
PrintFormat("Posición %d - Ticket: %d, Símbolo: %s, Tipo: %s, Volumen: %.2f, Precio de Apertura: %.5f",
i, ticket, symbol, type == POSITION_TYPE_BUY ? "Compra" : "Venta", volume, openPrice);
}
} else {
Print("No hay posiciones abiertas.");
}
}
Interactividad: Ejercicios Prácticos
Ejercicio 1: Escribe un script que envíe una orden Sell Limit para el símbolo GBPUSD con un stop loss a 50 pips y un take profit a 100 pips.
Ver solución:Ocultar solución//+------------------------------------------------------------------+
//| Script para enviar una orden Sell Limit |
//| |
//| Propósito: Enviar una orden Sell Limit para GBPUSD con niveles |
//| de stop loss y take profit definidos. |
//+------------------------------------------------------------------+
#property strict
void OnStart() {
string symbol = "GBPUSD"; // Símbolo
double lotSize = 0.1; // Tamaño de lote
int slippage = 10; // Deslizamiento máximo permitido
// Obtener el precio actual de venta (Bid)
double bidPrice = SymbolInfoDouble(symbol, SYMBOL_BID);
// Calcular el precio de activación para la orden Sell Limit
double activationPrice = NormalizeDouble(bidPrice + 20 * Point(), _Digits); // Activación a 20 pips por encima del precio actual
// Calcular los niveles de stop loss y take profit
double stopLoss = bidPrice + 50 * Point(); // Stop loss a 50 pips por encima del precio actual
double takeProfit = bidPrice - 100 * Point(); // Take profit a 100 pips por debajo del precio actual
// Enviar la orden Sell Limit
if (OrderSend(symbol, OP_SELLLIMIT, lotSize, activationPrice, slippage, stopLoss, takeProfit)) {
Print("Orden Sell Limit enviada correctamente.");
Print("Detalles de la orden:");
Print("Símbolo: ", symbol);
Print("Tamaño de lote: ", lotSize);
Print("Precio de activación: ", DoubleToString(activationPrice, _Digits));
Print("Stop Loss: ", DoubleToString(stopLoss, _Digits));
Print("Take Profit: ", DoubleToString(takeProfit, _Digits));
} else {
Print("Error al enviar la orden Sell Limit. Código de error: ", GetLastError());
}
}
Explicación del Código
- Definición de Parámetros:
- Especificamos el símbolo (
GBPUSD), el tamaño de lote (0.1), y el deslizamiento máximo permitido (10).
- Especificamos el símbolo (
- Obtención del Precio Actual:
- Usamos
SymbolInfoDouble(symbol, SYMBOL_BID)para obtener el precio actual de venta (Bid) del símbolo.
- Usamos
- Cálculo del Precio de Activación:
- Calculamos el precio de activación de la orden Sell Limit sumando 20 pips al precio actual (
Bid). Esto significa que la orden se activará cuando el precio alcance este nivel.
- Calculamos el precio de activación de la orden Sell Limit sumando 20 pips al precio actual (
- Cálculo de Stop Loss y Take Profit:
- Establecemos el stop loss a 50 pips por encima del precio actual.
- Establecemos el take profit a 100 pips por debajo del precio actual.
- Envío de la Orden Sell Limit:
- Usamos
OrderSendpara enviar la orden con los parámetros calculados. - Si la orden se envía correctamente, mostramos un mensaje con los detalles de la orden en la ventana de resultados.
- Si ocurre un error, mostramos el código de error correspondiente usando
GetLastError().
- Usamos
Resultado Esperado
Cuando ejecutes este script, verás un mensaje similar al siguiente en la ventana de resultados si la orden se envía correctamente:
Orden Sell Limit enviada correctamente.
Detalles de la orden:
Símbolo: GBPUSD
Tamaño de lote: 0.1
Precio de activación: 1.23678
Stop Loss: 1.24178
Take Profit: 1.22678
Si ocurre un error, verás un mensaje como este:
Error al enviar la orden Sell Limit. Código de error: 129
Caso Práctico
Este tipo de script puede ser útil para traders que desean automatizar estrategias basadas en órdenes pendientes. Por ejemplo:
- Colocar órdenes Sell Limit o Buy Limit para aprovechar movimientos esperados en el mercado.
- Configurar stop loss y take profit automáticamente para gestionar riesgos y maximizar ganancias.
¡Espero que este ejemplo te sea útil para entender cómo trabajar con órdenes pendientes en MQL5!
Ejercicio 2: Modifica el ejemplo de OrderClose() para cerrar todas las posiciones cortas en lugar de las largas.
//+------------------------------------------------------------------+
//| Script para cerrar todas las posiciones cortas |
//| |
//| Propósito: Recorrer todas las posiciones abiertas y cerrar solo |
//| las posiciones cortas (venta). |
//+------------------------------------------------------------------+
#property strict
void OnStart() {
// Verificar si hay posiciones abiertas
if (PositionsTotal() > 0) {
Print("Procesando posiciones abiertas...");
for (int i = 0; i < PositionsTotal(); i++) {
uint ticket = PositionGetTicket(i); // Obtener el ticket de la posición
string symbol = PositionGetString(POSITION_SYMBOL); // Obtener el símbolo
int type = PositionGetInteger(POSITION_TYPE); // Obtener el tipo de posición (compra o venta)
double volume = PositionGetDouble(POSITION_VOLUME); // Obtener el volumen de la posición
// Solo procesar posiciones cortas (tipo POSITION_TYPE_SELL)
if (type == POSITION_TYPE_SELL) {
double closePrice = SymbolInfoDouble(symbol, SYMBOL_ASK); // Precio de cierre (Ask)
// Intentar cerrar la posición corta
if (OrderClose(ticket, volume, closePrice, 10)) {
Print("Posición corta cerrada correctamente. Ticket: ", ticket, ", Símbolo: ", symbol);
} else {
Print("Error al cerrar la posición corta. Ticket: ", ticket, ", Código de error: ", GetLastError());
}
}
}
} else {
Print("No hay posiciones abiertas para cerrar.");
}
}
Explicación del Código
- Verificación de Posiciones Abiertas:
- Usamos
PositionsTotal()para verificar si hay posiciones abiertas en el terminal. - Si no hay posiciones abiertas, mostramos un mensaje indicando que no hay nada que cerrar.
- Usamos
- Recorrido de Posiciones Abiertas:
- Utilizamos un bucle
forpara recorrer todas las posiciones abiertas. - Para cada posición, obtenemos su ticket (
PositionGetTicket), símbolo (PositionGetString), tipo (PositionGetInteger) y volumen (PositionGetDouble).
- Utilizamos un bucle
- Filtrado de Posiciones Cortas:
- Comprobamos si el tipo de posición es
POSITION_TYPE_SELL, lo que indica una posición corta (venta). - Si es una posición corta, procedemos a cerrarla.
- Comprobamos si el tipo de posición es
- Cierre de la Posición:
- Usamos
OrderClosepara cerrar la posición corta. Le pasamos el ticket de la posición, el volumen y el precio de cierre (SYMBOL_ASKpara posiciones cortas). - Si la operación de cierre es exitosa, mostramos un mensaje de confirmación.
- Si ocurre un error, mostramos el código de error correspondiente usando
GetLastError().
- Usamos
Resultado Esperado
Cuando ejecutes este script, verás mensajes similares a los siguientes en la ventana de resultados:
- Si hay posiciones cortas:
Procesando posiciones abiertas...
Posición corta cerrada correctamente. Ticket: 123456, Símbolo: EURUSD
Posición corta cerrada correctamente. Ticket: 789012, Símbolo: GBPJPY
- Si no hay posiciones abiertas:
No hay posiciones abiertas para cerrar.
- Si ocurre un error al cerrar una posición:
Error al cerrar la posición corta. Ticket: 123456, Código de error: 129
Caso Práctico
Este tipo de script puede ser útil para traders que desean automatizar la gestión de riesgos o implementar estrategias basadas en condiciones específicas. Por ejemplo:
- Cerrar todas las posiciones cortas antes de un evento importante en el mercado (como un anuncio económico).
- Automatizar el cierre de posiciones cortas cuando se alcanza un cierto nivel de beneficio o pérdida.
¡Espero que este ejemplo te sea útil para entender cómo filtrar y gestionar posiciones específicas en MQL5!
Ejercicio 3: Crea un script que verifique si hay posiciones abiertas y, en caso afirmativo, muestre el promedio ponderado del precio de apertura de todas las posiciones.
Ver solución:Ocultar solución//+------------------------------------------------------------------+
//| Script para calcular el promedio ponderado del precio de apertura|
//| |
//| Propósito: Verificar si hay posiciones abiertas y calcular el |
//| promedio ponderado del precio de apertura. |
//+------------------------------------------------------------------+
#property strict
void OnStart() {
// Verificar si hay posiciones abiertas
if (PositionsTotal() > 0) {
double totalVolume = 0.0; // Variable para almacenar el volumen total
double weightedSum = 0.0; // Variable para almacenar la suma ponderada de precios
Print("Procesando posiciones abiertas...");
for (int i = 0; i < PositionsTotal(); i++) {
uint ticket = PositionGetTicket(i); // Obtener el ticket de la posición
double volume = PositionGetDouble(POSITION_VOLUME); // Obtener el volumen de la posición
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); // Obtener el precio de apertura
// Agregar al cálculo del promedio ponderado
weightedSum += volume * openPrice; // Suma ponderada: volumen * precio de apertura
totalVolume += volume; // Acumular el volumen total
}
// Calcular el promedio ponderado
if (totalVolume > 0) {
double weightedAverage = weightedSum / totalVolume;
Print("Promedio ponderado del precio de apertura: ", DoubleToString(weightedAverage, _Digits));
} else {
Print("No se pudo calcular el promedio ponderado debido a un volumen total de 0.");
}
} else {
Print("No hay posiciones abiertas.");
}
}
Explicación del Código
- Verificación de Posiciones Abiertas:
- Usamos
PositionsTotal()para verificar si hay posiciones abiertas en el terminal. - Si no hay posiciones abiertas, mostramos un mensaje indicando que no hay nada que procesar.
- Usamos
- Inicialización de Variables:
- Creamos dos variables:
totalVolume: Para almacenar el volumen total de todas las posiciones.weightedSum: Para almacenar la suma ponderada de los precios de apertura multiplicados por sus volúmenes correspondientes.
- Creamos dos variables:
- Recorrido de Posiciones Abiertas:
- Utilizamos un bucle
forpara recorrer todas las posiciones abiertas. - Para cada posición, obtenemos su volumen (
POSITION_VOLUME) y precio de apertura (POSITION_PRICE_OPEN). - Calculamos la contribución de cada posición al promedio ponderado multiplicando su volumen por su precio de apertura y lo acumulamos en
weightedSum. - También acumulamos el volumen total en
totalVolume.
- Utilizamos un bucle
- Cálculo del Promedio Ponderado:
- Después de procesar todas las posiciones, calculamos el promedio ponderado dividiendo
weightedSumentretotalVolume. - Mostramos el resultado en la ventana de resultados con una precisión adecuada usando
_Digits.
- Después de procesar todas las posiciones, calculamos el promedio ponderado dividiendo
- Gestión de Errores:
- Si
totalVolumees igual a 0 (lo cual no debería ocurrir normalmente), mostramos un mensaje indicando que no se pudo calcular el promedio ponderado.
- Si
Resultado Esperado
Cuando ejecutes este script, verás mensajes similares a los siguientes en la ventana de resultados:
- Si hay posiciones abiertas:
Procesando posiciones abiertas...
Promedio ponderado del precio de apertura: 1.23456
- Si no hay posiciones abiertas:
No hay posiciones abiertas.
Caso Práctico
Este tipo de script puede ser útil para traders que desean monitorear el rendimiento general de sus posiciones abiertas. El promedio ponderado del precio de apertura es una métrica importante porque refleja el costo medio ajustado según el tamaño de cada posición. Algunas aplicaciones prácticas incluyen:
- Evaluar si las posiciones actuales están rentables en conjunto.
- Tomar decisiones informadas sobre cuándo cerrar posiciones o ajustar niveles de stop loss y take profit.
- Implementar estrategias de promediación (averaging) basadas en el costo medio actual.
¡Espero que este ejemplo te sea útil para entender cómo trabajar con posiciones abiertas y realizar cálculos avanzados en MQL5!
Conclusión: En este capítulo, hemos explorado cómo gestionar posiciones y órdenes en MQL5, incluyendo los diferentes tipos de órdenes, las funciones clave para enviar, cerrar y modificar órdenes, y cómo consultar posiciones abiertas. Estos conceptos son fundamentales para desarrollar estrategias de trading automatizadas efectivas.
En el próximo capítulo, profundizaremos en la creación de indicadores personalizados, lo que nos permitirá implementar análisis técnicos avanzados.
¡Sigue practicando y perfeccionando tus habilidades en MQL5!
