Cómo construir y optimizar un sistema de trading basado en la volatilidad (Chaikin Volatility - CHV)
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:
- Chaikin Volatility: Para comprender los conocimientos más importantes sobre esta herramienta técnica.
- Indicador Chaikin Volatility personalizado: Para aprender cómo podemos codificar nuestro indicador personalizado para cambiar o aplicar nuestras preferencias con respecto al indicador.
- Estrategias de negociación de Chaikin Volatility: Para identificar estrategias de negociación sencillas que utilizaremos en nuestro sistema de negociación.
- Sistema de negociación de Chaikin Volatility: Construir y probar un sistema de negociación sencillo que se utilizará como parte de nuestro sistema de negociación.
- Conclusión
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.
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:
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:
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:
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:
Encontramos que la posición de venta también se puede colocar de la misma manera que la siguiente:
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.
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:
Encontramos que la posición de venta también se puede colocar de la misma manera que la siguiente:
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.
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
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso