English Русский 中文 Deutsch 日本語 Português
preview
Estrategia de negociación de órdenes en cascada basada en cruces de EMA para MetaTrader 5

Estrategia de negociación de órdenes en cascada basada en cruces de EMA para MetaTrader 5

MetaTrader 5Trading | 25 noviembre 2024, 11:19
400 0
Kikkih25
Kikkih25

Introducción 

En este artículo, estamos demostrando la estrategia de negociación de órdenes en cascada en MetaQuotes Language 5 (MQL5) para MetaTrader 5. En este artículo se utiliza cruces de medias móviles como base para la estrategia comercial, este artículo de MQL5 automatiza las opciones comerciales en la plataforma MetaTrader 5. Este artículo incorpora funciones esenciales para la inicialización, el ajuste y la supervisión de posiciones y hace uso de la biblioteca Trade.mqh para una administración eficaz de las órdenes.

En primer lugar, se utilizan inicialmente dos medias móviles exponenciales (EMAs) con periodos predeterminados como parte de la técnica. Dependiendo de la dirección del cruce, se produce una señal de compra o de venta cuando se cruzan estas medias móviles. Las órdenes se establecen con take profit y stop loss especificados, que se ajustan dinámicamente a medida que avanza el mercado.

Además, el script tiene una rutina para identificar nuevas barras, que son esenciales para garantizar que las decisiones de trading se toman basándose en formaciones de velas completas. Además, se ofrece una función para ajustar la participación actual al alcanzar los objetivos de beneficios.

Este artículo MQL5 puede ser utilizado para poner en práctica una estrategia de negociación sistemática mediante el uso de la ejecución automatizada y los indicadores técnicos para llevar a cabo operaciones por reglas predeterminadas.

En este artículo abordamos los siguientes temas:

  1. Explicación de la estrategia de negociación de órdenes en cascada
  2. Implementación en MQL5
  3. Conclusión


Explicación de la estrategia de negociación de órdenes en cascada 

La estrategia de negociación de órdenes en cascada describe una técnica en la que los resultados o términos de órdenes anteriores se utilizan para determinar la colocación de órdenes posteriores. Para gestionar y optimizar las entradas, salidas y tamaños de posiciones en función de los movimientos del mercado y reglas predeterminadas, esta estrategia se emplea con frecuencia en el trading. Esta es una descripción detallada de cómo podría funcionar una estrategia comercial que utilice órdenes en cascada.

Componentes esenciales de la estrategia de negociación de órdenes en cascada:

  1. Colocación de órdenes consecutivas: Una estrategia de órdenes en cascada implica el inicio consecutivo de transacciones en respuesta a eventos o condiciones predeterminados. Un comerciante podría realizar un pedido inicial, por ejemplo, en respuesta a una señal de un indicador técnico específico.
  2. Orden contingente: Las órdenes futuras se colocan en función de los resultados de operaciones anteriores o del estado del mercado. Si el mercado avanza a su favor, esto puede implicar colocar más órdenes para escalar a una posición.
  3. Para controlar el riesgo y optimizar el potencial de beneficios, la estrategia en cascada suele implicar la entrada progresiva en una posición. Por otro lado, el scalping out implica reducir el tamaño de la posición cuando se alcanzan los objetivos de beneficios o cuando el mercado se mueve negativamente.
  4. Gestión del riesgo: Para minimizar las pérdidas, la gestión eficaz del riesgo es esencial en las técnicas en cascada. Esto implica establecer umbrales de stop loss para cada orden o modificarlos dinámicamente a medida que cambia la posición.

Recogida de beneficios: Cuando se cumplen determinados requisitos, se toman medidas para asegurar las ganancias. Los objetivos de beneficios se fijan para cada orden en todas las fases de la operación. Esto garantiza a los operadores beneficios, al tiempo que permite una subida adicional si las circunstancias del mercado lo exigen.

Este es el gráfico que resume la estrategia de negociación de órdenes en cascada:

Estrategia de negociación de órdenes en cascada


Implementación en MQL5

En primer lugar, la biblioteca Trade.mqh de MQL5 es una biblioteca sólida y práctica que facilita las actividades de trading. Ofrece una interfaz de alto nivel para abrir, modificar y eliminar posiciones y órdenes. Cuando incluimos Trade.mqh nos da acceso a la clase CTrade, que simplifica y encapsula muchos de los intrincados detalles de las actividades de negociación, mejorando la capacidad de lectura y mantenimiento de nuestro código.

#include <Trade/Trade.mqh>
CTrade obj_Trade;

Después de incluir Trade.mqh, podemos acceder a la clase CTrade que es instantáneamente instanciada como obj_Trade. Nos hemos dado cuenta de que muchas de las funcionalidades que tenemos para operar están encapsuladas en la clase CTrade. A continuación se enumeran algunas de las principales técnicas que ofrece la clase CTrade:

  1.  Hacer un pedido
  2.  Modificación de la orden
  3.  Finalización del pedido

A continuación, pasamos a las variables globales que son muy cruciales para el funcionamiento de la estrategia comercial y cumplen una variedad de funciones en el Asesor Experto (EA). Hablemos de cada variable global y lo que significa:

  •  Variable en números enteros

int handleMAFast;
int handleMASlow;

Los controladores, o ID, para los indicadores de promedio de movimiento rápido y lento calculados por la función OnInit se almacenan en estas variables. Para recuperar los valores actuales de estos indicadores, los controladores deben acceder a sus búferes.

  • Matrices dobles para promedios móviles

double maSlow[],maFast[];

Los valores de los promedios de movimiento rápido y lento derivados de los buffers de indicadores se guardan en estas matrices. Para el análisis y la toma de decisiones comerciales, se utilizan para almacenar los valores presentes y pasados de los indicadores.

  • Variables double de take profit y stop loss

double takeProfit = 0;
double stopLoss = 0;

Los niveles de take profit (TP) y stop loss (SL) de las operaciones se almacenan actualmente en esta variable. Se utilizan para introducir o modificar órdenes de negociación y se actualizan en función de las condiciones del mercado.

  •  Variables reservadas del estado del sistema

bool isBuySystemInitiated = false;
bool isSellSystemInitiated = false;

Estas banderas reservadas monitorean el estado inicial de los sistemas comerciales de compra y venta. Ayudan a prevenir órdenes innecesarias o duplicadas y a garantizar que las órdenes solo se coloquen cuando se cumplan ciertos criterios (como cruces de medias móviles).

  • Parámetros de entrada

input int slPts = 300;
input int tpPts = 300;
input double lot = 0.01;
input int slPts_Min = 100;
input int fastPeriods = 10;
input int slowPeriods = 20;

Estas variables son parámetros de entrada que, sin cambiar el código en sí, permiten la configuración externa del comportamiento del EA. Los traders pueden modificar estos parámetros a través de la configuración del EA de la interfaz MetaTrader. Gestionan variables como el take-profit, el stop-loss, el tamaño del lote y los periodos de movimiento rápido.

Después de explicar el significado de las variables, nos dimos cuenta de que los datos a los que se debe acceder a través de ticks y funciones se almacenan en variables globales en MQL5. Esto se debe a que sirven para almacenar datos vitales, incluidos parámetros de pedidos, estado comercial, valores indicadores y configuraciones definidas por el usuario. Se utilizan para llevar a cabo la estrategia comercial, mantener posiciones y responder a las condiciones del mercado, diferentes funciones de EA acceden y alteran estas variables.

¡Ciertamente! Analicemos la parte de inicialización del código. La función OnInit es responsable de configurar el estado inicial del asesor experto. Lo primero que sucede es crear controladores para los promedios de movimiento rápido y lento utilizando la función iMA. Comprueba si estos identificadores son válidos. Si algún identificador no es válido, la inicialización falla. A continuación, establezca las matrices maFast y maSlow para que sean matrices de series temporales utilizando ArraySetAsSeries. Por último, devuelve éxito.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){
   
   handleMAFast = iMA(_Symbol,_Period,fastPeriods,0,MODE_EMA,PRICE_CLOSE);
   if (handleMAFast == INVALID_HANDLE){
      Print("UNABLE TO LOAD FAST MA, REVERTING NOW");
      return (INIT_FAILED);
   }
   
   handleMASlow = iMA(_Symbol,_Period,slowPeriods,0,MODE_EMA,PRICE_CLOSE);
   if (handleMASlow == INVALID_HANDLE){
      Print("UNABLE TO LOAD SLOW MA, REVERTING NOW");
      return (INIT_FAILED);
   }
   
   ArraySetAsSeries(maFast,true);
   ArraySetAsSeries(maSlow,true);
   
   return(INIT_SUCCEEDED);
}

A continuación, analizamos la función de desinicialización. Dentro del sistema de asesor experto MQL5, la función se invoca cuando el asesor experto se cierra o se elimina del gráfico. Aquí es donde se realiza la limpieza de las tareas.

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }

En este caso, la función está vacía, lo que indica que no se realizan acciones particulares al desinicializar el EA. 

La función toma un parámetro entero llamado reason, que especifica la causa de la desinicialización. Esto podría ocurrir porque la terminal está cerrada, el EA fue retirado del gráfico o por otras razones.

Ahora pasamos a la función OnTick, que se activa cada vez que se recibe un nuevo tick (cambio de precio). En esta función se aplica la lógica comercial. La función OnTick en el código proporcionado lleva a cabo la estrategia comercial basada en el cruce de medias móviles.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){
   
   double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
   double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
   
   if (CopyBuffer(handleMAFast,0,1,3,maFast) < 3){
      Print("NO ENOUGH DATA FROM FAST MA FOR ANALYSIS, REVERTING NOW");
      return;
   }
   if (CopyBuffer(handleMASlow,0,1,3,maSlow) < 3){
      Print("NO ENOUGH DATA FROM SLOW MA FOR ANALYSIS, REVERTING NOW");
      return;
   }
   
   //if (IsNewBar()){Print("FAST MA DATA:");ArrayPrint(maFast,6);}
   
   if (PositionsTotal()==0){
      isBuySystemInitiated=false;isSellSystemInitiated=false;
   }
   
   if (PositionsTotal()==0 && IsNewBar()){
      if (maFast[0] > maSlow[0] && maFast[1] < maSlow[1]){
         Print("BUY SIGNAL");
         takeProfit = Ask+tpPts*_Point;
         stopLoss = Ask-slPts*_Point;
         obj_Trade.Buy(lot,_Symbol,Ask,stopLoss,0);
         isBuySystemInitiated = true;
      }
      else if (maFast[0] < maSlow[0] && maFast[1] > maSlow[1]){
         Print("SELL SIGNAL");
         takeProfit = Bid-tpPts*_Point;
         stopLoss = Bid+slPts*_Point;
         obj_Trade.Sell(lot,_Symbol,Bid,stopLoss,0);
         isSellSystemInitiated = true;
      }
   }
   
   else {
      if (isBuySystemInitiated && Ask >= takeProfit){
         takeProfit = takeProfit+tpPts*_Point;
         stopLoss = Ask-slPts_Min*_Point;
         obj_Trade.Buy(lot,_Symbol,Ask,0);
         ModifyTrades(POSITION_TYPE_BUY,stopLoss);
      }
      else if (isSellSystemInitiated && Bid <= takeProfit){
         takeProfit = takeProfit-tpPts*_Point;
         stopLoss = Bid+slPts_Min*_Point;
         obj_Trade.Sell(lot,_Symbol,Bid,0);
         ModifyTrades(POSITION_TYPE_SELL,stopLoss);
      }
   }
}

A continuación se muestra el desglose detallado de la función OnTick para una fácil comprensión:

Obtener precios de compra y venta: la función obtiene los precios de compra y venta en el momento y los redondea al número apropiado de decimales. Recuperar y normalizar los precios actuales es esencial para una estrategia de negociación de órdenes en cascada para tomar decisiones bien informadas sobre la colocación de órdenes en diferentes puntos de precio. Es necesario mantener una estrecha vigilancia sobre los precios actuales del mercado al poner en práctica la estrategia de negociación de órdenes en cascada. Esto implica obtener los precios de oferta y demanda para el símbolo que está negociando en MetaTrader. El precio de venta actual para el símbolo designado (_Symbol) se obtiene llamando a la función. El precio al que puedes comprar este activo se conoce como precio de venta. Esta llamada de función recupera el precio de oferta actual del símbolo. El precio al que puedes comprar este activo se conoce como precio de oferta.

double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);

La normalización garantiza que los precios recuperados cumplan con los requisitos de precisión de los símbolos comerciales. Para evitar problemas con las matemáticas de punto flotante también depende de esto. Esta llamada de función redondea el valor al número designado de decimales (_Digits). _Digits, que indica la cantidad de decimales que admite el símbolo, generalmente está predefinido para el símbolo.

Duplicar los buffers de promedios móviles: la función obtiene los valores más recientes para los promedios móviles tanto lentos como rápidos. La función finaliza y se imprime un mensaje de error si no hay datos suficientes. Los promedios móviles se utilizan en una estrategia de negociación de órdenes en cascada para detectar operaciones y determinar los momentos base para colocar órdenes. Para que la estrategia sea confiable es imprescindible que antes de comenzar el estudio se cuente con suficientes datos de las medias móviles.

if (CopyBuffer(handleMAFast,0,1,3,maFast) < 3){
      Print("NO ENOUGH DATA FROM FAST MA FOR ANALYSIS, REVERTING NOW");
      return;
   }
   if (CopyBuffer(handleMASlow,0,1,3,maSlow) < 3){
      Print("NO ENOUGH DATA FROM SLOW MA FOR ANALYSIS, REVERTING NOW");
      return;
   }

Esta función transfiere información a la matriz maFast desde el búfer del indicador de promedio de movimiento rápido. Los indicadores de promedio móvil rápido manejan el número de búfer, que generalmente es 0 para la línea principal de un indicador, el punto de inicio desde el cual se deben copiar los datos, la cantidad de elementos que se duplicarán y la matriz en la que se guardará la copia de datos. La función devuelve el número de elementos copiados correctamente. Mientras verificamos la viabilidad de los datos, determinamos si al maFast se le han copiado menos de tres elementos. Menos de tres componentes transferidos indican que no hay suficientes datos del promedio móvil rápido para respaldar un análisis sólido. La función finaliza la ejecución imprimiendo un mensaje y regresando anticipadamente. El promedio de movimiento lento con identificador MASlow y maSlow sigue el mismo razonamiento.

A continuación se muestra un gráfico de los promedios móviles representados frente a los datos de precios. El gráfico incluye la serie de precios, el promedio de movimiento rápido (EMA de 10 días) y los promedios de movimiento lento (EMA de 20 días).

CRUCE DE MEDIAS MÓVILES

Antes de tomar cualquier decisión comercial, la estrategia se asegura de que haya una cantidad mínima de datos históricos de los promedios móviles. Esto ayuda a tomar decisiones más confiables y fundamentadas. La estrategia evita la información inadecuada, que podría generar señales falsas y posibles pérdidas de operaciones, al verificar que haya suficientes datos. Este fragmento sirve como paso de validación antes de operar. Si la condición no se cumple, la estrategia se revertirá y no ejecutará ninguna operación ni análisis para ese tick.

Los promedios móviles se utilizan para determinar la dirección y la fuerza de una tendencia en una estrategia de negociación de órdenes en cascada. Si el promedio de movimiento rápido cruza por encima o por debajo del promedio de movimiento lento, por ejemplo, es posible que usted coloque órdenes en diferentes niveles.

Comprobar posiciones abiertas: Las banderas de inicio del sistema de compra y venta se restablecen si no hay posiciones abiertas. Para evitar la superposición de transacciones y gestionar de manera eficiente el estado del sistema comercial, es imperativo, al utilizar una estrategia de comercio de órdenes en cascada, verificar si hay posiciones abiertas. Uno de los mecanismos que hemos realizado en esta función es restablecer banderas específicas si no hay espacios abiertos.

//if (IsNewBar()){Print("FAST MA DATA:");ArrayPrint(maFast,6);}
   
   if (PositionsTotal()==0){
      isBuySystemInitiated=false;isSellSystemInitiated=false;
   }

Esta función devuelve el número total de posiciones abiertas para la cuenta comercial actual. Es útil averiguar si hay operaciones activas. Cuando asumimos que PositionsTotal() == 0 determina si hay 0 posiciones abiertas en total, indica que no hay operaciones abiertas en este momento. Los indicadores isBuySytemInitiated y isSellSystemInitiated se establecen en falso cuando no hay posiciones abiertas. Restablece la bandera que indica si el sistema de compra se ha iniciado o no (_isBuySystemInitiated = false;). Restablece la bandera que indica si se ha iniciado o no el sistema de venta (_isSellSystemInitiated = false;).

Este enfoque garantiza que las nuevas operaciones solo se inicien cuando no haya posiciones abiertas, verificando periódicamente si hay posiciones abiertas y restableciendo los indicadores de inicio. De esta manera se evitan operaciones superpuestas que pueden dar lugar a una sobreexposición al riesgo o a acciones comerciales contradictorias. Gestionamos el sistema comercial iniciando banderas, isBuySystemInitiated y isSellSystemInitiated. Estas banderas garantizan que, hasta que se cierren las posiciones actuales, el sistema no inicie órdenes de compra o venta idénticas dentro de una tendencia particular más de una vez. También obtenemos ayuda para mantener intacto el flujo lógico de la estrategia en esta comprobación. El enfoque puede reaccionar con precisión a las condiciones y tendencias del mercado asegurándose de que se coloquen nuevos pedidos con fuerza cuando sea apropiado, es decir, cuando no haya posiciones abiertas. Logramos una mejor gestión de riesgos al evitar que numerosas posiciones estén abiertas al mismo tiempo. De esta manera, la estrategia puede limitar la exposición al mercado y evitar un posible apalancamiento excesivo.

 Detección de nueva barra: basándose en los cruces de medias móviles, busca señales de compra o venta si se ha formado una nueva barra (vela) y no hay posiciones abiertas. Para evitar ejecuciones múltiples de la estrategia comercial, es importante detectar la aparición de una nueva barra. El uso de los datos de la barra terminada como base para las decisiones comerciales, en lugar de cambios de precios intrabarra posiblemente inestables, mejora la precisión de las operaciones.

