English Русский Deutsch 日本語 Português
preview
Cómo construir y optimizar un sistema de trading basado en la volatilidad (Chaikin Volatility - CHV)

Cómo construir y optimizar un sistema de trading basado en la volatilidad (Chaikin Volatility - CHV)

MetaTrader 5Trading | 10 septiembre 2024, 09:25
263 0
Mohamed Abdelmaaboud
Mohamed Abdelmaaboud

Introducción

En el ámbito de la negociación, el factor de volatilidad es muy importante como se sabe y hay muchas herramientas que se pueden utilizar para medir este factor a continuación, de acuerdo con lo que medimos podemos tomar decisiones comerciales que pueden ser mejores si tenemos en cuenta la volatilidad como parte de nuestro sistema de comercio.

En este artículo, vamos a analizar uno de estos indicadores técnicos de volatilidad llamado Chaikin Volatility (CHV). A lo largo del artículo, aprenderás qué es lo importante de Chaikin Volatility, qué significa, cómo podemos calcularla y cómo podemos utilizarla a nuestro favor para obtener mejores resultados en el trading. Utilizaremos el indicador basándonos en estrategias de trading simples (Cruce CHV y CHV + cruce MA).

Nuestro enfoque es entender cómo podemos considerar el Indicador Chaikin Volatility como una herramienta de volatilidad para obtener mejores resultados de trading que puedan ser fiables en términos de medición de volatilidad para formar parte de nuestro sistema de trading. Así pues, aprenderemos a crear sistemas de trading basados en estrategias basadas en la volatilidad y daremos un ejemplo de cómo optimizar nuestro sistema de trading añadiendo tácticas sencillas o combinando otras herramientas para obtener mejores resultados en comparación con los que podemos obtener sin esta optimización. También aprenderemos a crear nuestro propio indicador CHV para utilizarlo como parte de nuestro sistema de trading.

Como usted sabe, es muy importante para cualquier sistema de comercio para ser probado en diferentes entornos antes de usarlo para el comercio real para asegurarse de que será útil y adecuado para su comercio, ya que no hay estrategia que se adapte a todos. Así que vamos a hacer algunas pruebas simples para nuestro sistema de comercio sobre la base de estas dos estrategias de negociación mencionados y os animo a hacer sus pruebas utilizando diferentes aspectos que he utilizado en este artículo para ver cómo se puede mejorar su sistema para obtener mejores resultados que me dieron o incluso encontrar que esta herramienta no es adecuada o aplicable para su sistema de comercio en absoluto.

Trataremos todo esto en los siguientes temas:

También es importante saber que si estás aprendiendo a codificar para operar o a programar en general, es muy importante que practiques y escribas código tú mismo. Así que te animo a que codifiques lo que aprendas, ya que esto puede mejorar tus habilidades y conocimientos de programación.

Descargo de responsabilidad: Toda la información se facilita «tal cual», únicamente con fines educativos y no está preparada para fines comerciales ni de asesoramiento. La información no garantiza ningún tipo de resultado. Si decide utilizar estos materiales en cualquiera de sus cuentas de operaciones, lo hará por su cuenta y riesgo y será el único responsable.


Chaikin Volatility

En esta parte, identificaremos en detalle el Indicador Chaikin Volatility. El Chaikin Volatility fue creado por Marc Chaikin, creador de muchos indicadores técnicos que llevan su nombre. El CHV se utiliza para medir la volatilidad en el movimiento de los mercados financieros y puede ser útil para anticipar posibles retrocesos del mercado. Puede ser útil para determinar el rango de valor entre precios altos y bajos durante un periodo de tiempo para medir posibles movimientos u oscilaciones del mercado en cualquier dirección. El CHV no tiene en cuenta las lagunas de la misma forma que veremos al calcularlo. Es muy importante tener en cuenta que el aumento de la volatilidad puede significar alto riesgo o alta rentabilidad y viceversa.

El indicador CHV puede registrar valores altos o bajos, los valores al alza significan que los precios están cambiando muy rápidamente, pero los valores bajos significan que los precios son constantes y no hay mucha volatilidad en el activo subyacente. Lo que creo que es muy importante mencionar es que la volatilidad puede registrarse en mercados con tendencia o sin tendencia, no sólo en mercados con tendencia, ya que estamos midiendo la volatilidad y no la tendencia o dirección de los precios. Al utilizar otras herramientas técnicas que sirvan de confirmación sobre lo generado dará mejores resultados y esto es lo que haremos como mencionamos ya que trataremos de tomar nuestras decisiones acompañados del indicador técnico de media móvil para dar la dirección del mercado y tomar operaciones tendenciales en la medida de lo posible.

Como hemos mencionado, podemos utilizar el indicador CHV para predecir retrocesos del mercado, ya que a veces cuando el indicador registra valores relativamente altos, esto puede utilizarse para predecir retrocesos y posibles máximos o mínimos en el mercado. Ahora debemos entender cómo se calcula el indicador CHV para profundizar en el concepto principal que subyace al indicador.

H-L (i) = HIGH (i) - LOW (i)

