English Русский 中文 Deutsch 日本語
preview
Desarrollo de asesores expertos autooptimizables en MQL5 (Parte 2): Estrategia de scalping en el USDJPY

Desarrollo de asesores expertos autooptimizables en MQL5 (Parte 2): Estrategia de scalping en el USDJPY

MetaTrader 5Ejemplos |
33 2
Gamuchirai Zororo Ndawana
Gamuchirai Zororo Ndawana

En nuestro último debate sobre la creación de asesores expertos autooptimizables en MQL5, creamos un modelo de regresión lineal para generar señales de entrada y salida para nuestra aplicación de trading. Puede encontrar un enlace al artículo anterior aquí. En retrospectiva, es posible que no necesitemos todas las partes móviles disponibles en un modelo de aprendizaje automático. Más bien, podemos observar los modelos de aprendizaje automático como un ejemplo de cómo resolver problemas del mundo real utilizando reglas dinámicas. Entonces, podemos utilizar los mismos principios simples de pensamiento y lógica para guiar potencialmente nuestras aplicaciones comerciales hacia niveles más altos de rentabilidad sin necesidad de crear una base de código gigantesca que mantener.

Para nuestro análisis de hoy, nuestro objetivo es operar con el par USDJPY de forma rentable en el marco temporal diario. Nuestra estrategia comercial se basará en patrones de velas japonesas. En concreto, operaremos con patrones de reversión creados por velas envolventes. Nuestras reglas para una vela envolvente alcista se cumplirán si nuestro precio de apertura es inferior al cierre del día anterior y el precio de cierre es superior al precio de apertura del día anterior. En la figura 1 se muestra un ejemplo. Se cree que estos patrones de velas japonesas muestran que un determinado nivel de precios fue rechazado con considerable fuerza.

Figura 1: Hemos identificado un ejemplo de nuestro patrón de velas alcistas.

Los operadores creen que los patrones de velas envolventes son una señal de que se está formando una nueva tendencia en el mercado. Si se identifican correctamente, suelen ir seguidas de una evolución constante de los precios en la dirección de la nueva tendencia, véase la figura 2 a continuación. Esto sienta las bases para la estrategia comercial, tratando de identificar correctamente el patrón comercial. Las velas envolventes bajistas pueden utilizarse para identificar el inicio de tendencias bajistas. Utilizamos las mismas reglas que acabamos de describir, pero de manera opuesta.

Figura 2: Nuestro patrón de velas japonesas resultó fiable en este ejemplo concreto.

Normalmente, se cree que estas estrategias son válidas en todos los marcos temporales. Sin embargo, creo que el marco temporal diario puede ser el más fiable y lo he seleccionado como nuestro marco temporal preferido para este ejercicio. Intentemos implementar una estrategia para operar con las señales de entrada generadas por nuestra comprensión de estos patrones particulares del mercado. También nos interesará ver si podemos aumentar nuestra rentabilidad realizando ajustes en la estrategia original.



Introducción a MQL5

Nuestro programa tendrá 6 partes principales que necesitaremos para lograr nuestro objetivo de operar con patrones de velas de manera rentable.

Parte
Objetivo
Inicialización
Esta parte de nuestro sistema será responsable de cargar y configurar las variables globales.

Desinicialización

Libere recursos que nuestra aplicación ya no utiliza para garantizar una experiencia estable para el usuario final.
OnTick
Actualiza las variables del sistema y analiza el gráfico actual en busca de nuestros patrones de velas japonesas.
Funciones personalizadas
Realizar trabajos especializados necesarios para alcanzar nuestro objetivo.
Constantes del sistema
Constantes que no están destinadas a ser modificadas por el usuario final.
Variables globales
Realice un seguimiento del último tipo de orden que hemos realizado, los precios actuales de mercado que se ofrecen y los niveles de volatilidad. Para ello se crearon variables como «trade» y «bid». El rango medio verdadero (Average True Range, ATR) nos ayudará a colocar órdenes stop loss y take profit para nuestras posiciones.

Inicialmente, nuestra estrategia solo realizará operaciones una vez que se haya identificado nuestro patrón de velas japonesas. Si se identifica el patrón y no tenemos posiciones abiertas, tomaremos la señal y utilizaremos el ATR para establecer y ajustar nuestro stop loss. De lo contrario, nuestro sistema gestionará todas las operaciones que hayamos abierto. Por lo tanto, las variables globales de nuestro sistema serán:

Variable
Description
trade
Con el fin de informarnos sobre el tipo de puesto que tenemos actualmente disponible, esto nos facilitará la actualización de nuestras paradas y cualquier otra tarea que se nos ocurra en el futuro.
atr_handler
Importante para actualizar nuestros stop loss de forma coherente.
bid, ask
Seguimiento de los precios de mercado.

Para comenzar, primero crearemos una versión de referencia de nuestra estrategia comercial. Comencemos definiendo las constantes del sistema. Estas constantes se crearán utilizando la directiva #define. La directiva #define instruye al preprocesador integrado en nuestro editor MQL5 a reemplazar cualquier ocurrencia del identificador de macro que hemos especificado y colocar en su lugar lo que hemos asignado a la derecha del identificador de macro.

La primera constante del sistema que hemos definido es "SYMBOL". Cuando compilamos nuestra aplicación, el preprocesador sustituirá todas las instancias de «SYMBOL» en nuestro código por el valor «USDJPY». Esta sencilla función nos proporciona un control completo y predecible sobre el sistema, y nos garantiza la coherencia en todas nuestras pruebas, atributos que nos resultan muy atractivos.

//+------------------------------------------------------------------+
//|                                      Dynamic Stops Benchmark.mq5 |
//|                                        Gamuchirai Zororo Ndawana |
//|                          https://www.mql5.com/en/gamuchiraindawa |
//+------------------------------------------------------------------+
#property copyright "Gamuchirai Zororo Ndawana"
#property link      "https://www.mql5.com/en/gamuchiraindawa"
#property version   "1.00"
//+------------------------------------------------------------------+
//| This trading application is intended to serve as our benchmark.  |
//| Our goal is to learn what it will take to surpass the benchmark. |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| System constants                                                 |
//+------------------------------------------------------------------+
#define SYMBOL          "USDJPY"    //--- System pair
#define DAILY           PERIOD_D1   //--- Daily  time frame
#define VOL             0.1         //--- Trading volume
#define ATR_PERIOD      14          //--- Technical Indicator ATR Period
#define ATR_MULTIPLE    2           //--- Stop loss ATR multiple

También necesitaremos cargar la biblioteca comercial.

//+------------------------------------------------------------------+
//| Libraries                                                        |
//+------------------------------------------------------------------+
#include <Trade/Trade.mqh>
CTrade Trade;

Ahora definiremos nuestras variables globales. Estas variables nos ayudarán a realizar un seguimiento de nuestra posición abierta y las cotizaciones actuales del mercado.

//+------------------------------------------------------------------+
//| Global variables                                                 |
//+------------------------------------------------------------------+
int    trade = 0;
int    atr_handler;
double atr[];
double bid,ask;

Al inicializar, llamaremos a una función especializada responsable de inicializar nuestras variables del sistema.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   setup();
//---
   return(INIT_SUCCEEDED);
  }

Si ya no utilizamos nuestra aplicación comercial, entonces publicaremos los indicadores técnicos que ya no utilizamos.

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Release the indicator
   release();
  }

Actualizaremos nuestras variables del sistema una vez al final del día. Esto se puede cambiar a su gusto para una mejor gestión de riesgos. He optado por actualizar las variables del sistema solo una vez al día para que las pruebas retrospectivas se completen de manera oportuna, lo que nos permitirá comparar más fácilmente los cambios que estamos realizando.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   update();
  }
//+------------------------------------------------------------------+

La primera función personalizada que crearemos será responsable de liberar recursos del sistema que ya no consumimos.

//+------------------------------------------------------------------+
//| Custom Functions                                                 |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Release variables we don't need                                  |
//+------------------------------------------------------------------+
void release(void)
  {
   IndicatorRelease(atr_handler);
  }

Actualice nuestras variables del sistema una vez al día.