if (PositionsTotal()==0 && IsNewBar()){
      if (maFast[0] > maSlow[0] && maFast[1] < maSlow[1]){
         Print("BUY SIGNAL");
         takeProfit = Ask+tpPts*_Point;
         stopLoss = Ask-slPts*_Point;
         obj_Trade.Buy(lot,_Symbol,Ask,stopLoss,0);
         isBuySystemInitiated = true;
      }
      else if (maFast[0] < maSlow[0] && maFast[1] > maSlow[1]){
         Print("SELL SIGNAL");
         takeProfit = Bid-tpPts*_Point;
         stopLoss = Bid+slPts*_Point;
         obj_Trade.Sell(lot,_Symbol,Bid,stopLoss,0);
         isSellSystemInitiated = true;
      }
   }

Cuando PositionsTotal == 0, esta condición garantiza que la función del bloque if solo se ejecute si no hay posiciones abiertas. Al hacer esto, se evita que las operaciones se superpongan y que las nuevas operaciones solo se abran después del cierre de las más antiguas. La función IsNewBar() determina si se ha formado una nueva barra desde la última ejecución. Básicamente, cuando la hora de apertura se registró previamente, este método debería devolver verdadero.

En la señal de compra, aquí determinamos si la barra reciente ha visto un cruce alcista o si el promedio de movimiento rápido (MA) cruzó el promedio de movimiento lento. Si este es el caso, calcula los niveles de take profit y stop loss y publica un mensaje de "BUY SIGNAL". Después de eso, establece el indicador isBuySystemInitiated en verdadero y envía una orden de compra usando obj_Trade.Buy(). A continuación se muestra una señal de compra de cruce de EMA de la estrategia de negociación de órdenes en cascada:

Señal de compra


En la señal de venta, aquí determinamos si la barra reciente representa un cruce bajista, lo que significa que la media de movimiento rápido (MA) ha cruzado por debajo de la media de movimiento lento. Si este es el caso, calcula los niveles de take profit y stop loss y emite un mensaje de "SELL SIGNAL". Después de eso, utiliza obj_Trade para enviar una orden de venta. Sell() establece el indicador isSellSystemInitiated como verdadero. A continuación se muestra una señal de venta cruzada de EMA de la estrategia de negociación de órdenes en cascada:

Señal de venta

La estrategia garantiza que la lógica comercial solo se ejecute una vez por barra identificando cuándo se detecta una nueva barra. Al hacer esto, se evita el problema de que se coloquen varias órdenes dentro de la misma barra, lo que puede resultar en operaciones excesivas y tarifas de transacción más altas. Cuando utilizamos datos de barras terminadas para fundamentar decisiones comerciales, garantizamos que las elecciones se basan en información confiable. Los cambios de precios dentro de las barras pueden ser ruidosos y producir indicaciones erróneas. El estado del sistema de trading se gestiona de forma eficaz combinando la comprobación de que no hay posiciones abiertas con la detección de una nueva barra, lo que garantiza que se realicen nuevas operaciones solo cuando sea necesario, preservando la progresión lógica de la estrategia. 

Ejecutar órdenes de compra o venta: Se coloca una orden de compra si el promedio de movimiento rápido cruza el promedio de movimiento lento. Inicia una orden de venta si la MA rápida cruza por debajo de la MA lenta. También modifica los indicadores de iniciación y establece las configuraciones de take profit (TP) y stop loss (SL). Esta "cascada" de órdenes ayuda a establecer gradualmente una posición a medida que el precio se mueve a favor de la primera operación.