H-L (i - 10) = HIGH (i - 10) - LOW (i - 10)

CHV = (EMA (H-L (i), 10) - EMA (H-L (i - 10), 10)) / EMA (H-L (i - 10), 10) * 100

Donde:

  • HIGH (i) - se refiere al precio máximo de la vela actual.
  • LOW (i) - se refiere al precio mínimo de la vela actual.
  • HIGH (i - 10) - se refiere al precio máximo de la vela desde la actual hasta diez posiciones más allá.
  • LOW (i - 10) - se refiere al precio mínimo de la vela desde la actual hasta diez posiciones atrás.
  • H-L (i) - se refiere a la diferencia entre el precio máximo y mínimo de la vela actual.
  • H-L (i - 10) - se refiere a la diferencia entre los precios máximo y mínimo de hace diez velas.
  • EMA - se refiere a la media móvil exponencial.


Indicador Chaikin Volatility personalizado

En esta sección, aprenderemos a codificar un indicador Chaikin Volatility personalizado utilizando MQL5, que puede ser útil ya que podemos personalizar el indicador para adaptarlo a nuestros objetivos. Los siguientes son los pasos para codificar nuestro indicador personalizado Chaikin Volatility (CHV):

Usa la directiva de preprocesador #include para poder utilizar el archivo de inclusión de medias móviles en el programa y realizar el cálculo.

#include <MovingAverages.mqh>

Utilizar el preprocesador #property para especificar parámetros adicionales que coincidan con los siguientes valores de identificador:

  • description: Establece un texto breve para el programa MQL5.
  • indicator_separate_window: Fija el lugar del indicador en una ventana separada.
  • indicator_buffers: Fija el número de búferes para el cálculo del indicador.
  • indicator_plots: Establece el número de series gráficas del indicador.
  • indicator_type1: Especifica el tipo de trazado gráfico, especificado por los valores de ENUM_DRAW_TYPE. N es el número de series gráficas; los números pueden empezar por 1.
  • indicator_color1: Especifica el color de visualización de la línea N, N es el número de series gráficas; los números pueden empezar por 1.
  • indicator_width1: Especifica el grosor de línea del indicador, N es el número de series gráficas; los números pueden empezar por 1.
#property description "Chaikin Volatility"
#property indicator_separate_window
#property indicator_buffers 3

#property indicator_plots   1
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_color1  MediumBlue
#property indicator_width1  3

Usando la palabra clave 'enum' para definir un conjunto de datos para el modo de suavizado de medias móviles:

enum smoothMode
  {
   SMA=0,// Simple MA
   EMA=1 // Exponential MA
  };

Establecer entradas para los ajustes del indicador mediante la palabra clave input:

input int          smoothPeriodInp=10;  // Smoothing Period
input int          chvPeriodInp=10;     // Chaikin Volatility Period
input smoothMode   InpSmoothType=EMA;   // Smoothing Mode

Declaración de tres matrices de búferes chv, hl y shl:

double             chvBuffer[];
double             hlBuffer[];
double             shlBuffer[];

Declarar dos variables globales para el periodo de alisado (smoothing, y el periodo CHV:

int                smoothPeriod,chvPeriod;

En la parte OnInit(), comprobaremos y especificaremos las variables de las entradas.

Nombre de la media móvil: Después de declarar el maName, el programa comprueba si la entrada es SMA, en cuyo caso el nombre será SMA (media móvil simple), o si la entrada es EMA, en cuyo caso el nombre será EMA (media móvil exponencial).

   string maName;
   if(InpSmoothType==SMA)
      maName="SMA";
   else
      maName="EMA";

Periodo de suavizado (Smoothing): El programa comprobará el periodo de suavizado, si es menor o igual que cero, se especificará el valor con un valor por defecto de 10 y se imprimirá un mensaje. Si el valor es diferente, es decir, superior a 10, se da como introducido.

   if(smoothPeriodInp<=0)
     {
      smoothPeriod=10;
      printf("Incorrect value for Smoothing Period input = %d. Default value = %d.",smoothPeriodInp,smoothPeriod);
     }
   else smoothPeriod=smoothPeriodInp;

Periodo CHV: El programa comprobará si el periodo CHV es menor o igual que cero, el valor se fijará en 10 por defecto y se imprimirá un mensaje. Si es diferente, es decir, superior a 10, se dará como introducido.

   if(chvPeriodInp<=0)
     {
      chvPeriod=10;
      printf("Incorrect value for Chaikin Volatility Period input = %d. Default value = %d.",chvPeriodInp,chvPeriod);
     }
   else chvPeriod=chvPeriodInp;

Define los buffers declarados utilizando la palabra clave SetIndexBuffer para devolver un valor bool. Sus parámetros son:

  • index: Número del búfer del indicador, parte de cero y es menor que el valor del identificador #property de indicator_buffers.
  • buffer[]: Para especificar la matriz declarada en el indicador personalizado.
  • data_type: Para especificar lo que se almacena. El valor por defecto es INDICATOR_DATA para chvBuffer y especificaremos INDICATOR_CALCULATIONS para que se utilice en el cálculo intermedio, no en la representación gráfica.
   SetIndexBuffer(0,chvBuffer);
   SetIndexBuffer(1,hlBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,shlBuffer,INDICATOR_CALCULATIONS);

Especificando la configuración de la representación gráfica:

   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,smoothPeriod+chvPeriod-1);
   PlotIndexSetString(0,PLOT_LABEL,"CHV("+string(smoothPeriod)+","+maName+")");
   IndicatorSetString(INDICATOR_SHORTNAME,"Chaikin Volatility("+string(smoothPeriod)+","+maName+")");
   IndicatorSetInteger(INDICATOR_DIGITS,1);

En la parte OnCalculate, vamos a declarar tres variables enteras como sigue:

   int    i,pos,posCHV;

Definir la variable posCHV para que sea igual al resultado de 2 - chvPeriod y smoothPeriod:

   posCHV=chvPeriod+smoothPeriod-2;

Para comprobar si rateTotal es menor que el valor de posCHV, necesitamos un valor de retorno de cero:

   if(rates_total<posCHV)
      return(0);

Define el valor de 'pos' después de comprobar si 'prev_calculated' es menor que 1, el valor de pos será cero o si la condición no es cierta, pos será el resultado de prev_calculated -1.

   if(prev_calculated<1)
      pos=0;
   else pos=prev_calculated-1;

Definición de hlBuffer[i]

   for(i=pos;i<rates_total && !IsStopped();i++)
     {
      hlBuffer[i]=High[i]-Low[i];
     }

Definición del buffer smoothedhl (shl):

   if(pos<smoothPeriod-1)
     {
      pos=smoothPeriod-1;
      for(i=0;i<pos;i++)
        {
         shlBuffer[i]=0.0;
        }
     }

Definición de MAs simples y exponenciales mediante las funciones SimpleMAOnBuffer y ExponentialMAOnBuffer:

   if(InpSmoothType==SMA)
     {
      SimpleMAOnBuffer(rates_total,prev_calculated,0,smoothPeriod,hlBuffer,shlBuffer);
     }
   else
      ExponentialMAOnBuffer(rates_total,prev_calculated,0,smoothPeriod,hlBuffer,shlBuffer);

Actualización de 'pos' tras comprobar si 'pos' es menor que 'posCHV':

   if(pos<posCHV)
     {
      pos=posCHV;
     }

Definición del buffer CHV:

   for(i=pos;i<rates_total && !IsStopped();i++)
     {
      if(shlBuffer[i-chvPeriod]!=0.0)
         chvBuffer[i]=100.0*(shlBuffer[i]-shlBuffer[i-chvPeriod])/shlBuffer[i-chvPeriod];
      else
         chvBuffer[i]=0.0;
     }

Devolviendo el valor de rates_total:

return(rates_total);

A continuación se muestra el código completo en un bloque:

//+------------------------------------------------------------------+
//|                                           Chaikin Volatility.mq5 |
//+------------------------------------------------------------------+
#include <MovingAverages.mqh>
#property description "Chaikin Volatility"
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_plots   1
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_color1  MediumBlue
#property indicator_width1  3
enum smoothMode
  {
   SMA=0,// Simple MA
   EMA=1 // Exponential MA
  };
input int          smoothPeriodInp=10;  // Smoothing Period
input int          chvPeriodInp=10;     // Chaikin Volatility Period
input smoothMode InpSmoothType=EMA;   // Smoothing Mode
double             chvBuffer[];
double             hlBuffer[];
double             shlBuffer[];
int                smoothPeriod,chvPeriod;
void OnInit()
  {
   string maName;
   if(InpSmoothType==SMA)
      maName="SMA";
   else
      maName="EMA";
   if(smoothPeriodInp<=0)
     {
      smoothPeriod=10;
      printf("Incorrect value for Smoothing Period input = %d. Default value = %d.",smoothPeriodInp,smoothPeriod);
     }
   else
      smoothPeriod=smoothPeriodInp;
   if(chvPeriodInp<=0)
     {
      chvPeriod=10;
      printf("Incorrect value for Chaikin Volatility Period input = %d. Default value = %d.",chvPeriodInp,chvPeriod);
     }
   else
      chvPeriod=chvPeriodInp;
   SetIndexBuffer(0,chvBuffer);
   SetIndexBuffer(1,hlBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,shlBuffer,INDICATOR_CALCULATIONS);
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,smoothPeriod+chvPeriod-1);
   PlotIndexSetString(0,PLOT_LABEL,"CHV("+string(smoothPeriod)+","+maName+")");
   IndicatorSetString(INDICATOR_SHORTNAME,"Chaikin Volatility("+string(smoothPeriod)+","+maName+")");
   IndicatorSetInteger(INDICATOR_DIGITS,1);
  }
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &Time[],
                const double &Open[],
                const double &High[],
                const double &Low[],
                const double &Close[],
                const long &TickVolume[],
                const long &Volume[],
                const int &Spread[])
  {
   int    i,pos,posCHV;
   posCHV=chvPeriod+smoothPeriod-2;
   if(rates_total<posCHV)
      return(0);
   if(prev_calculated<1)
      pos=0;
   else
      pos=prev_calculated-1;
   for(i=pos;i<rates_total && !IsStopped();i++)
     {
      hlBuffer[i]=High[i]-Low[i];
     }
   if(pos<smoothPeriod-1)
     {
      pos=smoothPeriod-1;
      for(i=0;i<pos;i++)
        {
         shlBuffer[i]=0.0;
        }
     }
   if(InpSmoothType==SMA)
     {
      SimpleMAOnBuffer(rates_total,prev_calculated,0,smoothPeriod,hlBuffer,shlBuffer);
     }
   else
      ExponentialMAOnBuffer(rates_total,prev_calculated,0,smoothPeriod,hlBuffer,shlBuffer);
   if(pos<posCHV)
     {
      pos=posCHV;
     }
   for(i=pos;i<rates_total && !IsStopped();i++)
     {
      if(shlBuffer[i-chvPeriod]!=0.0)
         chvBuffer[i]=100.0*(shlBuffer[i]-shlBuffer[i-chvPeriod])/shlBuffer[i-chvPeriod];
      else
         chvBuffer[i]=0.0;
     }
   return(rates_total);
  }