//+------------------------------------------------------------------+
//| Update system                                                    |
//+------------------------------------------------------------------+
void update(void)
  {
   static datetime daily_timestamp;
   datetime daily_time = iTime(SYMBOL,DAILY,0);
   if(daily_timestamp != daily_time)
     {
      //--- Update the time
      daily_timestamp = daily_time;
      //--- Update system variables
      daily_update();
      //--- Do we have an oppurtunity to trade?
      if((PositionsTotal() == 0))
         find_setup();
      //--- Do we have positions to manage?
      if(PositionsTotal() > 0)
         manage_setup();
     }
  }

Gestione nuestras operaciones actualizando el stop loss y el take profit únicamente si la nueva posición del stop loss o take profit será más rentable.

//+------------------------------------------------------------------+
//| Manage our trades                                                |
//+------------------------------------------------------------------+
void manage_setup(void)
  {
//--- Select the position
   if(PositionSelect(SYMBOL))
     {
      //--- Get ready to update the SL/TP
      double initial_sl  = PositionGetDouble(POSITION_SL);
      double initial_tp  = PositionGetDouble(POSITION_TP);
      double buy_sl      = (ask - (ATR_MULTIPLE * atr[0]));
      double sell_sl     = (bid + (ATR_MULTIPLE * atr[0]));
      double buy_tp      = (ask + (ATR_MULTIPLE * atr[0]));
      double sell_tp     = (bid - (ATR_MULTIPLE * atr[0]));
      double new_sl      = ((trade == 1) && (initial_sl <  buy_sl))? (buy_sl) : ((trade == -1) && (initial_sl > sell_sl)) ? (sell_sl) : (initial_sl);
      double new_tp      = ((trade == 1) && (initial_tp <  buy_tp))? (buy_tp) : ((trade == -1) && (initial_tp > sell_tp)) ? (sell_tp) : (initial_tp);
      //--- Update the position
      Trade.PositionModify(SYMBOL,new_sl,new_tp);
     }
  }

Configurar indicadores técnicos. Hasta el momento solo tenemos un indicador técnico para gestionar.

//+------------------------------------------------------------------+
//| Get our technical indicators ready                               |
//+------------------------------------------------------------------+
void setup(void)
  {
   atr_handler         = iATR(SYMBOL,DAILY,ATR_PERIOD);
  }

Actualizar el estado del sistema.

//+------------------------------------------------------------------+
//| Daily update routine                                             |
//+------------------------------------------------------------------+
void daily_update(void)
  {
//--- Get current prices
   ask = SymbolInfoDouble(SYMBOL,SYMBOL_ASK);
   bid = SymbolInfoDouble(SYMBOL,SYMBOL_BID);
//--- Update Technical Indicators
   CopyBuffer(atr_handler,0,0,1,atr);
//--- Check for engulfing candles.
   int candles_state = check_candles();
//--- Give feedback
   Comment("Candle State: ",candles_state);
  }

Consulte nuestro patrón de velas. Si se encuentra el patrón, devolveremos 1 o -1 y colocaremos una operación larga o corta. De lo contrario, esperaremos.

//+------------------------------------------------------------------+
//| Check if we have any engulfing candles                           |
//+------------------------------------------------------------------+
int check_candles(void)
  {
//--- Return 1 if we have a bullish engulfing candle
   if((iOpen(SYMBOL,DAILY,0) < iClose(SYMBOL,DAILY,1)) && (iClose(SYMBOL,DAILY,0) > iOpen(SYMBOL,DAILY,1)))
      return(1);

//--- Return -1 if we have a bearish engulfing candle
   if((iOpen(SYMBOL,DAILY,0) > iClose(SYMBOL,DAILY,1)) && (iClose(SYMBOL,DAILY,0) < iOpen(SYMBOL,DAILY,1)))
      return(-1);

//--- Otherwise return 0
   return(0);
  }

Nuestro sistema sabrá que ha encontrado una configuración comercial si el estado de la vela no es 0. De lo contrario, no es necesario hacer nada más por ahora.

//+------------------------------------------------------------------+
//| Find setup                                                       |
//+------------------------------------------------------------------+
void find_setup(void)
  {
//--- Our sentiment is bullish
   int candles_state = check_candles();
   if(candles_state == 1)
     {
      Trade.Buy(VOL,SYMBOL,ask,(ask - (ATR_MULTIPLE * atr[0])),(ask + (ATR_MULTIPLE * atr[0])),"");
      trade = 1;
     }

//--- Our sentiment is bearish
   if(candles_state == -1)
     {
      Trade.Sell(VOL,SYMBOL,bid,(bid + (ATR_MULTIPLE * atr[0])),(bid - (ATR_MULTIPLE * atr[0])),"");
      trade = -1;
     }
  }
//+------------------------------------------------------------------+

La figura 3 a continuación nos permite ver cómo luce nuestro sistema. Nuestro sistema realiza un seguimiento de la presencia o ausencia de nuestro patrón de velas y realiza operaciones si se encuentra el patrón. Con nuestra configuración actual, las posiciones de stop loss y take profit se moverán una vez al día, al final del día.

Nuestra estrategia visualizada

Figura 3: Visualización de nuestra estrategia comercial en el marco temporal diario del USDJPY

Probaremos nuestra nueva estrategia a lo largo de 4 años de datos históricos, desde el 1 de enero de 2020 hasta finales de noviembre de 2024. Si desea seguir adelante y desea realizar cambios en estas configuraciones, asegúrese de realizar también los cambios apropiados en las variables del sistema. De lo contrario, nuestro sistema continuará operando con el USDJPY en el marco temporal diario, independientemente de los símbolos y el marco temporal que especifiquemos.

Configuración del sistema

Figura 4: La configuración principal para nuestra prueba retrospectiva

El retraso aleatorio es el más cercano a los escenarios comerciales reales y nos permite realizar pruebas de estrés a nuestro sistema. Asegúrese de ajustar el "Deposit" y el apalancamiento de la cuenta para que coincidan con su configuración comercial prevista si está considerando utilizar la estrategia en la práctica.

Nuestro segundo lote de configuraciones

Figura 5: Selección del tipo de modelado y el tamaño de la cuenta para nuestra prueba retrospectiva

La curva de capital producida por la estrategia es prometedora. Nuestra estrategia de scalping aumentó el tamaño de la cuenta en aproximadamente un 4% en esta prueba retrospectiva. Como ocurre con cualquier estrategia comercial, atravesó períodos sostenidos de pérdidas. Pero lo más destacable de esta estrategia es su capacidad para recuperarse de períodos de pérdida.

La rentabilidad de nuestro sistema

Figura 6: Visualización del saldo de nuestra cuenta comercial a lo largo del tiempo

Veamos ahora más de cerca el desempeño de nuestra estrategia. En su forma actual, nuestra estrategia tenía un ratio de Sharpe de 1,12 y una tasa de éxito del 44,68%. ¿Qué se necesita para reducir el tamaño de la pérdida promedio de $133,22 y acercarla a 0 mientras minimizamos nuestro impacto en la ganancia promedio?

Nuestros resultados de backtest

Figura 7: Un análisis detallado del rendimiento de nuestras pruebas retrospectivas



Mejorando nuestros resultados

Nuestro sistema es rentable en su estado actual. ¿Hay algún cambio que podamos hacer que nos permita ejercer más control sobre las operaciones perdedoras? Propondré algunos cambios a la estrategia original:

Cambio propuesto
 Propósito previsto
Confirmación adicional
Al utilizar una estrategia de confirmación adicional junto con nuestra estrategia ya rentable, potencialmente podemos filtrar más operaciones no rentables.
Añadir relleno adicional al stop loss
Queremos minimizar la cantidad de veces que nos impiden realizar operaciones ganadoras.
Tenga en cuenta la volatilidad del mercado
Cada mercado tiene potencialmente niveles de volatilidad únicos. Nuestra estrategia comercial debe intentar considerar los niveles históricos de volatilidad, para analizar los niveles de precios actuales con cierto nivel de contexto, como lo hacen los traders humanos profesionales.

Con suerte, al implementar estos cambios, reduciremos nuestra proporción de operaciones no rentables. Al tomar estas decisiones siempre hay que hacer concesiones. En última instancia, nuestra nueva estrategia ocasionalmente perderá operaciones rentables que nuestra estrategia anterior habría logrado fácilmente.

Es lógico que, al final, no ejercer ningún control sobre el tamaño de nuestra pérdida promedio podría potencialmente costarnos todas las ganancias que trabajamos para acumular. Para realizar los cambios deseados, tendremos que introducir cambios en nuestra versión actual de la aplicación.

Cambio de sistema
Description
Nuevas variables del sistema
Para tener en cuenta la volatilidad del mercado, primero tenemos que decidir cuántos datos del pasado debemos recuperar. Esto lo manejará una nueva variable del sistema, apropiadamente llamada “fetch”. Además, necesitaremos fijar los parámetros de cualquier indicador técnico que utilicemos.
Indicadores técnicos
Podemos obtener confirmación adicional mediante el uso de estrategias comerciales con indicadores técnicos. Hoy emplearemos una estrategia de canal de media móvil. Por lo tanto, crearemos nuevos manejadores de indicadores y buffers para almacenar esta nueva información.
Confluencia de señales
Crearemos una nueva variable global llamada “sentiment”. Su valor será 1 o -1 cuando tanto nuestro patrón de velas como nuestros indicadores técnicos sean alcistas (1) o bajistas (-1). En caso contrario su valor será 0. Nuestro sistema solo realizará operaciones cuando nuestro valor de sentimiento no sea igual a 0.
Funciones personalizadas
Para lograr el comportamiento que deseamos de nuestro sistema, tendremos que ampliar algunas de las funciones personalizadas que ya hemos creado, así como crear algunas funciones nuevas.


Descripción general de la estrategia de confirmación

Nuestra estrategia de confirmación se basará en estrategias de negociación de canales de media móvil. Esta estrategia se crea mediante 2 medias móviles que siguen los precios máximos y mínimos respectivamente. Las dos medias móviles crean un canal. Tenga en cuenta que las medias móviles no se cruzan entre sí. Por lo tanto, nuestras señales de entrada se generan cuando una vela se forma completamente fuera de la región entre las dos medias móviles.

El razonamiento detrás de esta estrategia es que los niveles de precios entre la media móvil alta y baja se consideran estables. Por el contrario, cuando los niveles de precios se forman más allá de la región entre las dos medias móviles, percibimos un desequilibrio en el mercado. La estrategia sugiere que se trata de la formación de una nueva tendencia en la dirección del desequilibrio. La figura 8 muestra cómo utilizaríamos la estrategia.

La flecha roja representa una región óptima para haber ocupado una posición corta según la estrategia. La configuración se considera válida, por lo general, hasta que los niveles de precios vuelven al canal. En ese momento, nuestras posiciones pueden cerrarse y esperaremos a que se detecte el siguiente desequilibrio. Este segundo desequilibrio está marcado por la flecha azul. Dado que el desequilibrio apareció por encima de nuestro canal de media móvil, lo habríamos interpretado como una señal para comprar.

Figura 8: Nuestra estrategia de canal de media móvil para identificar puntos de entrada y salida.

Ampliaremos aún más la idea, teniendo en cuenta también los máximos y mínimos históricos experimentados en el mercado. Calcularemos el punto medio formado por el último año hasta la fecha de los precios máximos y mínimos históricos ofrecidos en el mercado. Además, utilizaremos la información para restringir o aplicar únicamente posiciones largas cuando el precio de cierre esté por encima del punto medio histórico entre el máximo y el mínimo, y lo contrario se aplicará a nuestras posiciones cortas.

La línea horizontal roja de la figura 9 simboliza la media de los precios máximos y mínimos del último año hasta la fecha. Este punto medio se actualiza cada día por nuestro sistema y servirá como lente para que nuestra aplicación vea los niveles de precios.

Marcando el punto medio

Figura 9: El punto medio histórico del último año hasta la fecha de los precios máximos y mínimos ofrecidos en el mercado.

Tipo de posición
Nuevos criterios de posición
Largo
Se ha formado una vela alcista envolvente, por encima del canal de la media móvil, y los niveles de precios se han elevado por encima de los niveles de volatilidad medios anuales.
Corto
Se ha formado una vela bajista envolvente por encima del canal de la media móvil y los niveles de precios se elevan por encima de los niveles de volatilidad promedio anual.

Con suerte, al usar nuestras dos estrategias juntas, podremos filtrar las operaciones no rentables que causaron problemas a nuestro antiguo sistema y, al mismo tiempo, conservar las operaciones rentables que queremos conservar. Comencemos a implementar estos cambios para ver qué tan efectivos serán. Primero debemos definir nuevas variables del sistema que fijarán los períodos de nuestro canal de media móvil y la cantidad de datos históricos que obtendremos para calcular nuestro punto medio.

//+------------------------------------------------------------------+
//|                                  USDJPY Price Action Benchmark 2 |
//|                                        Gamuchirai Zororo Ndawana |
//|                          https://www.mql5.com/en/gamuchiraindawa |
//+------------------------------------------------------------------+
#property copyright "Gamuchirai Zororo Ndawana"
#property link      "https://www.mql5.com/en/gamuchiraindawa"
#property version   "1.00"
//+------------------------------------------------------------------+
//| This trading application is intended to surpass our benchmark.   |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| System constants                                                 |
//+------------------------------------------------------------------+
//--- I have intentionally omitted parts of the system that remained unchanged
#define FETCH           365            //--- How much should we fetch?
#define MA_PERIOD       90             //--- Moving average period

También necesitaremos algunas variables globales adicionales para realizar un seguimiento de los estados del mercado que hemos definido.

//+------------------------------------------------------------------+
//| Global variables                                                 |
//+------------------------------------------------------------------+
int    sentiment = 0;
int    trade = 0;
int    ma_high_handler, ma_low_handler;
double ma_high[],ma_low[];

El cuerpo de nuestra aplicación seguirá siendo el mismo. Sin embargo, algunas de las funciones que se están llamando han cambiado.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Setup our system varaibles
   setup();
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Release any resources 
   release();
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Update system variables
   update();
  }
//+------------------------------------------------------------------+

Repasemos ahora los cambios realizados en las funciones personalizadas. Los dos primeros cambios consistirán en cargar nuestros indicadores técnicos y publicarlos posteriormente.

//+------------------------------------------------------------------+
//| Custom Functions                                                 |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Release our technical indicators                                 |
//+------------------------------------------------------------------+
void release(void)
  {
   IndicatorRelease(atr_handler);
   IndicatorRelease(ma_low_handler);
   IndicatorRelease(ma_high_handler);
  }

Estos cambios en nuestro código base van de la mano y son fáciles de entender.

//+------------------------------------------------------------------+
//| Get our technical indicators ready                               |
//+------------------------------------------------------------------+
void setup(void)
  {
   atr_handler         = iATR(SYMBOL,DAILY,ATR_PERIOD);
   ma_high_handler     = iMA(SYMBOL,DAILY,MA_PERIOD,0,MODE_EMA,PRICE_HIGH);
   ma_low_handler      = iMA(SYMBOL,DAILY,MA_PERIOD,0,MODE_EMA,PRICE_LOW);
  }

Nuestra rutina diaria de actualización también debe ampliarse. Ahora también nos interesa saber cómo se comparan los niveles de precios actuales con los niveles históricos de ruido esperados en este mercado. Si nuestros patrones de velas japonesas y los niveles de precios nos dan una señal coincidente, entonces buscaremos la validación de nuestro canal de media móvil para determinar si es un buen momento para ejecutar nuestra operación.

//+------------------------------------------------------------------+
//| Daily update routine                                             |
//+------------------------------------------------------------------+
void daily_update(void)
  {
//--- Get current prices
   ask = SymbolInfoDouble(SYMBOL,SYMBOL_ASK);
   bid = SymbolInfoDouble(SYMBOL,SYMBOL_BID);
//--- Update Technical Indicators
   CopyBuffer(atr_handler,0,0,1,atr);
   CopyBuffer(ma_high_handler,0,0,1,ma_high);
   CopyBuffer(ma_low_handler,0,0,1,ma_low);
//--- Check for engulfing candles.
   int candles_state = check_candles();
//--- Compare current price levels to historical price levels in the market
   int price_state  = check_price_levels();
//--- Check our tech
//--- What is our sentiment?
//--- Our sentiment is well defined.
   if(candles_state == price_state)
      sentiment = candles_state;
//--- Wait.
   if(candles_state != price_state)
      sentiment = 0;
//--- Give feedback
   Comment("Sentiment: ",sentiment,"\nCandle State: ",candles_state,"\nPrice State: ",price_state);
  }

Utilizaremos el tipo vectorial MQL5 para calcular y realizar un seguimiento de nuestras estadísticas de mercado sobre la marcha con facilidad.