else {
      if (isBuySystemInitiated && Ask >= takeProfit){
         takeProfit = takeProfit+tpPts*_Point;
         stopLoss = Ask-slPts_Min*_Point;
         obj_Trade.Buy(lot,_Symbol,Ask,0);
         ModifyTrades(POSITION_TYPE_BUY,stopLoss);
      }

En las cascadas de órdenes de compra, la estrategia determina si se ha alcanzado el nivel de toma de ganancias y si el precio de venta es actualmente mayor o igual a este. Esta circunstancia significa que se ha activado una orden de compra adicional ya que el precio se ha movido a favor de la posición de compra actual. El nivel de toma de ganancias se eleva en una cantidad predeterminada de puntos, estableciendo un nuevo global para el incremento posterior en la cascada. La modificación del Stop Loss garantiza que el riesgo esté controlado para la nueva orden de compra y que el nivel de Stop Loss se cambie a un nuevo nivel por debajo del precio de venta. La orden de compra adicional coloca una segunda orden de compra con el tamaño de lote indicado, vigente al precio de venta actual. La modificación de las operaciones actuales gestiona el riesgo de la posición general, el stop loss para las posiciones de compra actuales se cambia al nuevo nivel de stop loss.

La estrategia de orden de venta secuencial determina si el precio de oferta actual es menor o igual al nivel de toma de ganancias y si el sistema de venta ha comenzado. Esta situación significa que se ha activado una orden de venta adicional ya que el precio se ha movido a favor de la posición de venta actual. El nivel de toma de ganancias se reduce en una cantidad predeterminada de puntos, estableciendo un nuevo objetivo para el incremento posterior en la cascada. La actualización del stop loss garantiza que el riesgo esté controlado para la nueva orden de venta; el nivel de stop loss se cambia a un nuevo nivel por encima del precio de oferta existente. Se ejecuta una orden de venta adicional con el tamaño de lote especificado al precio de oferta actual. Al modificar los controles de operaciones actuales se controla el riesgo en todos los ámbitos; el stop loss para las posiciones de venta actuales se cambia al nuevo nivel de stop loss.

Ajustar las posiciones actuales: si hay posiciones abiertas y el precio alcanza el umbral de toma de ganancias, se colocan más órdenes y los montos de stop loss se actualizan adecuadamente. Esto ayuda a maximizar las ganancias incrementales y a gestionar los riesgos.

else if (isSellSystemInitiated && Bid <= takeProfit){
         takeProfit = takeProfit-tpPts*_Point;
         stopLoss = Bid+slPts_Min*_Point;
         obj_Trade.Sell(lot,_Symbol,Bid,0);
         ModifyTrades(POSITION_TYPE_SELL,stopLoss);
      }
   }
}

Un indicador booleano llamado isBuySystemInitiated indica si el sistema de compra se ha iniciado o no. Un indicador booleano llamado isSellSystemInitiated indica si el sistema de venta se ha iniciado o no. La tasa actual de venta, el precio de oferta actual, la cantidad de toma de ganancias, la cantidad de puntos necesarios para modificar el umbral de toma de ganancias, el nivel del stop loss, el punto mínimo de ajuste del stop loss, el tamaño del lote de la operación, la capacidad de colocar una orden de compra, la capacidad de enviar una orden de venta y la función que le permite cambiar el stop loss de una posición existente.

Ahora verificamos si el sistema UT se ha iniciado y si el precio solicitado en este momento ha alcanzado o superado el umbral de toma de ganancias. Aumentar el nivel de Take Profit en una cantidad predeterminada de puntos. Esto permite que la estrategia capture posibles ganancias adicionales al establecer un nuevo objetivo de toma de ganancias más alto que el existente. Establecer el stop loss en un precio nuevo, más bajo que el precio solicitado. Bloquear parte de las ganancias previas ayuda a gestionar el riesgo. Completar órdenes de compra adicionales al precio de venta ejecutó la segunda orden de compra con el tamaño de lote designado al precio de venta. A medida que el precio se mueve a favor de las operaciones iniciales, esto aumenta gradualmente la posición. Actualiza los stop loss de todas las posiciones de compra actuales para reflejar el nuevo monto de stop loss. Esto ayuda a controlar el riesgo total asociado con la posición de compra.

A continuación, verificamos si se ha iniciado el mecanismo de venta y si el precio de oferta ha subido o bajado por debajo del umbral de toma de ganancias. Reducir el nivel de Take Profit en una cantidad fija de puntos. Como resultado, el nuevo objetivo de toma de ganancias es menor que el nivel existente. Después de actualizar el stop loss, esto moverá el stop loss a un nuevo nivel por encima del precio de oferta. Bloquear parte de las ganancias previas ayuda a gestionar el riesgo. Complete una orden de venta adicional con un tamaño de lote designado al precio de oferta actual. A medida que el precio se mueve a favor de la operación inicial, esto aumenta gradualmente la posición. Actualiza los stop loss de todas las posiciones de venta actuales para reflejar el nuevo monto de stop loss. Esto ayuda a controlar el riesgo total asociado con la posición de venta.

A medida que el mercado cambia a favor de la primera transacción, la estrategia aumenta gradualmente la posición comercial. Como resultado, el comerciante puede aumentar su posición sin asumir un riesgo excesivo al principio y beneficiarse de tendencias significativas. La estrategia gestiona eficazmente el riesgo variando los niveles de stop loss tanto para nuevas órdenes como para posiciones abiertas. Si el mercado gira hacia el sur, esto ayuda a preservar las ganancias y reducir las pérdidas. Cada vez que el mercado avanza en la dirección de la preferencia de la estrategia en cascada, se establecen progresivamente nuevos niveles de toma de ganancias para maximizar las ganancias. Esto permite un crecimiento futuro y al mismo tiempo garantiza una fijación progresiva de las ganancias.