Después de compilar este código, podremos encontrar el mismo indicador que en el siguiente gráfico, si lo adjuntamos al gráfico:

CHVInda

Como podemos ver en el gráfico anterior, el indicador de la ventana inferior del gráfico se muestra como un histograma, oscilando o registrando valores por encima y por debajo de cero.


Estrategias de negociación de Chaikin Volatility

En esta parte, veremos cómo podemos utilizar el indicador Chaikin Volatility a nuestro favor y esto puede ser una parte de nuestro sistema de comercio para considerar la volatilidad cuando el comercio. Utilizaremos sólo el CHV y tomaremos decisiones de trading basadas en el valor del indicador, luego probaremos esto para ver si los resultados pueden ser rentables o no.

Utilizaremos otra estrategia y combinaremos otro indicador para filtrar las decisiones en base a la dirección de la media móvil como optimización de la estrategia para ver si es rentable o mejor que utilizar solo CHV o no en base a probar esta estrategia.

A continuación se exponen estas estrategias:

Cruce de CHV:

Esta estrategia puede generar señales de compra y venta y colocar órdenes automáticamente. Cuando el valor de CHV es superior a cero, el EA colocará una posición de compra. Si el valor de CHV es inferior a cero, el EA colocará una posición de venta.

Simplemente:

Valor CHV > 0 => Posición de compra.

Valor CHV < 0 => Posición de venta.

CHV y cruce MA:

La estrategia generará señales y colocará posiciones de compra y venta en función del cruce entre el valor CHV y el nivel cero, teniendo en cuenta la dirección de la media móvil. Si CHV está por encima de cero y la media móvil está por debajo del precio de cierre, se generará y colocará una posición de compra. Por otro lado, si CHV está por debajo de cero y la media móvil está por encima del precio de cierre, se generará y colocará una posición de venta.

Simplemente:

CHV > 0 y precio de cierre > MA => Posición de compra.

CHV < 0 y precio de cierre < MA => Posición de venta.


Sistema de negociación de Chaikin Volatility

En esta parte, crearemos un sistema de trading en MQL5 basado en las estrategias mencionadas y probaremos cada una de ellas para ver cómo podemos optimizar la estrategia para obtener mejores resultados. Primero, crearemos un EA simple para que sea la base de nuestros sistemas de trading de las dos estrategias y este EA mostrará los valores de CHV como un comentario en el gráfico. Los siguientes son los pasos para hacerlo:

Declarar las entradas del sistema de negociación basado en el indicador:

enum SmoothMethod
  {
   SMA=0,// Simple MA
   EMA=1 // Exponential MA
  };
input int          InpSmoothPeriod=10;  // Smoothing period
input int          InpCHVPeriod=10;     // Chaikin Volatility period
input SmoothMethod InpSmoothType=EMA;   // Smoothing method

Declara una variable entera para 'chv':

int chv;

En la parte OnInit() del EA, definiremos la variable 'chv' para que sea igual a la función iCustom para devolver el handle del indicador CHV. Los parámetros de iCustom son:

  • symbol: Para especificar el nombre del símbolo.
  • period: Para especificar el periodo, utilizaremos el PERIOD_CURRENT para que se aplique al periodo actual.
  • name: Para especificar el nombre del indicador.
  • Especificación de la lista de entradas (smoothPeriodInp,chvPeriodInp y smoothTypeInp)
chv = iCustom(_Symbol,PERIOD_CURRENT,"Custom_CHV",smoothPeriodInp,chvPeriodInp, smoothTypeInp);

En la parte OnDeinit(), imprimiremos el mensaje cuando se elimine el EA:

Print("EA is removed");

En la parte OnTick(), declarando el array 'chvInd':

double chvInd[];

Obtención de los datos especificados del buffer del indicador CHV mediante la palabra clave CopyBuffer. Sus parámetros son:

  • indicator_handle: Para especificar el indicador que es el 'chv'. 
  • buffer_num: Para especificar el número de búfer indicador que será 0.
  • start_pos: Para especificar la posición inicial que será 0.
  • count: Para especificar la cantidad a copiar que será de 3
  • buffer[]: Para especificar el array de destino a copiar que será 'chvInd'.