//+------------------------------------------------------------------+
//| Check if we are closer to the all time high or low               |
//+------------------------------------------------------------------+
int check_price_levels(void)
  {
//--- Get historical prices
   vector highs = vector::Zeros(FETCH);
   vector lows  = vector::Zeros(FETCH);
   highs.CopyRates(SYMBOL,DAILY,COPY_RATES_HIGH,0,FETCH);
   lows.CopyRates(SYMBOL,DAILY,COPY_RATES_LOW,0,FETCH);

//--- First we shall calculate the mid point between the all time high and low
   vector mid = ((highs + lows) / 2);

//--- Return 1 if we are above the mid point
   if(iClose(SYMBOL,DAILY,0) > mid.Mean())
      return(1);

//--- Return -1 if we are above the mid point
   if(iClose(SYMBOL,DAILY,0) < mid.Mean())
      return(-1);

//--- Otherwise return 0
   return(0);
  }

Nuestras nuevas reglas para encontrar una configuración comercial tendrán en cuenta dos filtros adicionales. El nivel de precios en relación con el punto medio anual y el nivel de precios en relación con el canal de la media móvil. Si ambas estrategias concuerdan, realizaremos nuestra operación en consecuencia.
//+------------------------------------------------------------------+
//| Find setup                                                       |
//+------------------------------------------------------------------+
void find_setup(void)
  {
//--- Our sentiment is bullish
   if(sentiment == 1)
     {
      if((iOpen(SYMBOL,DAILY,0) > ma_high[0]) && (iClose(SYMBOL,DAILY,0) > ma_high[0]))
        {
         Trade.Buy(VOL,SYMBOL,ask,(ask - (ATR_MULTIPLE * atr[0])),(ask + (ATR_MULTIPLE * atr[0])),"");
         trade = 1;
        }
     }

//--- Our sentiment is bearish
   if(sentiment == -1)
     {
      if((iOpen(SYMBOL,DAILY,0) < ma_low[0]) && (iClose(SYMBOL,DAILY,0) < ma_low[0]))
        {
         Trade.Sell(VOL,SYMBOL,bid,(bid + (ATR_MULTIPLE * atr[0])),(bid - (ATR_MULTIPLE * atr[0])),"");
         trade = -1;
        }
     }
  }
//+------------------------------------------------------------------+

Podemos echar un vistazo a nuestra estrategia en acción. Tenga en cuenta que nuestra estrategia ahora realiza un seguimiento de tres condiciones que deben cumplirse antes de comprometernos con cualquier posición. Esperamos que, al seleccionar cuidadosamente las condiciones adecuadas, no todas se cumplan por casualidad.

Nuestra nueva estrategia mejorada

Figura 10: Estamos probando nuevamente nuestra estrategia revisada de scalping del USDJPY con datos históricos del mercado.

Como dijimos anteriormente, las configuraciones sobre la duración y el período de la prueba retrospectiva se mantendrán fijas para mantener la coherencia en ambas pruebas. Por lo tanto, nuestras fechas corresponden con las fechas de la prueba anterior.

Probando nuestra nueva estrategia USDJPY

Figura 11: Nuestras configuraciones para la prueba retrospectiva se fijarán en ambas pruebas.

Recuerde que puede sentirse libre de ajustar estas configuraciones particulares para reflejar el entorno en el que desea utilizarlas.

Segundo lote de entradas para nuestra estrategia de scalping del USDJPY

Figura 12: El segundo lote de configuraciones para nuestra prueba retrospectiva

La curva de capital producida por nuestra nueva estrategia tiene menos períodos de caída en comparación con nuestra primera prueba retrospectiva. Por ejemplo, en el período comprendido entre enero de 2020 y cerca de diciembre de 2023, la curva de capital producida por nuestra estrategia inicial estaba en un lugar, oscilando alrededor del saldo inicial. Si bien nuestra nueva curva de capital no tiene esa característica indeseable. Nuestra curva de acciones creció en una tendencia menos volátil desde septiembre de 2022 hasta el final de la prueba retrospectiva.

La nueva curva de capital producida por nuestra estrategia revisada USDJPY

Figura 13: La curva de capital generada por nuestra estrategia comercial revisada

Tras una inspección más detallada, observamos que logramos nuestro objetivo de acercar la pérdida promedio y la proporción de operaciones perdedoras a 0. Sin embargo, sólo redujimos marginalmente la proporción de operaciones con pérdidas, de aproximadamente el 55% a aproximadamente el 54%. Además, nuestros cambios también redujeron la rentabilidad de nuestra estrategia comercial. Esto no es un problema material porque podemos corregirlo aumentando de forma segura el tamaño de nuestro lote. Los mercados son entornos dinámicos, y las nuevas medidas de seguridad que hemos implementado pueden resultar muy valiosas en el futuro.

Análisis detallado del rendimiento de nuestra nueva estrategia de scalping USDJY.

Figura 14: Análisis detallado de nuestra segunda estrategia comercial.



Conclusión

En este artículo, cubrimos el potencial que se puede descubrir al operar con las señales generadas por patrones de velas. Si bien existen muchas críticas contra dichas estrategias, como el hecho de que es posible observar la forma del patrón de velas, pero no siempre es seguido por la misma acción del precio después, lo que puede generar dudas sobre la validez de la estrategia.

Sin embargo, siguiendo los ajustes que hemos discutido en esta estrategia y agregando su propio entendimiento del mercado, creo que cualquier duda sobre la rentabilidad de la estrategia puede ser razonablemente disipada. El desafío es que no siempre nos resulta obvio cómo los cambios que estamos realizando afectarán la rentabilidad de la estrategia.

Archivo
Description
Acción del precio de referencia del USDJPY
Esta aplicación fue la versión inicial y volátil de nuestra estrategia comercial; era más rentable, pero también conllevaba más riesgo.
Estrategia de acción del precio del USDJPY 2
Esta es la versión refinada de la estrategia que construimos juntos, es igual de rentable y trata de minimizar sus pérdidas.

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

Avijit Barua
Avijit Barua | 24 dic 2024 en 17:54
¿Puedo probar el EA? Lo he descargado pero por alguna razón no aparece en EA. Cualquier ayuda es muy apreciada. Gracias.
Gamuchirai Zororo Ndawana
Gamuchirai Zororo Ndawana | 24 dic 2024 en 18:44
Avi B #:
¿Puedo probar el EA? Lo he descargado pero por alguna razón no aparece en EA. Cualquier ayuda es muy apreciada. Gracias.
Hey Avi B, ¿eres capaz de compilar con éxito?
Utilizando redes neuronales en MetaTrader Utilizando redes neuronales en MetaTrader
En el artículo se muestra la aplicación de las redes neuronales en los programas de MQL, usando la biblioteca de libre difusión FANN. Usando como ejemplo una estrategia que utiliza el indicador MACD se ha construido un experto que usa el filtrado con red neuronal de las operaciones. Dicho filtrado ha mejorado las características del sistema comercial.
Creación de un modelo de restricción de tendencia de velas (Parte 9): Asesor Experto de múltiples estrategias (III) Creación de un modelo de restricción de tendencia de velas (Parte 9): Asesor Experto de múltiples estrategias (III)
¡Bienvenidos a la tercera entrega de nuestra serie sobre tendencias! Hoy profundizaremos en el uso de la divergencia como estrategia para identificar puntos de entrada óptimos dentro de la tendencia diaria predominante. También presentaremos un mecanismo de bloqueo de ganancias personalizado, similar a un stop-loss dinámico, pero con mejoras únicas. Además, actualizaremos el asesor experto Trend Constraint a una versión más avanzada, incorporando una nueva condición de ejecución comercial para complementar las existentes. A medida que avanzamos, continuaremos explorando la aplicación práctica de MQL5 en el desarrollo algorítmico, brindándole información más detallada y técnicas prácticas.
Particularidades del trabajo con números del tipo double en MQL4 Particularidades del trabajo con números del tipo double en MQL4
En estos apuntes hemos reunido consejos para resolver los errores más frecuentes al trabajar con números del tipo double en los programas en MQL4.
Indicador de previsión de volatilidad con Python Indicador de previsión de volatilidad con Python
Hoy pronosticaremos la volatilidad extrema futura utilizando una clasificación binaria. Asimismo, crearemos un indicador de previsión de volatilidad extrema usando el aprendizaje automático.