Indicadores con control interactivo en el gráfico.

Aleksandr Kononov | 19 julio, 2022

Introducción

La experiencia como tráder desde 2008 y los amplios conocimientos acumulados ahora me permiten usar dicho bagaje para desarrollar mis propios productos. Tras probar docenas de estrategias comerciales diferentes a lo largo de los años, además de probar cientos de indicadores diferentes, he llegado a algunas conclusiones propias que quiero compartir con ustedes en este artículo. Ahora, como antes, la calidad de las plataformas comerciales de MetaTrader está fuera de toda duda. No obstante, el progreso nunca se detiene y, en las condiciones modernas, los usuarios son cada vez más exigentes con los productos ofrecidos. Por consiguiente, para aumentar la comodidad de los tráders, pensé que sería bueno crear un principio que se pueda aplicar fácilmente a cualquier indicador, y que consista en una interacción más operativa entre el usuario y el programa. 


Sobre los indicadores

Existen varios tipos de software comercial disponibles en las plataformas MetaTrader. Hay asesores comerciales, scripts e indicadores. Quiero hablar de los indicadores.

Los indicadores tienen tipos diferentes: líneas de apoyo y resistencia, fractales o figuras de velas japonesas, volúmenes u otros datos sobre operaciones comerciales en la bolsa de valores, osciladores o histogramas. Todos ellos son necesarios para mostrar un cierto patrón de movimiento de precios que, a su vez, forma una señal para realizar una transacción. Y cuanto más a menudo ocurra el patrón, más fuerte será la señal. 

Un patrón es un movimiento de precios que se repite o resulta muy similar al darse ciertas lecturas del indicador. Por ejemplo, si la media móvil rápida cruza la media móvil lenta de abajo hacia arriba y el precio la cruza de arriba hacia abajo, entonces será más probable que el precio rebote desde esta línea y continúe subiendo. Podemos encontrar dichos patrones usando cualquier indicador. 

Sin embargo, cada indicador, independientemente de su propósito, muestra patrones durante un cierto periodo de tiempo. Es decir, la señal se forma usando como base los movimientos de precio transmitidos en algún segmento de los datos históricos. Pueden ser 10 barras de hora o 1000 barras de día. Este intervalo temporal en el que buscamos un patrón, se denomina "periodo" del indicador.

Cualquier indicador tiene un periodo de cálculo, ya que todos los indicadores se calculan sobre los datos históricos. Si establecemos el valor del periodo en 100 y colocamos el indicador en el gráfico H1, obtendremos el resultado del cálculo del indicador para las últimas 100 velas de hora. El periodo permanecerá invariable durante todo el funcionamiento del indicador, hasta que lo modifiquemos nosotros mismos. Si la naturaleza del movimiento del precio varía, por ejemplo, el movimiento se vuelve más volátil, tendremos que aumentar el periodo para que el indicador se corresponda con la situación actual del mercado. 

Para hacer esto, deberemos ir a la configuración del indicador y seleccionar un nuevo valor para el periodo. Además, deberemos cambiar este parámetro paso a paso. El paso deberá seleccionarse de forma intuitiva: no deberá resultar demasiado grande para no perder la señal deseada, pero tampoco demasiado pequeño, para no perder demasiado tiempo en él. Y si lo hacemos a menudo durante el día, entonces podremos dedicarle una cantidad significativa de tiempo. Por lo tanto, trabajar con indicadores es una especie de compromiso entre el resultado deseado, su precisión y el tiempo que estamos dispuestos a dedicarle.

Otra opción para salir del paso es abrir todos los gráficos necesarios a la vez con diferentes configuraciones para sus indicadores. Pero luego, toda la pantalla de trabajo del monitor se verá llena de ventanas con el mismo tipo de indicadores, que se distinguirán ligeramente en la configuración del periodo. Esta solución tampoco resulta óptima en cuanto a la organización del espacio de trabajo. Desafortunadamente, en ninguno de los casos podemos hablar de comodidad.


La esencia del problema

Me gustaría mostrar cuál es el problema usando para ello un ejemplo de una estrategia comercial que he usado durante mucho tiempo al negociar. Creo que muchos tráders se enfrentan al mismo problema todos los días, pero algunos simplemente no se dan cuenta y lo dan por sentado, mientras que a otros como yo, les crea incomodidad. La estrategia se basa en las indicaciones de las líneas de media móvil, y funciona bien en los movimientos de tendencia. Su esencia reside en que si ha comenzado una tendencia, lo más probable es que esta continúe; la señal para la transacción será el regreso del precio a la línea lenta durante la corrección. 

Para calcular el periodo de la línea lenta, deberemos encontrar una determinada posición de las medias móviles rápidas y lentas durante la corrección anterior. 

imagen_01

Para encontrar el periodo deseado, deberemos realizar una serie de operaciones repetitivas. La peculiaridad de esta estrategia es que el periodo de las líneas siempre deberá diferir en 2 veces. Por ejemplo, si el periodo de la línea rápida es 20, el periodo de la línea lenta deberá ser 40. En este caso, deberemos encontrar un valor mínimo para los periodos de estas líneas en el que la línea rápida no cruce la lenta durante esta corrección. En la imagen, los periodos de las líneas son 25 y 50, respectivamente. Podemos ver que durante la corrección anterior, las líneas aún no se han cruzado. Así, podremos reducir aún más sus periodos. Abrimos la configuración de línea rápida y cambiamos el periodo. Luego abrimos la configuración de línea lenta, y también cambiamos el periodo. Tendremos que hacer esta operación varias veces hasta que las líneas converjan lo más cerca posible.

imagen_03

Las líneas todavía no se han cruzado. Sin embargo, primero necesitaremos encontrar la posición extrema en la que las líneas se cruzan y luego aumentar su periodo en un paso. Por consiguiente, volveremos a cambiar la configuración del periodo a 7 y 14, respectivamente.

  

imagen_04

Obtenemos el cruce de las líneas. Esto significará que se ha encontrado una posición extrema y ahora será necesario aumentar los periodos en un paso. Abrimos la configuración para cada línea nuevamente y cambiamos los valores del periodo.

imagen_05

Como resultado, encontramos la combinación deseada de parámetros de línea y la señal genera con éxito. Pero la preparación para la búsqueda de esta señal ha tomado cierto tiempo y también me ha obligado a realizar acciones monótonas, se podría decir, tediosas. Sin embargo, este es solo un periodo de tiempo en una pareja de divisas. Para monitorear varias parejas de divisas en distintos marcos temporales, estas acciones deberán realizarse con mucha frecuencia. En la práctica, puedo decir que si usamos marcos temporales de minutos, este proceso tomará al menos la mitad del tiempo de trabajo. Puede que esta estrategia sea popular, tal vez la tomé prestada o la inventé yo mismo, eso no lo recuerdo ahora, pero creo que muchos tráders usan algo similar en sus transacciones diarias.

Las desventajas derivadas del uso de estas estrategias son obvias. Además del hecho de que tales manipulaciones constantes con los ajustes del indicador toman mucho tiempo, también distraen la atención de la actividad principal: el trading. Durante la selección de los siguientes parámetros de las líneas, podemos pasar por alto una señal ya formada en otra pareja de divisas o en otro periodo de tiempo, o no cerrar a tiempo una transacción ya abierta, con el máximo beneficio o las mínimas pérdidas. Además, después de varias horas de un trabajo semejante, cualquier persona comienza a cansarse. Las acciones monótonas atontan nuestra mente: debido a estas manipulaciones, la atención se dispersa, haciendo que nos cansemos de comerciar. Sin embargo, el principal recurso, más valioso que cualquier dinero, es el tiempo gastado. Lo más probable es que muchos tráders simplemente no hayan pensado en ello todavía, pero después de varios años de trabajo ante el monitor de una computadora, comienzas a valorar tu tiempo y comprender la importancia de esas cosas que parecerían insignificantes.


Principio de la interfaz

El sentido de la interfaz consiste en desplazar el periodo del indicador con la rueda del ratón directamente desde el gráfico, sin entrar en la configuración. Para activar el modo de desplazamiento, usaremos el botón.