Veamos ahora las dos funciones de utilidad en nuestro código MQL5. IsNewBar y ModifyTrades. Estas rutinas proporcionan operaciones auxiliares necesarias para respaldar la lógica comercial central que se proporciona en la función OnTick.

Comenzamos con la función IsNewBar. Esta función examina el gráfico para ver si se ha formado una nueva barra o vela. Esto es necesario para garantizar que acciones específicas, como la apertura de nuevas operaciones, se realicen solo una vez por barra.

//+------------------------------------------------------------------+

bool IsNewBar(){
   static int prevBars = 0;
   int currBars = iBars(_Symbol,_Period);
   if (prevBars==currBars) return (false);
   prevBars = currBars;
   return (true);
}

El número de barras del tick anterior se almacena en la variable estática prevBars. El valor de la variable se conserva entre llamadas de función gracias a la palabra clave static. Recuento de barras: Desde currBars se recupera el conteo de barras actual del gráfico. Comparación: La función devuelve falso si no se ha generado una nueva barra y prevBars y currBars son iguales. Había surgido algo nuevo si no estaban de acuerdo. La función devuelve verdadero después de actualizar prevBars a currBars. 

Pasemos ahora a la función ModifiyTrades. Según el tipo de posición especificado, la función ModifyTrades ajusta los niveles de stop loss (SL) de las posiciones activas.

void ModifyTrades(ENUM_POSITION_TYPE posType, double sl){
   for (int i=0; i<=PositionsTotal(); i++){
      ulong ticket = PositionGetTicket(i);
      if (ticket > 0){
         if (PositionSelectByTicket(ticket)){
            ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
            if (type==posType){
               obj_Trade.PositionModify(ticket,sl,0);
            }
         }
      }
   }
}

En esta función:

  1. Recorrer posiciones: Utiliza PositionsTotal() para recorrer todas las posiciones abiertas.
  2. Obtener boleto: Devuelve el lugar en el número de boleto de index[i].
  3. Verificar Ticket: Verificar que el número de ticket sea real (más de 0).
  4. Seleccionar posición: Utiliza PositionSelectByTicket para elegir la posición.
  5.  Verificar tipo de posición: Verifica que posType especificado coincida con el tipo de posición.
  6. Modificar posición: Utilice PositionModify para cambiar las coincidencias del tipo de posición.

El código completo de la estrategia de negociación de órdenes en cascada es el siguiente:

//|                                                     CASCADE ORDERING.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include <Trade/Trade.mqh>
CTrade obj_Trade;

int handleMAFast;
int handleMASlow;
double maSlow[], maFast[];

double takeProfit = 0;
double stopLoss = 0;
bool isBuySystemInitiated = false;
bool isSellSystemInitiated = false;

input int slPts = 300;
input int tpPts = 300;
input double lot = 0.01;
input int slPts_Min = 100;
input int fastPeriods = 10;
input int slowPeriods = 20;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit() {
    handleMAFast = iMA(_Symbol, _Period, fastPeriods, 0, MODE_EMA, PRICE_CLOSE);
    if (handleMAFast == INVALID_HANDLE) {
        Print("UNABLE TO LOAD FAST MA, REVERTING NOW");
        return (INIT_FAILED);
    }

    handleMASlow = iMA(_Symbol, _Period, slowPeriods, 0, MODE_EMA, PRICE_CLOSE);
    if (handleMASlow == INVALID_HANDLE) {
        Print("UNABLE TO LOAD SLOW MA, REVERTING NOW");
        return (INIT_FAILED);
    }

    ArraySetAsSeries(maFast, true);
    ArraySetAsSeries(maSlow, true);

    return (INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
    // Cleanup code if necessary
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick() {
    double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits);
    double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits);

    if (CopyBuffer(handleMAFast, 0, 1, 3, maFast) < 3) {
        Print("NO ENOUGH DATA FROM FAST MA FOR ANALYSIS, REVERTING NOW");
        return;
    }
    if (CopyBuffer(handleMASlow, 0, 1, 3, maSlow) < 3) {
        Print("NO ENOUGH DATA FROM SLOW MA FOR ANALYSIS, REVERTING NOW");
        return;
    }

    if (PositionsTotal() == 0) {
        isBuySystemInitiated = false;
        isSellSystemInitiated = false;
    }

    if (PositionsTotal() == 0 && IsNewBar()) {
        if (maFast[0] > maSlow[0] && maFast[1] < maSlow[1]) {
            Print("BUY SIGNAL");
            takeProfit = Ask + tpPts * _Point;
            stopLoss = Ask - slPts * _Point;
            obj_Trade.Buy(lot, _Symbol, Ask, stopLoss, 0);
            isBuySystemInitiated = true;
        } else if (maFast[0] < maSlow[0] && maFast[1] > maSlow[1]) {
            Print("SELL SIGNAL");
            takeProfit = Bid - tpPts * _Point;
            stopLoss = Bid + slPts * _Point;
            obj_Trade.Sell(lot, _Symbol, Bid, stopLoss, 0);
            isSellSystemInitiated = true;
        }
    } else {
        if (isBuySystemInitiated && Ask >= takeProfit) {
            takeProfit = takeProfit + tpPts * _Point;
            stopLoss = Ask - slPts_Min * _Point;
            obj_Trade.Buy(lot, _Symbol, Ask, 0);
            ModifyTrades(POSITION_TYPE_BUY, stopLoss);
        } else if (isSellSystemInitiated && Bid <= takeProfit) {
            takeProfit = takeProfit - tpPts * _Point;
            stopLoss = Bid + slPts_Min * _Point;
            obj_Trade.Sell(lot, _Symbol, Bid, 0);
            ModifyTrades(POSITION_TYPE_SELL, stopLoss);
        }
    }
}

    static int prevBars = 0;
    int currBars = iBars(_Symbol, _Period);
    if (prevBars == currBars) return (false);
    prevBars = currBars;
    return (true);
}

