Gestionar indicadores en el gráfico

Como ya hemos visto, los gráficos son el entorno de ejecución y visualización de los indicadores. Su estrecha relación encuentra una confirmación adicional en forma de todo un grupo de funciones integradas que proporcionan control sobre los indicadores en los gráficos. En uno de los capítulos anteriores, ya completamos una visión general de estas características. Ahora, tras familiarizarnos con los gráficos, estamos preparados para estudiarlos en detalle.

Todas las funciones están unidas por el hecho de que los dos primeros parámetros están unificados: se trata del identificador del gráfico (chartId) y del número de ventana (window). Los valores cero de los parámetros denotan el gráfico actual y la ventana principal, respectivamente.

int ChartIndicatorsTotal(long chartId, int window)

La función devuelve el número de todos los indicadores adjuntos a la ventana de gráfico especificada. Puede utilizarse para enumerar todos los indicadores adjuntos a un gráfico determinado. El número de todas las ventanas del gráfico puede obtenerse de la propiedad CHART_WINDOWS_TOTAL mediante la función ChartGetInteger.

string ChartIndicatorName(long chartId, int window, int index)

La función devuelve el nombre corto del indicador por el index en la lista de indicadores situados en la ventana del gráfico especificado. El nombre corto es el nombre especificado en la propiedad INDICATOR_SHORTNAME por la función IndicatorSetString (si no se establece, por defecto es igual al nombre del archivo del indicador).

int ChartIndicatorGet(long chartId, int window, const string shortname)

Devuelve el manejador del indicador con el nombre corto especificado en la ventana de gráfico específica. Podemos decir que la identificación del indicador en la función ChartIndicatorGet se hace exactamente por el nombre corto, y por lo tanto se recomienda componerlo de tal manera que contenga los valores de todos los parámetros de entrada. Si esto no es posible por una razón u otra, existe otra forma de identificar una instancia de indicador a través de la lista de sus parámetros, que puede obtenerse mediante un descriptor dado utilizando la función IndicatorParameters.

La obtención de un manejador de una función ChartIndicatorGet aumenta el contador interno para utilizar este indicador. El sistema de ejecución del terminal mantiene cargados todos los indicadores cuyo contador es mayor que cero. Por lo tanto, un indicador que ya no se necesita debe liberarse explícitamente llamando a IndicatorRelease. De lo contrario, el indicador permanecerá inactivo y consumirá recursos.

bool ChartIndicatorAdd(long chartId, int window, int handle)

La función añade un indicador con el descriptor pasado en el último parámetro a la ventana del gráfico especificada. El indicador y el gráfico deben tener la misma combinación de símbolo y marco temporal. En caso contrario, se producirá el error ERR_CHART_INDICATOR_CANNOT_ADD (4114).

Para añadir un indicador a una nueva ventana, el parámetro window debe ser mayor en uno que el índice de la última ventana existente, es decir, igual a la propiedad CHART_WINDOWS_TOTAL recibida a través de la llamada a ChartGetInteger. Si el valor del parámetro supera el valor de ChartGetInteger(ID,CHART_WINDOWS_TOTAL), no se creará una nueva ventana ni un nuevo indicador.

Si se añade un indicador a la ventana del gráfico principal, que debería dibujarse en una subventana separada (por ejemplo, un iMACD integrado o un indicador personalizado con la propiedad especificada #property indicator_separate_window), entonces dicho indicador puede parecer invisible, aunque estará presente en la lista de indicadores. Esto suele significar que los valores de este indicador no se encuentran dentro del rango mostrado en el gráfico de precios. Los valores de dicho indicador «invisible» pueden observarse en Data window y leerse utilizando funciones de otros programas MQL.

Añadir un indicador a un gráfico aumenta el contador interno de su uso debido a su vinculación con el gráfico. Si el programa MQL mantiene su descriptor y ya no es necesario, entonces vale la pena borrarlo llamando a IndicatorRelease. En realidad, esto reducirá el contador, pero el indicador permanecerá en el gráfico.

bool ChartIndicatorDelete(long chartId, int window, const string shortname)

La función elimina el indicador con el nombre corto especificado de la ventana con el número window en el gráfico con chartId. Si hay varios indicadores con el mismo nombre corto en la subventana del gráfico especificado, se eliminará el primero en orden.

Si se calculan otros indicadores utilizando los valores del indicador eliminado en el mismo gráfico, también se eliminarán.

Borrar un indicador de un gráfico no significa que su parte calculada también se borre de la memoria del terminal si el descriptor permanece en el programa MQL. Para liberar el manejador del indicador, utilice la función IndicatorRelease.

La función ChartWindowFind devuelve el número de la subventana donde se encuentra el indicador. Hay 2 formas diseñadas para buscar el indicador actual en su gráfico o un indicador con un nombre corto dado en un gráfico arbitrario con el identificador chartId.

int ChartWindowFind()

int ChartWindowFind(long chartId, string shortname)

La segunda forma puede utilizarse en scripts y Asesores Expertos.

Como primer ejemplo de demostración de estas funciones, vamos a analizar la versión completa del script ChartList.mq5. Lo hemos creado y perfeccionado gradualmente en las secciones anteriores, hasta la sección Obtener el número y la visibilidad de las ventanas/subventanas. En comparación con ChartList4.mq5 que se presentó ahí, añadiremos variables de entrada para poder listar sólo gráficos con programas MQL y suprimir la visualización de ventanas ocultas.

input bool IncludeEmptyCharts = true;
input bool IncludeHiddenWindows = true;

Con el valor por defecto (true) el parámetro IncludeEmptyCharts ordena incluir todos los gráficos en la lista, incluidos los vacíos. El parámetro IncludeHiddenWindows establece por defecto la visualización de las ventanas ocultas. Estos ajustes corresponden a la lógica de creación de scripts ChartListN anterior.

Para calcular el número total de indicadores e indicadores en subventanas, definimos las variables indicators y subs.

void ChartList()
{
   ...
   int indicators = 0subs = 0;
   ...

El bucle de trabajo en las ventanas del gráfico actual ha sufrido cambios importantes.

void ChartList()
{
      ...
      for(int i = 0i < wini++)
      {
         const bool visible = ChartGetInteger(idCHART_WINDOW_IS_VISIBLEi);
         if(!visible && !IncludeHiddenWindowscontinue;
         if(!visible)
         {
            Print("  "i"/Hidden");
         }
         const int n = ChartIndicatorsTotal(idi);
         for(int k = 0k < nk++)
         {
            if(temp == 0)
            {
               Print(header);
            }
            Print("  "i"/"k" [I] "ChartIndicatorName(idik));
            indicators++;
            if(i > 0subs++;
            temp++;
         }
      }
      ...

Aquí hemos añadido las llamadas ChartIndicatorsTotal y ChartIndicatorName. Ahora la lista mencionará programas MQL de todo tipo: [E]: Asesores Expertos; [S]: scripts; [I]: indicadores.

A continuación se muestra un ejemplo de las entradas de registro generadas por el script para la configuración predeterminada.

Chart List
N, ID, Symbol, TF, #subwindows, *active, Windows handle
0 132358585987782873 EURUSD M15 #1    133538
  1/0 [I] ATR(11)
1 132360375330772909 EURUSD D1     133514
2 132544239145024745 EURUSD M15   *   395646
 [S] ChartList
3 132544239145024732 USDRUB D1     395688
4 132544239145024744 EURUSD H1 #2  active  2361730
  1/0 [I] %R(14)
  2/Hidden
  2/0 [I] Momentum(15)
5 132544239145024746 EURUSD H1     133584
Total chart number: 6, with MQL-programs: 3
Experts: 0, Scripts: 1, Indicators: 3 (main: 0 / sub: 3)

Si fijamos ambos parámetros de entrada en false, obtendremos una lista reducida.

Chart List
N, ID, Symbol, TF, #subwindows, *active, Windows handle
0 132358585987782873 EURUSD M15 #1    133538
  1/0 [I] ATR(11)
2 132544239145024745 EURUSD M15   * active  395646
 [S] ChartList
4 132544239145024744 EURUSD H1 #2    2361730
  1/0 [I] %R(14)
Total chart number: 6, with MQL-programs: 3
Experts: 0, Scripts: 1, Indicators: 2 (main: 0 / sub: 2)

Como segundo ejemplo, vamos a analizar un script interesante ChartIndicatorMove.mq5.

Cuando ejecutamos varios indicadores en un gráfico, a menudo podemos necesitar cambiar el orden de los indicadores. MetaTrader 5 no tiene herramientas integradas para ello, lo que le obliga a eliminar algunos indicadores y añadirlos de nuevo, mientras que es importante guardar y restaurar la configuración. El script ChartIndicatorMove.mq5 ofrece una opción para automatizar este procedimiento. Es importante tener en cuenta que el script sólo transfiere indicadores: si necesita cambiar el orden de las subventanas junto con los objetos gráficos (si están dentro), entonces debe utilizar plantillas tpl.

La base de funcionamiento de ChartIndicatorMove.mq5 es la siguiente: cuando el script se aplica a un gráfico, determina a qué ventana/subventana se ha añadido, y comienza a listar al usuario los indicadores que allí se encuentran con una petición de confirmación de la transferencia. El usuario puede aceptar o continuar con el listado.

La dirección del movimiento, arriba o abajo, se establece en la variable de entrada MoveDirection. La enumeración DIRECTION lo describirá:

#property script_show_inputs
   
enum DIRECTION
{
   Up = -1,
   Down = +1,
};
   
input DIRECTION MoveDirection = Up;

Para transferir el indicador no a la subventana vecina sino a la siguiente, es decir, para intercambiar realmente las subventanas con indicadores en lugares (lo que suele ser necesario), introducimos la variable de entrada jumpover.

input bool JumpOver = true;

El bucle a través de los indicadores de la ventana de destino obtenidos de ChartWindowOnDropped comienza en OnStart.

void OnStart()
{
   const int w = ChartWindowOnDropped();
   if(w == 0 && MoveDirection == Up)
   {
      Alert("Can't move up from window at index 0");
      return;
   }
   const int n = ChartIndicatorsTotal(0w);
   for(int i = 0i < n; ++i)
   {
      ...
   }
}

Dentro del bucle, definimos el nombre del siguiente indicador, mostramos un mensaje al usuario y movemos el indicador de una ventana a otra utilizando una secuencia de las siguientes manipulaciones:

  • Obtenga el manejador llamando a ChartIndicatorGet.
  • Añádalo a la ventana situada encima o debajo de la actual a través de ChartIndicatorAdd, de acuerdo con la dirección seleccionada, y al desplazarse hacia abajo, se puede crear automáticamente una nueva subventana.
  • Elimine el indicador de la ventana anterior con ChartIndicatorDelete.
  • Libere el descriptor, puesto que ya no lo necesitamos en el programa.

      ...
      const string name = ChartIndicatorName(0wi);
      const string caption = EnumToString(MoveDirection);
      const int button = MessageBox("Move '" + name + "' " + caption + "?",
         captionMB_YESNOCANCEL);
      if(button == IDCANCELbreak;
      if(button == IDYES)
      {
         const int h = ChartIndicatorGet(0wname);
         ChartIndicatorAdd(0w + MoveDirectionh);
         ChartIndicatorDelete(0wname);
         IndicatorRelease(h);
         break;
      }
      ...

En la siguiente imagen se muestra el resultado de intercambiar subventanas con los indicadores WPR y Momentum. El script se lanzó soltándolo en la subventana superior con el indicador WPR, la dirección de movimiento se eligió hacia abajo (Down), el salto (JumpOver) se activó por defecto.

Intercambio de indicadores en las subventanas

Intercambio de indicadores en las subventanas

Tenga en cuenta que, si mueve el indicador de la subventana a la ventana principal, lo más probable es que sus gráficos no sean visibles debido a que los valores van más allá del rango de precios mostrado. Si esto ocurre por error, puede utilizar el script para transferir el indicador de nuevo a la subventana.