CopyBuffer(chv,0,0,3,chvInd);

Establecer la bandera AS_SERIES al array seleccionado utilizando la palabra clave ArraySetAsSeries y sus parámetros son:

  • array[]: Para especificar el array por referencia que será 'chvInd'. 
  • flag: Se establece como true lo que denota el orden inverso de indexación. 
ArraySetAsSeries(chvInd,true);

Declarar y definir 'chvVal' para devolver el valor actual del indicador:

double chvVal = NormalizeDouble(chvInd[0], 1);

Comentar el valor actual en el gráfico:

Comment("CHV value = ",chvVal);

Así, podemos ver el código completo en un bloque igual al siguiente:

//+------------------------------------------------------------------+
//|                                                       chvVal.mq5 |
//+------------------------------------------------------------------+
enum SmoothMethod
  {
   SMA=0,// Simple MA
   EMA=1 // Exponential MA
  };
input int          smoothPeriodInp=10;  // Smoothing period
input int          chvPeriodInp=10;     // Chaikin Volatility period
input SmoothMethod smoothTypeInp=EMA;   // Smoothing method
int chv;
int OnInit()
  {
   chv = iCustom(_Symbol,PERIOD_CURRENT,"Custom_CHV",smoothPeriodInp,chvPeriodInp, smoothTypeInp);
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("EA is removed");
  }
void OnTick()
  {
    double chvInd[];
    CopyBuffer(chv,0,0,3,chvInd);
    ArraySetAsSeries(chvInd,true);
    double chvVal = NormalizeDouble(chvInd[0], 1);
    Comment("CHV value = ",chvVal);
  }
//+------------------------------------------------------------------+

Después de compilar este código, podemos encontrar el valor del valor actual como se muestra en la siguiente imagen:

chvVal

Podemos asegurarnos de que el valor impreso en el gráfico es correcto insertando el indicador en el mismo gráfico para ver si hay diferencia entre los dos valores o no. Por lo tanto, el siguiente gráfico muestra esto para asegurarse de que todo es correcto antes de seguir adelante en la creación de nuestro sistema de comercio:

chvValSame

Como podemos ver, el valor impreso del CHV actual es el mismo que el valor del indicador adjunto. Ahora vamos a crear nuestro sistema de trading para la primera estrategia (Cruce CHV).

Cruce de CHV:

De acuerdo con la estrategia de la estrategia de cruce CHV, el siguiente es el código completo para ello:

//+------------------------------------------------------------------+
//|                                                 chvCrossover.mq5 |
//+------------------------------------------------------------------+
#include <trade/trade.mqh>
enum smoothMode
  {
   SMA=0,// Simple MA
   EMA=1 // Exponential MA
  };
input int          smoothPeriodInp=10;  // Smoothing period
input int          chvPeriodInp=10;     // Chaikin Volatility period
input smoothMode   smoothTypeInp=EMA;   // Smoothing Mode
input double       lotSize=1;
input double slPips = 300;
input double tpPips = 600;

int chv;
int barsTotal;
CTrade trade;
int OnInit()
  {
   barsTotal=iBars(_Symbol,PERIOD_CURRENT);
   chv = iCustom(_Symbol,PERIOD_CURRENT,"Custom_CHV",smoothPeriodInp,chvPeriodInp, smoothTypeInp, lotSize, slPips, tpPips);
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("EA is removed");
  }
void OnTick()
  {
   int bars=iBars(_Symbol,PERIOD_CURRENT);
   if(barsTotal < bars)
     {
      barsTotal=bars;
      double chvInd[];
      CopyBuffer(chv,0,0,3,chvInd);
      ArraySetAsSeries(chvInd,true);
      double chvVal = NormalizeDouble(chvInd[0], 1);
      double chvValPrev = NormalizeDouble(chvInd[1], 1);
      if(chvVal>0)
        {
         double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
         double slVal = ask - slPips*_Point;
         double tpVal = ask + tpPips*_Point;
         trade.Buy(lotSize,_Symbol,ask,slVal,tpVal);
        }
      if(chvVal<0)
        {
         double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
         double slVal = bid + slPips*_Point;
         double tpVal = bid - tpPips*_Point;
         trade.Sell(lotSize,_Symbol,bid,slVal,tpVal);
        }
     }
  }
//+------------------------------------------------------------------+

Las diferencias en este código son las siguientes:

Incluye el archivo 'trade' para las funciones de trading:

#include <trade/trade.mqh>

Declarar entradas para el lotSize, el slPips, y el tpPips para ser editable por el usuario.

input double      lotSize=1;
input double slPips = 300;
input double tpPips = 600;

Declaración de una variable entera de barsTotal que se utilizará como código para cada nueva barra,.

int barsTotal;

Declaración del objeto del comercio.

CTrade trade;

En la parte OnInit(), tendremos la definición de la variable barsTotal.

barsTotal=iBars(_Symbol,PERIOD_CURRENT);

Añadiendo las tres entradas de lotSize, slPips y tpPips a la palabra clave iCustom.

chv = iCustom(_Symbol,PERIOD_CURRENT,"Custom_CHV",smoothPeriodInp,chvPeriodInp, smoothTypeInp, lotSize, slPips, tpPips);

Declaración y definición de la variable entera 'bar'.

int bars=iBars(_Symbol,PERIOD_CURRENT);

Comprobando si el barsTotal es menor que bars entonces necesitamos que se ejecute lo siguiente:

Actualiza el valor de barsTotal para que sea igual al valor de bars.

barsTotal=bars;

Declaración de la matriz 'chvInd'.

double chvInd[];

Recuperación de los datos del buffer especificado del indicador CHV mediante la palabra clave CopyBuffer.

CopyBuffer(chv,0,0,3,chvInd);

Establezca el indicador AS_SERIES en la matriz seleccionada mediante la palabra clave ArraySetAsSeries, como se indica a continuación.

ArraySetAsSeries(chvInd,true);

Declaración y definición de chvVal para la devolución del valor actual y del valor anterior del actual del indicador.

      double chvVal = NormalizeDouble(chvInd[0], 1);
      double chvValPrev = NormalizeDouble(chvInd[1], 1);

Estableciendo la condición de la posición de compra, necesitamos que el EA coloque automáticamente una posición de compra cuando compruebe el valor CHV y encuentre que es mayor que cero.

      if(chvVal>0)
        {
         double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
         double slVal = ask - slPips*_Point;
         double tpVal = ask + tpPips*_Point;
         trade.Buy(lotSize,_Symbol,ask,slVal,tpVal);
        }

Estableciendo la condición de posición de venta, necesitamos que el EA coloque automáticamente una posición de venta cuando compruebe el valor CHV y encuentre que es menor que cero.

      if(chvVal<0)
        {
         double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
         double slVal = bid + slPips*_Point;
         double tpVal = bid - tpPips*_Point;
         trade.Sell(lotSize,_Symbol,bid,slVal,tpVal);
        }

Después de compilar este código, podemos ver que la colocación de la posición de compra puede ser la siguiente:

chvCrossover_buySignal

Encontramos que la posición de venta también se puede colocar de la misma manera que la siguiente:

chvCrossover_sellSignal

Como sabemos, no existe una buena estrategia sin pruebas y la obtención de resultados rentables. Nos enfocaremos en las siguientes medidas clave:

  • Net profit: Se calcula restando la pérdida bruta del beneficio bruto. El valor más alto es el mejor.
  • Balance DD relative: Es la pérdida máxima que experimenta la cuenta durante las operaciones. El más bajo es el mejor.
  • Profit factor: Es la relación entre el beneficio bruto y la pérdida bruta. El valor más alto es el mejor.
  • Expected Payoff: Es la ganancia o pérdida media de una operación. El valor más alto es el mejor.
  • Recovery factor: Mide lo bien que se recupera la estrategia probada tras las pérdidas. El valor más alto es el mejor.
  • Sharpe Ratio: Determina el riesgo y la estabilidad del sistema de negociación probado comparando la rentabilidad con la rentabilidad sin riesgo. El Ratio de Sharpe más alto es el mejor.

Por lo tanto, los siguientes gráficos corresponden a los resultados de las pruebas. Vamos a probarlo durante un año (1-1-2023 a 31-12-2023) en EURUSD y un marco de tiempo de 1 hora.

chvCrossover_result

chvCrossover_result2

chvCrossover_result1

Según los resultados de las pruebas, podemos encontrar los siguientes valores importantes para los números de prueba:

  • Net Profit: -35936.34 USD.
  • Balance DD relative: 48.12%.
  • Profit factor: 0.94.
  • Expected payoff: -6.03.
  • Recovery factor: -0.62.
  • Sharpe Ratio: -1.22.

Según los resultados anteriores, podemos ver que los resultados no son buenos ni rentables, por lo que necesitamos optimizarlos para mejorar y obtener mejores resultados. Lo siguiente es hacerlo a través de la estrategia.

CHV y cruce MA:

Según esta estrategia, utilizaremos el indicador CHV pero combinaremos otro indicador técnico, la media móvil, para filtrar las operaciones en función de la dirección de la media móvil. A continuación se muestra el código completo para hacer esto:

//+------------------------------------------------------------------+
//|                                             chv_MA_Crossover.mq5 |
//+------------------------------------------------------------------+
#include <trade/trade.mqh>
enum smoothMode
  {
   SMA=0,// Simple MA
   EMA=1 // Exponential MA
  };
