
Creamos y optimizamos un sistema comercial basado en los volúmenes negociados (Chaikin Money Flow (CMF))
Introducción
Bienvenido a un nuevo artículo en el que exploramos nuevos indicadores atendiendo a su creación, la construcción de sistemas comerciales basados en su concepto y la optimización de estos sistemas para proporcionar mejor información y resultados en términos de beneficio y riesgo. En este artículo, presentaremos un nuevo indicador técnico basado en el volumen llamado Chaikin Money Flow (CMF).
Y aquí será mejor mencionar algo importante, el objetivo principal de este tipo de artículos es compartir nuevas herramientas técnicas que pueden ser utilizadas solas o en combinación con otras herramientas según la naturaleza de las mismas, además de probar estas, optimizarlas para obtener mejores resultados para ver si herramientas pueden ser útiles.
Desarrollaremos este nuevo indicador (CMF) según las siguientes secciones:
- Chaikin Money Flow: adquiera conocimientos básicos de esta herramienta técnica definiendo cómo puede calcularse y utilizarse.
- Indicador personalizado Chaikin Cash Flow: aprenda a programar nuestro indicador personalizado cambiando o aplicando sus preferencias.
- Estrategias de Chaikin Money Flow: veremos algunas estrategias sencillas que forman parte de nuestro sistema comercial.
- Sistema comercial de Chaikin Cash Flow: cree, pruebe y optimice estos sencillos sistemas comerciales.
- Conclusión
Descargo de responsabilidad: El contenido de este artículo se ofrece "tal cual", tiene fines exclusivamente educativos y no constituye una recomendación comercial. El artículo no garantiza ningún resultado en absoluto. Todo lo que ponga en práctica usando este artículo como base, lo hará bajo su propia cuenta y riesgo; el autor no garantiza resultado alguno.
Chaikin Money Flow
El Chaikin Money Flow (CMF) es un indicador técnico basado en el volumen que considera el movimiento del precio. Como veremos, puede usarse solo o en combinación con otras herramientas para obtener información más detallada. El CMF es un indicador desarrollado por Marc Chaikin para monitorear la acumulación y distribución de un instrumento a lo largo de un periodo de tiempo. La idea básica del CMF es que a medida que el precio de cierre se acerca al máximo, se produce la acumulación. En cambio, cuando el precio de cierre se acerca al mínimo, supone una señal de distribución. Un resultado positivo de Chaikin Money Flow se consigue cuando el movimiento del precio cierra consistentemente por encima del punto medio de la barra con un volumen creciente. Un resultado negativo de Chaikin Money Flow se consigue cuando el movimiento del precio cierra consistentemente por debajo del punto medio de la barra en un volumen creciente.
A continuación le mostramos los pasos para calcular el CMF:
- Cálculo del multiplicador de flujo de dinero
- Cálculo del volumen de flujo de dinero
Volumen de flujo de dinero = multiplicador de flujo de dinero * volumen del periodo
- Cálculo de CMF
El CMF del periodo n = suma del volumen de flujo de dinero del periodo n / suma del volumen del periodo n
Una vez calculado, el indicador mostrará un rango de +1 a -1, y se parecerá a la siguiente figura:
Como podemos ver el indicador puede suponer una línea que oscila alrededor de cero; los cambios en CMF y el impulso de compra o venta pueden ser identificados por cualquier cruce por encima o por debajo de 0. Los valores positivos por encima de cero indican la capacidad de compra; en cambio, el indicador caerá por debajo de cero si la capacidad de venta empieza a imponerse. Cuando el CMF fluctúa cerca de la línea cero, podemos indicar un poder de compra y venta relativamente igual o la ausencia de una tendencia obvia. El CMF se usa como herramienta para identificar y evaluar las tendencias del instrumento negociado.
En la siguiente sección podemos personalizar nuestro indicador como queramos, por ejemplo, dibujándolo como un histograma en lugar de una línea o cualquier otra cosa que creamos que nos ayudará a negociar mejor. En esto reside el sentido de personalizar cualquier indicador según nuestras preferencias escribiendo o editando su código.
Indicador personalizado Chaikin Money Flow
En esta sección, le mostraremos cómo crear un indicador CMF personalizado paso a paso para que pueda usarlo posteriormente en nuestro sencillo sistema comercial. Como veremos, nuestra personalización será sencilla, ya que el objetivo principal consiste en abrir los ojos del lector a los nuevos datos y conocimientos sobre el indicador y las estrategias que se pueden utilizar en función de este indicador de volumen.
A continuación le mostraremos los pasos que seguiremos para crear el código de este indicador personalizable:
Especificaremos los parámetros adicionales junto a #property para definir los valores siguientes para el comportamiento y el aspecto del indicador
- Descripción del indicador usando la constante de descripción y especificando "Chaikin Money Flow".
#property description "Chaikin Money Flow"
- Colocación de un indicador como ventana independiente en el gráfico mediante una constante (indicator_separate_window).
#property indicator_separate_window
- El número de búferes para calcular el indicador, usando la constante (indicator_buffers) , lo fijamos igual a 4.
#property indicator_buffers 4
- El número de filas del gráfico en el indicador, usando la constante (indicator_plots), lo fijaremos igual a 1.
#property indicator_plots 1
- El grosor de la línea en la fila gráfica utilizando la constante (indicator_width1), donde 1 es el número de la fila gráfica, lo fijaremos igual a 3.
#property indicator_width1 3
- Los niveles horizontales 1,2 y 3 en una ventana de indicadores independiente utilizando las constantes (nivel_indicador1), (nivel_indicador2 ) y (nivel_indicador3 ) para el nivel (0), (0,20) y (-0,20).
#property indicator_level1 0 #property indicator_level2 0.20 #property indicator_level3 -0.20
- El estilo de los niveles horizontales del indicador con (indicator_levelstyle), aquí fijaremos el valor STYLE_DOT
#property indicator_levelstyle STYLE_DOT
- El grosor de los niveles horizontales del indicador mediante (indicator_levelwidth), aquí fijaremos el valor 0
#property indicator_levelwidth 0
- El color de los niveles horizontales del indicador con (indicator_levelcolor), fijaremos el valor clrBlack
#property indicator_levelcolor clrBlack
- El tipo de construcción gráfica con (indicator_type1), fijaremos DRAW_HISTOGRAM
#property indicator_type1 DRAW_HISTOGRAM
- El color de visualización de la línea N se selecciona con (indicator_color1), aquí usaremos clrBlue
#property indicator_color1 clrBlue
- Especifica los datos de entrada para establecer las preferencias del usuario para los periodos y tipos de volumen que se utilizarán en el cálculo del indicador usando la función de entrada
input int periods=20; // Periods input ENUM_APPLIED_VOLUME volumeTypeInp=VOLUME_TICK; // Volume Type
- Declaración del array cmfBuffer
double cmfBuffer[];
En la función OnInit() para configurar el indicador,
Vincula un array dinámico unidimensional de tipo double a la memoria intermedia del indicador CMF usando (SetIndexBuffer), y sus parámetros son:
- index: para especificar el índice del búfer, que será igual a 0
- buffer[]: para especificar un array que será cmfBuffer
- tipo_datos: para especificar el tipo de datos almacenados en el array de indicadores.
SetIndexBuffer(0,cmfBuffer,INDICATOR_DATA);
Estableceremos el valor de la propiedad del indicador correspondiente utilizando la función (IndicatorSetInteger); sus parámetros son:
- prop_id: para definir el identificador que será (INDICATOR_DIGITS).
- prop_value: para definir el valor decimal a fijar, será igual a (5).
IndicatorSetInteger(INDICATOR_DIGITS,5);
Estableceremos cuándo se inicia el dibujado utilizando la función (PlotIndexSetInteger) con estos parámetros:
- plot_index: para especificar el índice del estilo de muestra del gráfico, que será igual a (0).
- prop_id: para especificar el identificador de la propiedad, que será (PLOT_DRAW_BEGIN) como una de las enumeraciones ENUM_PLOT_PROPERTY_INTEGER.
- prop_value: para especificar el valor a establecer como propiedad, será igual a (0).
PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,0);
Luego especificaremos el nombre y el periodo del indicador utilizando la función (IndicatorSetString) con estos parámetros:
- prop_id: para especificar un identificador que puede ser una de las enumeraciones ENUM_CUSTOMIND_PROPERTY_STRING, e indicar también (INDICATOR_SHORTNAME).
- prop_value: especifica el valor del texto del indicador, que tendrá el siguiente aspecto: ("Chaikin Money Flow("+string(periods)+")").
IndicatorSetString(INDICATOR_SHORTNAME,"Chaikin Money Flow("+string(periods)+")");
Sección OnCalculate para calcular el valor CMF
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 &tick_volume[], const long &volume[], const int &spread[])
Comprobaremos la disponibilidad de datos para calcular los valores CMF mediante la función if
if(rates_total<periods) return(0);
Cuando tengamos los datos y calculemos previamente el CM, no empezaremos a calcular el valor actual
int initPos = prev_calculated -1; if(initPos<0) initPos = 0;
Calcularemos el CMF realizando los siguientes pasos
- Seleccionaremos el tipo de volumen.
- Ciclo para calcular el valor CMF de cada barra.
- Declararemos sumAccDis, sumVol.
- Realizaremos un ciclo para calcular las variables declaradas (sumAccDis, sumVol) después de declarar y definir una variable (thisTickVolume).
- Guardaremos el resultado en cmfBuffer.
- Retornaremos los valores calculados.
if(volumeTypeInp==VOLUME_TICK) { for(int pos = initPos;pos<=rates_total-periods;pos++) { double sumAccDis = 0; long sumVol = 0; for(int i = 0; i < periods && !IsStopped(); ++i) { long thisTickVolume = tick_volume[pos+i]; sumVol += thisTickVolume; sumAccDis += AccDis(high[pos+i], low[pos+i], close[pos+i], thisTickVolume); } cmfBuffer[pos+periods-1] = sumAccDis/sumVol; } } else { for(int pos = initPos;pos<=rates_total-periods;pos++) { double sumAccDis = 0; long sumVol = 0; for(int i = 0; i < periods && !IsStopped(); ++i) { long thisTickVolume = volume[pos+i]; sumVol += thisTickVolume; sumAccDis += AccDis(high[pos+i], low[pos+i], close[pos+i], thisTickVolume); } cmfBuffer[pos+periods-1] = sumAccDis/sumVol; } } return (rates_total-periods-10);
Declararemos que la función (AccDis) que se ha utilizado en el código contiene 4 variables (high, low, close y volume) que nos ayudarán a calcular el multiplicador de flujo de dinero y el volumen de flujo de dinero para la barra que se utiliza para calcular el CMF.
double AccDis(double high,double low,double close,long volume) { double res=0; if(high!=low) res=(2*close-high-low)/(high-low)*volume; return(res); }
Ahora hemos finalizado nuestro código para crear un indicador CMF personalizado, podrá encontrar el código completo en un bloque a continuación:
#property description "Chaikin Money Flow" #property indicator_separate_window #property indicator_buffers 4 #property indicator_plots 1 #property indicator_width1 3 #property indicator_level1 0 #property indicator_level2 0.20 #property indicator_level3 -0.20 #property indicator_levelstyle STYLE_DOT #property indicator_levelwidth 0 #property indicator_levelcolor clrBlack #property indicator_type1 DRAW_HISTOGRAM #property indicator_color1 clrBlue input int periods=20; // Periods input ENUM_APPLIED_VOLUME volumeTypeInp=VOLUME_TICK; // Volume Type double cmfBuffer[]; void OnInit() { SetIndexBuffer(0,cmfBuffer,INDICATOR_DATA); IndicatorSetInteger(INDICATOR_DIGITS,5); PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,0); IndicatorSetString(INDICATOR_SHORTNAME,"Chaikin Money Flow("+string(periods)+")"); } 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 &tick_volume[], const long &volume[], const int &spread[]) { if(rates_total<periods) return(0); int initPos = prev_calculated -1; if(initPos<0) initPos = 0; if(volumeTypeInp==VOLUME_TICK) { for(int pos = initPos;pos<=rates_total-periods;pos++) { double sumAccDis = 0; long sumVol = 0; for(int i = 0; i < periods && !IsStopped(); ++i) { long thisTickVolume = tick_volume[pos+i]; sumVol += thisTickVolume; sumAccDis += AccDis(high[pos+i], low[pos+i], close[pos+i], thisTickVolume); } cmfBuffer[pos+periods-1] = sumAccDis/sumVol; } } else { for(int pos = initPos;pos<=rates_total-periods;pos++) { double sumAccDis = 0; long sumVol = 0; for(int i = 0; i < periods && !IsStopped(); ++i) { long thisTickVolume = volume[pos+i]; sumVol += thisTickVolume; sumAccDis += AccDis(high[pos+i], low[pos+i], close[pos+i], thisTickVolume); } cmfBuffer[pos+periods-1] = sumAccDis/sumVol; } } return (rates_total-periods-10); } double AccDis(double high,double low,double close,long volume) { double res=0; if(high!=low) res=(2*close-high-low)/(high-low)*volume; return(res); }
Tras armar este código y compilarlo, encontrará el archivo en su carpeta de indicadores. Después de añadirlo al gráfico, podrá verlo como se muestra en la imagen siguiente
Como podemos ver, este indicador se ve y actúa exactamente igual que en nuestro código personalizado. Podrá modificarlo para adaptarlo a sus necesidades, en función de lo que le sirva de ayuda en su sistema. En este punto, tendremos un indicador CMF personalizado que se puede utilizar en nuestro sistema comercial según nuestras estrategias simples, que discutiremos en la siguiente sección.
Estrategias del indicador de flujo de dinero de Chaikin
En esta sección, compartiremos algunas estrategias sencillas que se pueden utilizar con el indicador CMF. Estas estrategias se basan en diferentes conceptos y reglas que nos permiten realizar nuestras pruebas de forma cualitativa y metodológicamente sólida en términos de eficacia y optimización. Estas estrategias son sencillas en su concepto, pero podrá desarrollarlas según sus preferencias para probarlas y ver lo útiles que pueden ser.
Utilizaremos las tres estrategias sencillas siguientes:
- Estrategia de cruce de cero de CMF
- Estrategia de sobrecompra y sobreventa de CMF
- Estrategia de confirmación de la tendencia de CMF
Estrategia de cruce de cero de CMF:
Esta estrategia es bastante sencilla: usa el valor del indicador CMF para determinar cuándo comprar o vender. Si el valor CMF anterior es negativo y el valor actual o último es positivo, se tratará de una señal de compra. Lo contrario ocurrirá cuando el valor CMF anterior sea positivo y el valor actual o último sea negativo.
Así, tendremos lo siguiente:
Previous CMF < 0 and Current CMF > 0 --> Buy
Previous CMF > 0 and Current CMF < 0 --> Sell
Estrategia de sobrecompra y sobreventa de CMF:
Esta estrategia es un poco distinta a la anterior, pues observa otros niveles para determinar si se encuentra en zona de sobrecompra o sobreventa. Estas zonas pueden cambiar de vez en cuando o en distintos instrumentos; podrá comprobarlo observando visualmente el movimiento del indicador antes de tomar una decisión al respecto. Cuando el valor CMF sea inferior o igual a -0,20, dará una señal de compra, y viceversa. Cuando el valor de CMF sea superior o igual a 0,20, esto indicará una señal de venta.
Así, tendremos lo siguiente:
CMF <= -0.20 --> Buy
CMF >= 0.20 --> Sell
Estrategia de confirmación de la tendencia de CMF:
Esta estrategia tiene un enfoque distinto, ya que al recibir sus señales, combinaremos otro indicador que pueda confirmar una tendencia o al menos un movimiento del precio hacia arriba o hacia abajo, con la recepción de una señal del cruce del cero. Combinaremos el uso de la media móvil con el indicador CMF. Si el precio de cierre anterior está por debajo del valor de la media móvil anterior y, al mismo tiempo, el precio Ask actual está por encima de la media móvil y el valor de CMF actual es superior a cero, se activará una señal de compra, y viceversa. Si el precio de cierre anterior está por encima del valor de la media móvil anterior y, al mismo tiempo, el precio Bid actual está por debajo de la media móvil y el valor de CMF actual es inferior a cero, se activará una señal de venta.
Así, tendremos lo siguiente:
prevClose < prevMA, ask > MA, and CMF > 0 --> Buy
prevClose > prevMA, bid < MA, and CMF < 0 --> Sell
Vamos a probar y optimizar cada una de estas estrategias, ensayando diferentes conceptos para lograr los mejores resultados posibles. Veremos qué ocurre en la siguiente sección.
Sistema comercial de flujo de dinero de Chaikin
En esta sección, le mostraremos cómo desarrollar cada estrategia paso a paso. A continuación, las pondremos a prueba y le mostraremos cómo puede optimizarlas para obtener mejores resultados. Así que permanezca atento a esta parte del artículo: merece la pena. Antes de pasar a la programación de estrategias, ejecutaremos un pequeño asesor experto que nos mostrará los valores de CMF mostrados en el gráfico. Esta será nuestra plantilla básica para todos los asesores expertos. Esto también garantizará que utilicemos un indicador preciso con valores precisos en nuestros asesores expertos para cada estrategia.
Esto es lo que haremos a continuación con este sencillo asesor:
Estableceremos los parámetros de entrada del asesor experto para configurar los periodos y el tipo de volumen deseados, que se utilizarán en la función de llamada al indicador
input int periods=20; // Periods input ENUM_APPLIED_VOLUME volumeTypeInp=VOLUME_TICK; // Volume Type
Declaración de una variable entera para cmf
int cmf;
En el evento OnInit(), inicializaremos nuestro indicador CMF personalizado llamándolo mediante la función iCustom con los siguientes parámetros:
- Symbol: Aquí introduciremos el nombre del símbolo en forma de línea. Será el (_Symbol) aplicado al símbolo actual.
- Period: Aquí introduciremos el periodo en forma de ENUM_TIMEFRAMES. Este será el PERIOD_CURRENT con el que se aplicará el marco temporal actual.
- Name: Aquí introduciremos el nombre del indicador personalizado que estamos llamando con la ruta correcta en su computadora local, por lo que deberemos introducir folder/custom_indicator_name. Eso sería "Chaikin_Money_Flow".
- ...: Aquí introduciremos la lista de parámetros de entrada del indicador, si existe. Estos serían los periodos y los datos de entrada volumeTypeInp.
A continuación, utilizaremos el valor de retorno (INIT_SUCCEED) cuando la inicialización se realice correctamente para pasar a la siguiente parte del código.
int OnInit() { cmf = iCustom(_Symbol,PERIOD_CURRENT,"Chaikin_Money_Flow",periods,volumeTypeInp); return(INIT_SUCCEEDED); }
En el evento OnDeinit(), especificaremos que el mensaje del asesor experto se eliminará cuando se produzca un evento de desinicialización.
void OnDeinit(const int reason) { Print("EA is removed"); }
En el evento OnTick(), declararemos el array para cmfInd[] como un tipo de dato double
double cmfInd[];
Obtendremos los datos del búfer indicador cmf especificado utilizando la función CopyBuffer. Parámetros:
- indicator_handle: para especificar el manejador double (cmf) declarado anteriormente.
- buffer_num: para especificar el número de búfer cmf (0).
- start_pos: para especificar la posición inicial (0).
- count: para especificar el número a copiar (3).
- buffer[]: para especificar el array cmfInd[] a copiar.
CopyBuffer(cmf,0,0,3,cmfInd);
luego estableceremos la bandera AS_SERIES en cmfInd[] para indexar el elemento en la serie temporal. Podemos utilizar como parámetros array[] y una bandera que será verdadera en caso de éxito.
ArraySetAsSeries(cmfInd,true);
Luego definiremos una variable doble para el valor de CMF actual y la normalizaremos con una restricción de 5 decimales; usted podrá definirla.
double cmfVal = NormalizeDouble(cmfInd[0], 5);
Comentaremos en el gráfico el valor cmf actual, determinado previamente utilizando la función de comentario.
Comment("CMF value = ",cmfVal);
A continuación le mostraremos el código completo en un bloque.
//+------------------------------------------------------------------+ //| CMF_Val.mq5 | //+------------------------------------------------------------------+ input int periods=20; // Periods input ENUM_APPLIED_VOLUME volumeTypeInp=VOLUME_TICK; // Volume Type int cmf; int OnInit() { cmf = iCustom(_Symbol,PERIOD_CURRENT,"Chaikin_Money_Flow",periods,volumeTypeInp); return(INIT_SUCCEEDED); } void OnDeinit(const int reason) { Print("EA is removed"); } void OnTick() { double cmfInd[]; CopyBuffer(cmf,0,0,3,cmfInd); ArraySetAsSeries(cmfInd,true); double cmfVal = NormalizeDouble(cmfInd[0], 5); Comment("CMF value = ",cmfVal); }
Después de compilar este código e insertarlo en el gráfico como un asesor experto, podremos obtener el mismo resultado que a continuación:
Como podemos ver, el valor de CMF en el gráfico es el mismo que en el indicador insertado (0,15904). Podremos utilizarlo como punto de partida para otros asesores y estrategias.
Estrategia de cruce de cero de CMF:
Como hemos dicho, necesitaremos programar una estrategia de cruce del cero para que las transacciones se generen automáticamente en función de este cruce. El programa debe comprobar continuamente cada nueva barra. Cuando se da un cruce por encima de cero, necesitaremos esto para colocar una orden de compra. Cuando el cruce se produce por debajo de cero, necesitaremos que el asesor experto coloque una orden de venta.Aquí está el código completo que realizará el trabajo:
//+------------------------------------------------------------------+ //| CMF_Zero_Crossover.mq5 | //+------------------------------------------------------------------+ #include <trade/trade.mqh> input int periods=20; // Periods input ENUM_APPLIED_VOLUME volumeTypeInp=VOLUME_TICK; // Volume Type input double cmfPosLvls = 0.20; // CMF OB Level input double cmfNegLvls = -0.20; // CMF OS Level input int maPeriodInp=20; //MA Period input double lotSize=1; input double slLvl=300; input double tpLvl=900; int cmf; CTrade trade; int barsTotal; int OnInit() { barsTotal=iBars(_Symbol,PERIOD_CURRENT); cmf = iCustom(_Symbol,PERIOD_CURRENT,"Chaikin_Money_Flow",maPeriodInp,volumeTypeInp); 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 cmfInd[]; CopyBuffer(cmf,0,0,3,cmfInd); ArraySetAsSeries(cmfInd,true); double cmfVal = NormalizeDouble(cmfInd[0], 5); double cmfPreVal = NormalizeDouble(cmfInd[1], 5); double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK); double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID); if(cmfPreVal<0 && cmfVal>0) { double slVal=ask - slLvl*_Point; double tpVal=ask + tpLvl*_Point; trade.Buy(lotSize,_Symbol,ask,slVal,tpVal); } if(cmfPreVal>0 && cmfVal<0) { double slVal=bid + slLvl*_Point; double tpVal=bid - tpLvl*_Point; trade.Sell(lotSize,_Symbol,bid,slVal,tpVal); } } } //+------------------------------------------------------------------+
Para que lo sepa, hay diferencias en este código:
Hemos incluido un archivo comercial para llamar funciones comerciales
#include <trade/trade.mqh>
Asimismo, añadiremos los datos de entrada adicionales definidos por el usuario, cmfPosLvls para nivel de sobreventa, cmfNegLvls para nivel de sobrecompra, el tamaño de lote, el stop-loss y el take profit.
input double cmfPosLvls = 0.20; // CMF OB Level input double cmfNegLvls = -0.20; // CMF OS Level input double lotSize=1; input double slLvl=300; input double tpLvl=900;
Declaración de objetos comerciales, variable entera barsTotal
CTrade trade;
int barsTotal;
En el evento OnTick(), solo tendremos que comprobar si hay una nueva barra para mantener el código en ejecución. Podremos hacerlo utilizando una cláusula if después de haber definido la variable entera bars.
int bars=iBars(_Symbol,PERIOD_CURRENT); if(barsTotal != bars)
Si hay una nueva barra, tendremos que ejecutar el código restante con las siguientes diferencias:
Actualizamos el valor de barsTotal para que sea igual al valor de bars
barsTotal=bars;
Declaración del valor cmf anterior
double cmfPreVal = NormalizeDouble(cmfInd[1], 5);
Declaración de las variables dobles ask y bid
double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK); double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
Establecemos la condición de compra, si (cmfPreVal<0 y cmfVal>0), necesitaremos declarar SL, TP y colocar una orden de compra
if(cmfPreVal<0 && cmfVal>0) { double slVal=ask - slLvl*_Point; double tpVal=ask + tpLvl*_Point; trade.Buy(lotSize,_Symbol,ask,slVal,tpVal); }
Establecemos la condición de venta, si (cmfPreVal>0 y cmfVal<0), necesitaremos declarar SL, TP y colocar una orden de venta
if(cmfPreVal>0 && cmfVal<0) { double slVal=bid + slLvl*_Point; double tpVal=bid - tpLvl*_Point; trade.Sell(lotSize,_Symbol,bid,slVal,tpVal); }
Una vez juntamos este código y lo ejecutamos adjuntándolo al gráfico, podemos ver que las posiciones se ubican igual que en el ejemplo de abajo, que es de la fase de pruebas.
Posición de compra:
Posición de venta:
Ahora probaremos todas las estrategias EURUSD durante un año, desde el 1.01.2023 hasta el 31.12.2023. Utilizaremos 300 puntos para el SL y 900 para el TP. Nuestro principal enfoque de la optimización consistirá en probar otro concepto o añadir otra herramienta, como una media móvil. También podemos probar otros marcos temporales para ver cuál funciona mejor. También merece la pena probar este tipo de optimización.
En cuanto a los resultados de las pruebas de la estrategia de comparación entre ellas, evaluaremos los indicadores clave:
- Beneficio neto (Net Profit): se calcula restando la pérdida bruta del beneficio bruto. Cuanto mayor sea el valor, mejor.
- Balance DD relativo (Balance DD relative): la pérdida máxima en la cuenta durante la negociación. Cuanto menor sea el valor, mejor.
- Ratio de rentabilidad: Es la relación entre el beneficio bruto y la pérdida bruta. Cuanto mayor sea el valor, mejor.
- Esperanza de beneficio: Es el beneficio o la pérdida media de una operación. Cuanto mayor sea el valor, mejor.
- Factor de recuperación (Recovery Factor): es la capacidad de una estrategia probada para recuperarse de las pérdidas. Cuanto mayor sea el valor, mejor.
- Ratio de Sharpe: Determina el riesgo y la estabilidad del sistema comercial probado comparando la rentabilidad con la rentabilidad sin riesgo. Cuanto mayor sea el valor del ratio, mejor.
Los resultados de la prueba con el marco temporal de 15 minutos serán iguales a los mostrados a continuación:
Partiendo de los resultados de las pruebas de 15 minutos, podemos determinar los siguientes valores importantes para los números de prueba:
- Beneficio neto: 29019,10 USD.
- Reducción relativa del balance del 23%.
- Ratio de rentabilidad: 1.09.
- Esperanza de beneficio: 19.21.
- Factor de recuperación: 0.88.
- Ratio de Sharpe: 0.80.
Parece que la estrategia puede ser rentable en el marco temporal de 15 minutos, pero la reducción es alta, lo que puede aumentar el riesgo. Por lo tanto, probaremos otra estrategia con un concepto diferente: la sobrecompra y la sobreventa de CMF.
Estrategia de sobrecompra y sobreventa de CMF:
Como ya hemos dicho, necesitaremos programar esta estrategia para que el asesor experto coloque automáticamente órdenes de compra y venta basándose en la aproximación a las zonas de sobrecompra y sobreventa. Las zonas en las que nos fijaremos son 0,20 para sobrecompra y -0,20 para sobreventa. Por ello, necesitaremos que el asesor experto controle cada valor de CMF y lo compare con estas áreas. Si el CMF es igual o inferior a -0,20, el asesor experto deberá colocar una orden de compra. Si el valor de CMF es igual o superior a 0,20, el asesor experto deberá colocar una orden de venta.
Podrá leer los pasos para crear esta estrategia o asesor experto en el siguiente código completo:
//+------------------------------------------------------------------+ //| CMF_MA_OB&OS.mq5 | //+------------------------------------------------------------------+ #include <trade/trade.mqh> input int periods=20; // Periods input ENUM_APPLIED_VOLUME volumeTypeInp=VOLUME_TICK; // Volume Type input double cmfPosLvls = 0.20; // CMF OB Level input double cmfNegLvls = -0.20; // CMF OS Level input double lotSize=1; input double slLvl=300; input double tpLvl=900; int cmf; CTrade trade; int barsTotal; int OnInit() { barsTotal=iBars(_Symbol,PERIOD_CURRENT); cmf = iCustom(_Symbol,PERIOD_CURRENT,"Chaikin_Money_Flow",periods,volumeTypeInp); 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 cmfInd[]; CopyBuffer(cmf,0,0,3,cmfInd); ArraySetAsSeries(cmfInd,true); double cmfVal = NormalizeDouble(cmfInd[0], 5); double cmfPreVal = NormalizeDouble(cmfInd[1], 5); double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK); double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID); if(cmfVal<=cmfNegLvls) { double slVal=ask - slLvl*_Point; double tpVal=ask + tpLvl*_Point; trade.Buy(lotSize,_Symbol,ask,slVal,tpVal); } if(cmfVal>=cmfPosLvls) { double slVal=bid + slLvl*_Point; double tpVal=bid - tpLvl*_Point; trade.Sell(lotSize,_Symbol,bid,slVal,tpVal); } } } //+------------------------------------------------------------------+
Las diferencias en este código serán las mismas que se muestran a continuación:
Estableceremos dos parámetros para las zonas de sobrecompra y sobreventa, según lo que desee el usuario. Por ahora, utilizaremos los valores por defecto (0,20 y -0,20).
input double cmfPosLvls = 0.20; // CMF OB Level input double cmfNegLvls = -0.20; // CMF OS Level
Condiciones de la estrategia
Abriremos una posición de compra cuando el valor de CMF sea menor o igual al valor cmfNegLvls.
if(cmfVal<=cmfNegLvls) { double slVal=ask - slLvl*_Point; double tpVal=ask + tpLvl*_Point; trade.Buy(lotSize,_Symbol,ask,slVal,tpVal); }
Abriremos una posición de venta cuando el valor de CMF sea mayor o igual al valor cmfPosLvls
if(cmfVal>=cmfPosLvls) { double slVal=bid + slLvl*_Point; double tpVal=bid - tpLvl*_Point; trade.Sell(lotSize,_Symbol,bid,slVal,tpVal); }
Una vez reunido este código y ejecutado en un gráfico, podremos ver dónde coinciden las posiciones con las condiciones de la estrategia, al igual que en los ejemplos de la fase de pruebas.
Posición de compra:
Posición de venta:
Probaremos esta estrategia utilizando el mismo enfoque que usamos para probar anteriormente la estrategia de cruce del cero de CMF. Pondremos a prueba EURUSD desde el 01.01.2023 hasta el 31.12.2023 en el marco temporal de 15 minutos con 300 pips para SL y 900 para TP. Las siguientes figuras muestran los resultados de estas pruebas:
Partiendo de los resultados de las pruebas de 15 minutos, podemos determinar los siguientes valores importantes para los números de prueba:
- Beneficio neto: 58029,90 USD.
- Reducción relativa del balance: 55.60%.
- Ratio de rentabilidad: 1.06.
- Esperanza de beneficio: 14.15.
- Factor de recuperación: 0.62.
- Ratio de Sharpe: 0.69.
Ahora que vemos más beneficios con una mayor reducción, intentaremos optimizarla añadiendo o combinando otro indicador técnico con un CMF de cruce del cero para comprobar la tendencia. Veamos qué ocurre en la próxima estrategia.
Estrategia de confirmación de la tendencia de CMF:
Como decíamos, necesitaremos añadir o combinar otro indicador técnico, la media móvil, con el cruce del cero de CMF para confirmar el movimiento en ambas direcciones (alcista y bajista). El asesor deberá comprobar cada precio de cierre, ask y CMF. Este valor se utilizará para determinar la posición de cada uno con respecto a los demás. Cuando el último precio de cierre está por debajo del último valor de la media móvil, el precio de venta actual está por encima de la media móvil actual, mientras que el valor CMF es superior a cero, deberemos colocar una orden de compra. Por otro lado, cuando el último precio de cierre está por encima del último valor de la media móvil, el precio Bid actual está por debajo de la media móvil actual y el valor de CMF es inferior a cero, deberemos colocar una orden de venta.
A continuación, podremos ver el código completo de este asesor:
//+------------------------------------------------------------------+ //| CMF_trendValidation.mq5 | //+------------------------------------------------------------------+ #include <trade/trade.mqh> input int periods=20; // Periods input ENUM_APPLIED_VOLUME volumeTypeInp=VOLUME_TICK; // Volume Type input int maPeriodInp=20; //MA Period input double lotSize=1; input double slLvl=300; input double tpLvl=900; int cmf; int ma; CTrade trade; int barsTotal; int OnInit() { barsTotal=iBars(_Symbol,PERIOD_CURRENT); cmf = iCustom(_Symbol,PERIOD_CURRENT,"Chaikin_Money_Flow",periods,volumeTypeInp); ma = iMA(_Symbol,PERIOD_CURRENT,maPeriodInp,0,MODE_SMA,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 cmfInd[]; double maInd[]; CopyBuffer(cmf,0,0,3,cmfInd); CopyBuffer(ma,0,0,3,maInd); ArraySetAsSeries(cmfInd,true); ArraySetAsSeries(maInd,true); double cmfVal = NormalizeDouble(cmfInd[0], 5); double maVal= NormalizeDouble(maInd[0],5); double cmfPreVal = NormalizeDouble(cmfInd[1], 5); double maPreVal = NormalizeDouble(maInd[1],5);; double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK); double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID); double prevClose = iClose(_Symbol,PERIOD_CURRENT,1); if(prevClose<maPreVal && ask>maVal) { if(cmfVal>0) { double slVal=ask - slLvl*_Point; double tpVal=ask + tpLvl*_Point; trade.Buy(lotSize,_Symbol,ask,slVal,tpVal); } } if(prevClose>maPreVal && bid<maVal) { if(cmfVal<0) { double slVal=bid + slLvl*_Point; double tpVal=bid - tpLvl*_Point; trade.Sell(lotSize,_Symbol,bid,slVal,tpVal); } } } } //+------------------------------------------------------------------+
Las principales diferencias de este código son las siguientes:
Vamos a añadir otra entrada que permita al usuario definir el periodo de la media móvil a utilizar
input int maPeriodInp=20; //MA Period
Declaración de una variable entera para una media móvil
int ma;
Definiremos la variable creada por la media móvil utilizando la función iMA, sus parámetros son:
- symbol: para especificar un nombre de símbolo, usaremos (_Symbol) y se aplicará sobre el símbolo actual.
- period: establece el periodo de la media móvil que se aplicará (PERIOD_CURRENT) en el marco temporal actual.
- ma_period: establece el periodo de promediación, el usuario deberá introducir un valor (maPeriodInp).
- ma_shift: establece el desplazamiento horizontal si es necesario.
- ma_method: establece el tipo de suavizado o media móvil, será (MODE_SMA) para utilizar una media móvil simple.
- applied_price: especifica el tipo de precio, este será (PRECIO_CIERRE).
ma = iMA(_Symbol,PERIOD_CURRENT,maPeriodInp,0,MODE_SMA,PRICE_CLOSE);
Declaramos el array maInd[]
double maInd[];
Luego obtendremos los datos del búfer del indicador MA especificado utilizando la función CopyBuffer.
CopyBuffer(ma,0,0,3,maInd);
Estableceremos la bandera AS_SERIES en maInd[] para indexar el elemento en la serie temporal.
ArraySetAsSeries(maInd,true);
Determinaremos el valor actual y anterior de la media móvil
double maVal= NormalizeDouble(maInd[0],5); double prevClose = iClose(_Symbol,PERIOD_CURRENT,1);
Condiciones de posición de compra, prevClose<maPreVal, ask>maVal, y cmfVal>0
if(prevClose<maPreVal && ask>maVal) { if(cmfVal>0) { double slVal=ask - slLvl*_Point; double tpVal=ask + tpLvl*_Point; trade.Buy(lotSize,_Symbol,ask,slVal,tpVal); } }
Condiciones de posición de venta, prevClose>maPreVal, bid<maVal, y cmfVal<0
if(prevClose>maPreVal && bid<maVal) { if(cmfVal<0) { double slVal=bid + slLvl*_Point; double tpVal=bid - tpLvl*_Point; trade.Sell(lotSize,_Symbol,bid,slVal,tpVal); } }
Después de ejecutar este asesor experto, podremos encontrar la orden colocada como se muestra en las imágenes de abajo:
Posición de compra:
Posición de venta:
Probaremos esta estrategia utilizando el mismo enfoque que en las pruebas anteriores para el CMF de cruce del cero y las estrategias OB y OS. Vamos a probar EURUSD desde el 01.01.2023 hasta el 31.12.2023 en el marco temporal de 15 minutos con 300 pips para SL y 900 para TP. Las siguientes figuras muestran los resultados de estas pruebas:
Partiendo de los resultados de las pruebas de 15 minutos, podemos determinar los siguientes valores importantes para los números de prueba:
- Beneficio neto: 40723,80 USD.
- Reducción relativa del balance: 6.30%.
- Ratio de rentabilidad: 1.91.
- Esperanza de beneficio: 167.59.
- Factor de recuperación: 3.59.
- Ratio de Sharpe: 3.90.
Observando los resultados de cada estrategia, está claro que la comprobación de tendencia de CMF es la mejor en cuanto a las métricas clave.
Conclusión
Como hemos visto a lo largo de este artículo, el volumen es un concepto muy importante en el trading, especialmente cuando se combina con otras herramientas importantes; además hemos aprendido que la optimización es una tarea muy importante a la hora de probar cualquier estrategia ya que puede verse afectada por pequeños cambios. Le sugiero que realice sus pruebas cambiando diferentes aspectos como los marcos temporales, el SL y el TP, añadiendo además otras herramientas hasta que obtenga resultados razonables.
Asumiremos que usted entiende cómo utilizar el Indicador de volumen de flujo de dinero Chaikin, cómo configurarlo y codificarlo, y cómo crear, optimizar y probar asesores expertos basados en diferentes estrategias simples:
- Estrategia de cruce del cero de CMF.
- Estrategia CMF OB y OS.
- Estrategia de confirmación de la tendencia de CMF.
Además, usted ha visto cuál es la mejor según los resultados de la optimización y las pruebas. Espero que este artículo le haya resultado útil: si desea leer más artículos míos, por ejemplo, sobre la creación de sistemas comerciales basados en los indicadores técnicos más populares y otros, puede solicitarlos en mi página de publicaciones .
Asimismo, encontrará mis archivos adjuntos de código fuente como el que se muestra a continuación:
Nombre del archivo | características |
---|---|
Chaikin_Money_Flow | Indicador CMF personalizado que hemos creado |
CMF_Zero_Crossover | Indicador CMF con la estrategia comercial de cruce del cero |
CMF_OBOS | Indicador CMF con la estrategia comercial de sobrecompra y sobreventa |
CMF_trendValidation | Indicador CMF con la estrategia comercial de comprobación del movimiento / tendencia |
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/16469
Advertencia: todos los derechos de estos materiales pertenecen a MetaQuotes Ltd. Queda totalmente prohibido el copiado total o parcial.
Este artículo ha sido escrito por un usuario del sitio web y refleja su punto de vista personal. MetaQuotes Ltd. no se responsabiliza de la exactitud de la información ofrecida, ni de las posibles consecuencias del uso de las soluciones, estrategias o recomendaciones descritas.








- 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