//+------------------------------------------------------------------+
//| ModifyTrades Function                                            |
//+------------------------------------------------------------------+

void ModifyTrades(ENUM_POSITION_TYPE posType, double sl) {
    for (int i = 0; i <= PositionsTotal(); i++) {
        ulong ticket = PositionGetTicket(i);
        if (ticket > 0) {
            if (PositionSelectByTicket(ticket)) {
                ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
                if (type == posType) {
                    obj_Trade.PositionModify(ticket, sl, 0);
                }
            }
        }
    }
}


Conclusión

Finalmente, este asesor experto MQL5 es un gran ejemplo de una estrategia de negociación de cruce de medias móviles bien ejecutada. El artículo muestra una automatización eficiente de las opciones comerciales mediante el uso de la biblioteca Trade.mqh para agilizar la gestión de órdenes e incluir niveles dinámicos para tomar ganancias y detener pérdidas.

Entre los atributos más destacados de este asesor experto se encuentran:

  • Inicialización y gestión: Las señales de compra y venta basadas en cruces se gestionan sistemáticamente y los promedios móviles se inicializan de manera eficiente.
  • Gestión de riesgos: Uso de procedimientos de toma de ganancias y de stop loss para reducir los riesgos y garantizar recompensas dentro de límites configurables por el usuario.
  • Modularidad y flexibilidad: Uso de parámetros de entrada y variables globales para personalizar y adaptarse a diferentes situaciones del mercado y preferencias comerciales. 

Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/15250

Desarrollo de un robot de trading en Python (Parte 3): Implementamos un algoritmo comercial basado en el modelo Desarrollo de un robot de trading en Python (Parte 3): Implementamos un algoritmo comercial basado en el modelo
Hoy vamos a continuar con la serie de artículos sobre la creación de un robot comercial en Python y MQL5. En esta ocasión, resolveremos el problema relacionado con la creación de un algoritmo comercial en Python.
Desarrollamos un asesor experto multidivisa (Parte 13): Automatización de la segunda fase: selección en grupos Desarrollamos un asesor experto multidivisa (Parte 13): Automatización de la segunda fase: selección en grupos
Ya hemos puesto en marcha la primera fase del proceso de optimización automatizada. Para distintos símbolos y marcos temporales, realizamos la optimización utilizando varios criterios y almacenamos información sobre los resultados de cada pasada en la base de datos. Ahora vamos a seleccionar los mejores grupos de conjuntos de parámetros de entre los encontrados en la primera etapa.
Herramientas econométricas para la previsión de la volatilidad: el modelo GARCH Herramientas econométricas para la previsión de la volatilidad: el modelo GARCH
El presente artículo describe las propiedades de un modelo de heteroscedasticidad condicional no lineal (GARCH). Sobre esta base se construye el indicador iGARCH para predecir la volatilidad un paso por delante. Para estimar los parámetros del modelo se usará la biblioteca de análisis numérico ALGLIB.
Creación de una interfaz gráfica de usuario interactiva en MQL5 (Parte 2): Añadir controles y capacidad de respuesta Creación de una interfaz gráfica de usuario interactiva en MQL5 (Parte 2): Añadir controles y capacidad de respuesta
Mejorar el panel GUI de MQL5 con funciones dinámicas puede mejorar significativamente la experiencia comercial de los usuarios. Al incorporar elementos interactivos, efectos de desplazamiento y actualizaciones de datos en tiempo real, el panel se convierte en una herramienta poderosa para los traders modernos.