Si desea probar el funcionamiento de esta interfaz, podrá descargar el código fuente del indicador "Button CCI" en el archivo adjunto, o descargar la última versión gratuita con características adicionales y ver una descripción detallada de su configuración en el enlace.

La esencia del problema parece clara; ahora debemos pensar en su solución. Obviamente, necesitaremos acelerar de alguna forma el proceso de establecimiento del periodo. Solo hay una manera de hacer esto: automatizando este proceso. Podemos crear un algoritmo que seleccionará los valores para el periodo en sí, ¡pero este algoritmo todavía necesitará su propio periodo para el cálculo! ¡Tendremos que configurar manualmente el número de velas en el que el algoritmo seleccionará el periodo de las media móviles! Una especie de metaperiodo. Esto resolverá el problema del tiempo dedicado a la selección del periodo deseado, pero, debido a su complejidad, esta solución tiene sus inconvenientes. Este enfoque se implementa en el indicador gratuito Dynamic Double Moving Averages. En el futuro, planeo mejorarlo para que resulte más manejable y responda a los cambios en la configuración introducida por el usuario.

Otro método, en mi opinión, más simple y a la vez más interactivo, es el cambio del periodo por parte del propio tráder, pero de una forma más cómoda. Después de todo, no importa lo inteligente que sea el algoritmo, el tráder sabe aún mejor qué configuración del indicador necesita: nuestra tarea es ayudarlo y facilitar este proceso. Para cambiar el periodo, usaremos el desplazamiento con la rueda del ratón. El modo de desplazamiento en sí mismo se activará al activar el botón a la derecha en el gráfico.


GIF_01

La imagen muestra lo simple que resulta cambiar el periodo del indicador con un solo movimiento. Solo tenemos que activar el botón del indicador deseado y girar la rueda del ratón en la dirección necesaria. Si lo desea, podrá establecer el paso deseado para cambiar el periodo. También podrá cambiar el periodo de varios indicadores a la vez simplemente activando los botones deseados. Estas características serían excelentes para la estrategia descrita anteriormente. Por ejemplo, podemos establecer el paso para cambiar la línea rápida en 1, y la línea lenta en 2, activar el desplazamiento de ambas líneas y cambiar fácilmente sus periodos al mismo tiempo, manteniendo la relación 1/2.


Ventajas

Los indicadores con esta interfaz tienen una serie de ventajas.

Desventajas

Aun poseyendo todas estas ventajas, dicha interfaz no está exenta de inconvenientes.

Pero el análisis de la historia no se necesita con tanta frecuencia y, para el uso diario, podemos limitar la cantidad de datos a calcular.  No obstante, estas deficiencias no son de una importancia tan crítica, y tampoco nos impiden disfrutar del uso diario de dichos indicadores en MetaTrader 5.


Creación de un indicador con desplazamiento de periodo basado en la media móvil

Usando como base lo anteriormente dicho, decidí que sería útil crear un indicador con una interfaz más cómoda, que ahorrara al usuario acciones rutinarias, así como tiempo y esfuerzo al tráder. Además, el objetivo era crear el principio más simple para la mayoría de los indicadores, de forma que una interfaz similar se pudiera reproducir fácilmente en cualquier otro indicador.

Como ejemplo, decidí tomar el indicador más popular: la media móvil. Toda la complejidad de la idea reside en el hecho de que si queremos cambiar dinámicamente el periodo, entonces, en esencia, usaremos docenas e incluso cientos de indicadores al mismo tiempo. Como el sistema distingue los indicadores usados en una ventana según el nombre breve y el conjunto de parámetros, el conjunto de parámetros siempre se distinguirá por el "periodo" del indicador en cada paso de cambio, por lo que para cada periodo se creará un identificador de indicador nuevo, lo cual puede ralentizar significativamente el funcionamiento. Mientras intentaba resolver este problema, en los foros me encontré críticas a este método. Los programadores experimentados aseguraban que tal implementación está prohibida a nivel de idioma y generalmente resulta imposible: el desbordamiento de memoria resulta inevitable (lo cual encontré constantemente en MetaTrader 4). Sí, para MetaTrader 4 este es un problema imposible de resolver.

Pero en el lenguaje MQL5, se crea una vez un identificador para cada indicador en el gráfico, y luego solo se accede al identificador del ya creado. Es decir, incluso si creamos un nuevo identificador en cada manejador, en la práctica, no se creará, sino que solo se referirá al ya creado. Y esto ya facilita las cosas para la memoria. Pero, después de todo, podemos crear todos los identificadores necesarios en OnInit de antemano y luego olvidarnos por completo de este problema. En este caso, surgirá una única limitación para el tráder: deberá determinar de antemano dentro de qué límites cambiará el periodo para crear todos los identificadores necesarios al inicializar el indicador. El periodo máximo está limitado de antemano por el tráder en la configuración a través del parámetro "period_ma_max". Con la ayuda de un paso, ahorramos aún más memoria, pues no calcularemos identificadores innecesarios. El tráder también establece el paso, pero por defecto, estableceremos step = 1.

int OnInit()
{
//Create all the necessary handles
for(int i=1; i<=period_ma_max; i+=step)
    handle=iMA(_Symbol,_Period,i,0,method_MA,price_MA);
     
}

Ahora necesitamos crear la funcionalidad para implementar el desplazamiento del periodo. Para hacer esto, crearemos un botón en el gráfico; al clicar en él, el modo de desplazamiento del periodo se activará con la rueda del ratón.

//+------------------------------------------------------------------+
//|              CREATING BUTTON IN OnInit()                          
//+------------------------------------------------------------------+
 
   ObjectDelete(0,name);
   ObjectCreate(0,name,OBJ_BUTTON,0,0,0);
   ObjectSetString(chart_ID,name,OBJPROP_TEXT,text);
   ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr_Text_Button);
   ObjectSetInteger(chart_ID,name,OBJPROP_BGCOLOR,clr_Button);
   ObjectSetInteger(chart_ID,name,OBJPROP_CORNER,CORNER_RIGHT_UPPER);
   ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,distance_X);
   ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,distance_Y);
   ObjectSetInteger(chart_ID,name,OBJPROP_XSIZE,size_X);
   ObjectSetInteger(chart_ID,name,OBJPROP_YSIZE,size_Y);
   ObjectSetInteger(chart_ID,name,OBJPROP_STATE,true);
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,true);
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,true);
   ObjectSetInteger(chart_ID,name,OBJPROP_STATE,press_Button);
   ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,1);

   ChartRedraw();

Al cargar dos o más indicadores en un gráfico, sus botones se crearán en el mismo lugar, lo cual resultará un inconveniente. Por lo tanto, al añadir cada indicador posterior, deberemos desplazar el botón a lo largo de algún eje. Para hacer esto, primero deberemos calcular exactamente cuántos de nuestros indicadores ya se han cargado en el gráfico. Primero, buscaremos el número total de indicadores en esta ventana:

int      total_Indicators=ChartIndicatorsTotal(0,0),
         this_indicators=0;

A continuación, seleccionaremos nuestros indicadores de ellos:

for(int i=0; i<total_Indicators; i++)
     {
      if(ChartIndicatorName(0,0,i)=="Button_MA")
         this_indicators++;
     }
IndicatorSetString(INDICATOR_SHORTNAME,"Button_MA")

Al buscar de esta forma un indicador según el nombre breve, siempre deberemos recordar que si creamos un nombre de indicador breve después de un ciclo, entonces el nombre del indicador actual que añadimos al gráfico se corresponderá con el nombre de su archivo. Es decir, en este caso, si el nombre del archivo difiere de INDICATOR_SHORTNAME, el indicador actual no se calculará en el ciclo.

Ahora vamos a desplazar el botón a lo largo del eje X:

distance_X=size_X*this_indicators;

Después de eso, los botones de todos los indicadores añadidos al gráfico aparecerán en una fila. Pero, desafortunadamente, el usuario tendrá que cambiar el nombre del botón al añadir más de un indicador a un gráfico. Eso, o al menos cambiar otros parámetros de entrada del indicador en la configuración. Esto se debe a que en MetaTrader 5 está prohibido añadir a una ventana indicadores con los mismos parámetros de entrada. No se puede hacer nada al respecto, por lo que deberemos delegar en el tráder el cambio manual de la configuración. No obstante, como no siempre resulta necesario cambiar la configuración, moveremos el nombre del botón a la configuración del indicador. De esta forma, mataremos dos pájaros de un tiro: cambiaremos los parámetros de entrada del indicador y proporcionaremos diferentes nombres para los objetos en el mismo gráfico. Además, los botones con diferentes nombres resultan más informativos y cómodos de usar. 

input string  name_Line = "MA_1"; 
string   name = name_Line,
         text = name_Line;

Ahora, cuando el usuario cambie el nombre de cada botón, los indicadores y los propios botones se añadirán a la ventana sin ningún problema, y el texto que se muestra en los botones se corresponderá con su nombre. Los botones están listos, ahora necesitamos crear un mecanismo para desplazar el periodo. Activaremos el evento de desplazamiento de la rueda, así como la pulsación de los botones del ratón.

ChartSetInteger(0,CHART_EVENT_MOUSE_WHEEL,1);
ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,1);

A continuación, trabajaremos en la función OnChartEvent(). Comprobamos si el botón está presionado. Si no se encuentra presionado, mostraremos su nombre en él, y si lo está, activaremos el modo de desplazamiento del periodo del indicador y deshabilitaremos el desplazamiento del gráfico en sí. En consecuencia, si el botón no se encuentra presionado, activaremos el desplazamiento del gráfico.


void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   if(!press_Button)
      ObjectSetString(chart_ID,name,OBJPROP_TEXT,text);
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      if(sparam==name)
        {
         press_Button=ObjectGetInteger(chart_ID,name,OBJPROP_STATE);
         if(press_Button)
           {
            scroll_Button=true;
            ChartSetInteger(0,CHART_MOUSE_SCROLL,0);
            ChartRedraw();
           }
         else
           {
            scroll_Button=false;
            ChartSetInteger(0,CHART_MOUSE_SCROLL,1);
            ChartRedraw();
           }
        }
     }
  }

Si el modo de desplazamiento del periodo está activado, comprobaremos el estado de la rueda del ratón. Dependiendo de hacia dónde gire, sumaremos o restaremos el periodo. El valor de desplazamiento total de la rueda se activará cuando llegue a +120 o -120.

if(scroll_Button)
      if(id==CHARTEVENT_MOUSE_WHEEL)
        {
         int delta = (int)dparam;
         if(delta>119)
            if(period_ma<period_ma_max)
              {
               period_ma+=step;
               ChartRedraw();
              }
         //
         if(delta < -119)
            if(period_ma>step)
              {
               period_ma-=step;
               ChartRedraw();
              }

Aquí accedemos al manejador del indicador con el nuevo periodo y redibujamos la línea del indicador ('total' se define en OnCalculate) Además, cambiamos el texto del botón del nombre al periodo actual al girar la rueda.

handle = iMA(_Symbol,_Period,period_ma,0,method_MA,price_MA);
      
         ArraySetAsSeries(Label1Buffer,true);
         for(int i = 0; i<total; i++)
           {
            double MA[];
            CopyBuffer(handle,0,i,1,MA);
            Label1Buffer[i]=MA[0];
       
            ChartRedraw();

           }
         ArraySetAsSeries(Label1Buffer,false);
         if(press_Button)
            ObjectSetString(chart_ID,name,OBJPROP_TEXT,IntegerToString(period_ma));
        }

Aquí, redibujamos la línea para no tener que esperar un nuevo tick para mostrar la línea del indicador con el nuevo periodo. Así, la línea siempre se reconstruirá al momento, independientemente de la llegada de un nuevo tick.

Otra limitación que no podemos eludir se refiere al botón. Si el modo de arrastre está activado, el modo de pulsación de un botón estará desactivado, y viceversa. Por consiguiente, podremos arrastrar el botón a un lugar más cómodo solo una vez. Después de desactivar el modo encargado de arrastrar y soltar, ya no lo activaremos. Ya en la próxima inicialización, el botón no recordará su posición y volverá a su lugar original en la fila general.

if(id==CHARTEVENT_OBJECT_CLICK)
     {
      if(sparam==name)
        {
         long select = ObjectGetInteger(chart_ID,name,OBJPROP_SELECTED);
         if(select==0)
           {
            ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,false);
            ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,false);
            flag_drag=false;
           }
         ChartRedraw();
         }
      }

Implementamos la línea principal del indicador como de costumbre en OnCalculate();

total=rates_total-1;
   if(Limit_for_Calc)
      if(total>Limit)
         total=Limit;
   handle = iMA(_Symbol,_Period,period_ma,0,method_MA,price_MA);
   if(handle==INVALID_HANDLE)
     {
      Print("invalid handle ");
      return(rates_total);
     }
   ResetLastError();
   while(BarsCalculated(handle)<=0)
     {
      // indicator values are not calculated yet, try next time
      return(0);
     }

   for(int i = prev_calculated>0?prev_calculated-1:0; i<rates_total; i++)
     {
      double MA[];
      CopyBuffer(handle,0,time[i],1,MA);
      Label1Buffer[i]=MA[0]+level;
     }
Aquí podemos limitar el cálculo de la línea al girar la rueda solo en los datos más recientes, para ahorrar así recursos computacionales. Para hacer esto, ofreceremos al tráder la oportunidad de elegir si desea activar el límite de cálculo en la configuración y cuántas barras se tomarán para los cálculos.
input bool    Limit_for_Calc = false;
input int     Limit = 20000;


Resultado

Eso es todo, ya hemos analizado los puntos principales a la hora de crear un indicador. Como resultado, hemos obtenido un indicador completo, de ninguna manera inferior al estándar, pero más cómodo. Lo único negativo es que todavía no hemos podido evitar algunas desventajas. Por ejemplo, en una historia de más de 20.000 barras, podemos notar una desaceleración. Sin embargo, el análisis de la historia no resulta necesario con tanta frecuencia y, para el uso diario, podemos limitar el número de barras para el cálculo. También hemos tenido ciertos inconvenientes con el cambio manual del nombre de los botones y la imposibilidad de arrastrar un botón más de una vez.

Por lo demás, hemos logrado los objetivos marcados: el indicador cambia suavemente el periodo al girar la rueda del ratón, mientras que la función de desplazamiento se activa y desactiva con solo pulsar el botón a la derecha en el gráfico.


Conclusión

Esta interfaz, aun teniendo algún defecto, todavía puede considerarse más cómoda que la estándar, ya que permite al tráder obtener la configuración de indicador necesaria con el mínimo tiempo y esfuerzo, así como descargar el espacio de trabajo del mismo tipo de indicadores. También permite obtener señales más precisas durante un periodo de tiempo limitado en un mercado que cambia rápidamente. 

Los indicadores creados con una interfaz de este tipo son fáciles de usar, intuitivos, y ahorran tiempo y esfuerzo al tráder. Asimismo, permiten a este concentrarse en el comercio, mejorando así su calidad y también aumentando su productividad. 

Además, este enfoque permite obtener no solo la configuración del periodo, sino también cualquier otra que sea recomendable para poner en un botón, o incluso a la hora de crear un panel para varias configuraciones. Puede tratarse del color, el grosor de la línea, el tamaño del objeto, etc. Además del desplazamiento, podremos arrastrar objetos, teclas de acceso rápido o simplemente pasar el cursor sobre un objeto o área del gráfico. Una de estas funciones se implementa en el indicador Button MA. En él, podemos usar el desplazamiento del periodo no solo presionando el botón, sino también simplemente pasando el ratón sobre él. Además, recuerda la posición de los botones tras el arrastre, incluso después de cambiar el marco temporal.

Este artículo abarca los pasos básicos para crear un indicador de desplazamiento de periodo basado en la media móvil. En el archivo adjunto, encontrará el código del indicador terminado creado sobre la base de CCI. Su uso es aún más simple, ya que, sea cual sea el número de botones en un gráfico, no será necesario cambiarles el nombre: este se indexará automáticamente según el número de botones instalados.

GIF_02