input int          InpSmoothPeriod=10;  // Smoothing period
input int          InpCHVPeriod=10;     // Chaikin Volatility period
input smoothMode smoothTypeInp=EMA;   // Smoothing Mode
input int InpMAPeriod=10; //MA Period
input ENUM_MA_METHOD InpMAMode=MODE_EMA; // MA Mode
input double      lotSize=1;
input double slPips = 300;
input double tpPips = 600;
int chv;
int ma;
int barsTotal;
CTrade trade;
int OnInit()
  {
   barsTotal=iBars(_Symbol,PERIOD_CURRENT);
   chv = iCustom(_Symbol,PERIOD_CURRENT,"Custom_CHV",InpSmoothPeriod,InpCHVPeriod, smoothTypeInp, lotSize, slPips, tpPips);
   ma=iMA(_Symbol,PERIOD_CURRENT, InpMAPeriod, 0, InpMAMode, PRICE_CLOSE);
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("EA is removed");
  }
void OnTick()
  {
   int bars=iBars(_Symbol,PERIOD_CURRENT);
   if(barsTotal < bars)
     {
      barsTotal=bars;
      double chvInd[];
      double maInd[];
      CopyBuffer(chv,0,0,3,chvInd);
      ArraySetAsSeries(chvInd,true);
      CopyBuffer(ma,0,0,3,maInd);
      ArraySetAsSeries(maInd,true);
      double chvVal = NormalizeDouble(chvInd[0], 1);
      double chvValPrev = NormalizeDouble(chvInd[1], 1);
      double maVal = NormalizeDouble(maInd[0], 5);
      double maValPrev = NormalizeDouble(maInd[1], 5);
      double lastClose=iClose(_Symbol,PERIOD_CURRENT,1);
      double prevLastClose=iClose(_Symbol,PERIOD_CURRENT,2);

      if(prevLastClose<maValPrev && lastClose>maVal && chvVal>0)
        {
         double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
         double slVal = ask - slPips*_Point;
         double tpVal = ask + tpPips*_Point;
         trade.Buy(lotSize,_Symbol,ask,slVal,tpVal);
        }
      if(prevLastClose>maValPrev && lastClose<maVal && chvVal<0)
        {
         double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
         double slVal = bid + slPips*_Point;
         double tpVal = bid - tpPips*_Point;
         trade.Sell(lotSize,_Symbol,bid,slVal,tpVal);
        }
     }
  }
//+------------------------------------------------------------------+

Las diferencias en este código son las siguientes:

Declara una variable entera para la media móvil.

int ma;

En la parte OnInit(), definiremos la media móvil utilizando la palabra clave iMA para devolver el handle de la media móvil. Sus parámetros son:

  • symbol: Para especificar el nombre del símbolo, será _Symbol que se aplicará al actual. 
  • period: Para especificar el marco temporal, será PERIOD_CURRENT para aplicarse al marco temporal actual.
  • ma_period: Para especificar el periodo de la media móvil, será la entrada MAperiod.
  • ma_shift: Para especificar si necesitamos un desplazamiento horizontal para la línea de la MA.
  • ma_method: Para especificar el modo de suavizado (smoothing) de la media móvil, será la entrada del modo MA. 
  • applied_price: Para especificar el tipo de precio que se utilizará para el cálculo, utilizaremos el precio de cierre.
ma=iMA(_Symbol,PERIOD_CURRENT, InpMAPeriod, 0, InpMAMode, PRICE_CLOSE);

Añadir lo siguiente después de comprobar si hay una nueva barra:

Declaración de la matriz maInd[].

double maInd[];

Obtención de los datos del búfer especificado del indicador de media móvil mediante la palabra clave CopyBuffer y establecimiento de la bandera AS_SERIES en la matriz seleccionada mediante la palabra clave ArraySetAsSeries.

      CopyBuffer(ma,0,0,3,maInd);
      ArraySetAsSeries(maInd,true);

Definir los siguientes valores:

La media móvil actual, la media móvil anterior, el último cierre y el anterior del último cierre.

      double maVal = NormalizeDouble(maInd[0], 5);
      double maValPrev = NormalizeDouble(maInd[1], 5);
      double lastClose=iClose(_Symbol,PERIOD_CURRENT,1);
      double prevLastClose=iClose(_Symbol,PERIOD_CURRENT,2);

Estableciendo las condiciones de la posición de compra, si el anterior del último cierre es menor que el valor de la media móvil anterior y al mismo tiempo el último cierre es mayor que la media móvil actual y al mismo tiempo el valor Chaikin actual es mayor que cero, necesitamos que el EA coloque una posición de compra.

      if(prevLastClose<maValPrev && lastClose>maVal && chvVal>0)
        {
         double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
         double slVal = ask - slPips*_Point;
         double tpVal = ask + tpPips*_Point;
         trade.Buy(lotSize,_Symbol,ask,slVal,tpVal);
        }

Estableciendo las condiciones de la posición de venta, si el anterior del último cierre es mayor que el valor de la media móvil anterior y al mismo tiempo el último cierre es menor que la media móvil actual y al mismo tiempo el valor Chaikin actual es menor que cero, necesitamos que el EA coloque una posición de venta.

      if(prevLastClose>maValPrev && lastClose<maVal && chvVal<0)
        {
         double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
         double slVal = bid + slPips*_Point;
         double tpVal = bid - tpPips*_Point;
         trade.Sell(lotSize,_Symbol,bid,slVal,tpVal);
        }

Después de compilar este código, podemos ver que la colocación de la posición de compra puede ser la siguiente:

chvMACrossover_buySignal

Encontramos que la posición de venta también se puede colocar de la misma manera que la siguiente:

chvMACrossover_sellSignal

Después de una prueba de esta estrategia durante un año (1/1/2023 a 31/12/2023) en el EURUSD y un marco de tiempo de 1 hora, nuestros resultados son los siguientes.

chvMACrossover_result

chvMACrossover_result2

chvMACrossover_result1

Según los resultados de las pruebas, podemos encontrar los siguientes valores importantes para los números de prueba:

  • Net Profit: 20817.39 USD.
  • Balance DD relative: 9.62%.
  • Profit factor: 1.15.
  • Expected payoff: 29.28.
  • Recovery factor: 1.69.
  • Sharpe Ratio: 1.71.

Con base en los resultados de las pruebas anteriores y después de agregar otra herramienta técnica, que es la media móvil, podemos encontrar las mejores cifras que corresponden a la estrategia probada de CHV y cruce de MA en el marco de tiempo de 1 hora, tal como se muestra a continuación:

  • Net Profit: La cifra más alta (20817.39 USD).
  • Balance DD Relative: La cifra más baja (9.62%).
  • Profit Factor: La cifra más alta (1.15).
  • Expected Payoff: La cifra más alta (29.28).
  • Recovery Factor: La cifra más alta (1.69).
  • Sharpe Ratio: La cifra más alta (1.71).


Conclusión

Debemos entender la importancia del concepto de volatilidad en el mercado financiero aprendiendo sobre el indicador técnico Chaikin Volatility, el cual puede ser útil para interpretar o predecir posibles movimientos del mercado. Suponemos que entenderíamos cómo funciona el indicador CHV, cómo puede calcularse y cómo podemos utilizarlo a nuestro favor en los mercados de trading.

Suponemos que entendimos dos estrategias simples y cómo optimizar nuestra estrategia para obtener mejores resultados, acompañándola con otra herramienta técnica, como la media móvil. Hemos aprendido cómo crear nuestro propio indicador CHV utilizando MQL5 para poder agregar nuestras preferencias, y hemos aprendido cómo usar este indicador CHV personalizado en un sistema de trading basado en las estrategias mencionadas.

  • Cruce CHV
  • CHV y cruce MA

También aprendimos cómo crear un sistema de trading para operar y colocar posiciones automáticamente basado en las estrategias mencionadas mediante la creación de EAs, luego probándolos y viendo cómo podemos obtener mejores ideas y resultados al acompañarlos de otra herramienta técnica, como la media móvil, como parte de la optimización a través del Probador de estrategias.

Te animo a probar y testear otras herramientas posibles para obtener mejores perspectivas, ya que la mejora nunca termina y es una función infinita, no solo en el trading, sino también en nuestras vidas. Espero que hayas disfrutado leyendo este artículo y que lo hayas encontrado útil en tu trayectoria de trading. Si deseas leer más artículos sobre la construcción de sistemas de trading y comprender el concepto principal detrás de ellos, puedes leer mis anteriores artículos sobre estos temas y otros relacionados con la programación en MQL5.


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

Archivos adjuntos |
Custom_CHV.mq5 (3.24 KB)
chvVal.mq5 (0.97 KB)
chvCrossover.mq5 (1.8 KB)
Introducción a MQL5 (Parte 5): Funciones de trabajo con arrays para principiantes Introducción a MQL5 (Parte 5): Funciones de trabajo con arrays para principiantes
En el quinto artículo de nuestra serie, nos familiarizaremos con el mundo de los arrays en MQL5. Este artículo ha sido pensado para principiantes. En este artículo intentaremos repasar conceptos complejos de programación de manera simplificada para que el material resulte comprensible para todos. Asimismo, exploraremos conceptos básicos, discutiremos diferentes cuestiones y compartiremos conocimientos.
Desarrollo de un robot en Python y MQL5 (Parte 1): Preprocesamiento de datos Desarrollo de un robot en Python y MQL5 (Parte 1): Preprocesamiento de datos
Desarrollar un robot de trading basado en aprendizaje automático: Una guía detallada. El primer artículo de la serie trata de la recogida y preparación de datos y características. El proyecto se ejecuta utilizando el lenguaje de programación y las librerías Python, así como la plataforma MetaTrader 5.
El método de manejo de datos en grupo: implementación del algoritmo combinatorio en MQL5 El método de manejo de datos en grupo: implementación del algoritmo combinatorio en MQL5
En este artículo continuamos nuestra exploración de la familia de algoritmos del método de manejo de datos en grupo, con la implementación del algoritmo combinatorio junto con su encarnación refinada, el algoritmo combinatorio selectivo en MQL5.
Redes neuronales: así de sencillo (Parte 80): Modelo generativo y adversarial del Transformador de grafos (GTGAN) Redes neuronales: así de sencillo (Parte 80): Modelo generativo y adversarial del Transformador de grafos (GTGAN)
En este artículo, le presentamos el algoritmo GTGAN, introducido en enero de 2024 para resolver problemas complejos de disposición arquitectónica con restricciones gráficas.