Indicadores de subventanas independientes: tamaños y niveles

Hasta ahora nos hemos limitado a los indicadores que funcionan en la ventana principal del gráfico, es decir, que tienen la directiva #property indicator_chart_window. Ha llegado el momento de estudiar los indicadores colocados en una subventana separada debajo del gráfico de precios. Recuerde que deben declararse con la directiva #property indicator_separate_window.

Todo lo que aprendimos anteriormente se aplica a los indicadores en una subventana, incluyendo la descripción y el anclaje de los búferes, la configuración de los tipos y estilos de dibujo y el uso de las formas completa y abreviada de OnCalculate, a elegir. Sin embargo, también tienen algunas características y ajustes adicionales.

Dado que la subventana tiene su escala de valores, MQL5 permite establecer los valores máximo y mínimo para ella (los usuarios pueden establecer restricciones similares en el cuadro de diálogo de configuración del indicador, en la pestaña Scale). Esto se hace mediante programación utilizando la función IndicatorSetDouble con el siguiente prototipo.

bool IndicatorSetDouble(ENUM_CUSTOMIND_PROPERTY_DOUBLE property, double value)

bool IndicatorSetDouble(ENUM_CUSTOMIND_PROPERTY_DOUBLE property, int modifier,
double value)

La función establece un valor de propiedad double para un indicador. Se necesitaron dos formularios porque algunas propiedades pueden ser múltiples; en concreto, los niveles horizontales (se abordarán un poco más adelante). Las propiedades disponibles se recopilan en la enum ENUM_CUSTOMIND_PROPERTY_DOUBLE.

Identificador

Descripción

INDICATOR_MINIMUM

Mínimo en el eje vertical

INDICATOR_MAXIMUM

Máximo en el eje vertical

INDICATOR_LEVELVALUE

Valor del nivel horizontal (el número se establece en el parámetro modificador)

En muchos indicadores oscilatorios, como WPR, se utiliza un rango de escala fijo. Veremos un ejemplo con él en el que se abarcan todas las funciones (propiedades) de esta sección.

La función devuelve true en caso de éxito y false en caso contrario.

Además de controlar la escala, los indicadores de la subventana pueden, como ya hemos entendido, tener niveles horizontales. Para establecer su número y atributos, se utiliza otra función, IndicatorSetInteger. El usuario puede realizar acciones similares en el cuadro de diálogo de configuración del indicador en la pestaña Levels tab/

bool IndicatorSetInteger(ENUM_CUSTOMIND_PROPERTY_INTEGER property, int value)

bool IndicatorSetInteger(ENUM_CUSTOMIND_PROPERTY_INTEGER property, int modifier,
int value)

La función también tiene dos formas y permite establecer el valor de la propiedad de tipo para el indicador int o equivalente (por ejemplo, color o listado). Las propiedades disponibles se recopilan en la enumeración ENUM_CUSTOMIND_PROPERTY_INTEGER. Además de las propiedades asociadas a los niveles, contiene la propiedad INDICATOR_DIGITS, que es común para los indicadores de cualquier tipo: la estudiaremos en la sección siguiente.

Identificador

Descripción

INDICATOR_DIGITS

Precisión de visualización de los valores de los indicadores (dígitos después del punto decimal)

INDICATOR_HEIGHT

Altura fija de la propia ventana del indicador en píxeles (comando del preprocesador #property indicator_height)

INDICATOR_LEVELS

Número de niveles horizontales en la ventana del indicador

INDICATOR_LEVELCOLOR

Color de la línea de nivel (tiene el tipo color, el parámetro modifier establece el número de nivel)

INDICATOR_LEVELSTYLE

Estilo de línea de nivel (tiene un tipo ENUM_LINE_STYLE, el parámetro modifier establece el número de nivel)

INDICATOR_LEVELWIDTH

Grosor de la línea de nivel (1-5) (el parámetro modifier establece el número de nivel)

Los niveles pueden tener etiquetas de texto. Para asignarlas, utilice la función IndicatorSetString.

bool IndicatorSetString(ENUM_CUSTOMIND_PROPERTY_STRING property, string value)

bool IndicatorSetString(ENUM_CUSTOMIND_PROPERTY_STRING property, int modifier,
string value)

ENUM_CUSTOMIND_PROPERTY_STRING contiene la lista de parámetros del indicador de cadena. Preste atención a la propiedad INDICATOR_SHORTNAME que no está relacionada con los niveles: también es común a todos los indicadores y se abordará en la sección siguiente.

Identificador

Descripción

INDICATOR_SHORTNAME

Indicador título público

INDICATOR_LEVELTEXT

Descripción del nivel (el número se indica en el modificador)

Todas las funciones mencionadas para los tipos numéricos int y double están duplicadas por directivas especiales (a continuación se muestra una tabla resumen).

Directivas para 
propiedades de nivel

Funciones analógicas

Tipo de 
propiedad

Descripción

indicator_levelN

IndicatorSetDouble(
INDICATOR_LEVELVALUE,
N-1, valor)

double

Valor del número de nivel horizontal N en el eje vertical

indicator_levelcolor

IndicatorSetInteger(
INDICATOR_LEVELCOLOR,
N-1, color)

color

Color de los niveles horizontales (sólo se pueden establecer diferentes colores mediante números utilizando la función)

indicator_levelwidth

IndicatorSetInteger(
INDICATOR_LEVELWIDTH,
N-1, anchura)

int

Grosor de línea de los niveles horizontales en píxeles (sólo se pueden establecer diferentes grosores mediante números utilizando la función)

indicator_levelstyle

IndicatorSetInteger(
INDICATOR_LEVELSTYLE,
N-1, estilo)

ENUM
__LINE__
_STYLE

Estilos de línea de los niveles horizontales (sólo se pueden establecer diferentes estilos por número utilizando la función)

indicator_minimum

IndicatorSetDouble(
INDICATOR_MINIMUM, mínimo)

double

Valor mínimo fijo, límite inferior de la escala en el eje vertical

indicator_maximum

IndicatorSetDouble(
INDICATOR_MAXIMUM, máximo)

double

Valor máximo fijo, límite superior de la escala en el eje vertical

Tenga en cuenta que la numeración de las instancias de propiedades (modificadores) cuando se utilizan directivas #property empieza por 1 (uno), mientras que las funciones utilizan una numeración a partir de 0 (cero).

Un lector atento observará que no hay directivas para algunas propiedades. Entre ellas se incluyen INDICATOR_LEVELTEXT, INDICATOR_SHORTNAME, INDICATOR_DIGITS. Se da por sentado que estas propiedades deben rellenarse dinámicamente desde el código MQL, dependiendo de las variables de entrada y del gráfico en el que se coloque el indicador. INDICATOR_LEVELS se establece indirectamente especificando varias directivas para los niveles.

Por último, la característica distintiva de los indicadores en una subventana es que un programa puede «congelar» el tamaño vertical de su ventana.

Directiva para 
tamaño de la subventana

Función analógica

Descripción

indicator_height

IndicatorSetInteger(
INDICATOR_HEIGHT, altura)

Altura fija de la subventana del indicador en píxeles (el usuario no podrá cambiar la altura).

Una altura de subventana fija se utiliza normalmente sólo para paneles de control con controles (botones, banderas, campos de entrada) implementados utilizando objetos gráficos.

Para las funciones de configuración de propiedades, desgraciadamente, no hay inversas (IndicatorGetInteger, IndicatorGetDouble, IndicatorGetString). Entre otras cosas, esto no permite, por ejemplo, buscar el número y los valores de los niveles horizontales si han sido modificados por el usuario.

Como ejemplo de trabajo con una escala y niveles fijos, considere el indicador IndWPR.mq5. En él, utilizaremos el algoritmo WPR estándar: en un número determinado de barras pasadas (periodo WPR), encontraremos los máximos H y los mínimos L del precio (es decir, su rango). A continuación, calculamos la relación entre la diferencia entre el precio actual C y el mínimo L, C - L (o la diferencia -(H - C), con signo negativo) y todo el rango, y lo llevamos todo al rango de 0 a -100. He aquí la fórmula canónica para calcular WPR:

R% = (-(H — C) / (H — L)) * 100

Vamos a añadir algunas directivas al principio del código fuente. Además de la propiedad de ubicación del indicador en su propia ventana, vamos a establecer la escala de valores de 0 a -100.

#property indicator_separate_window
#property indicator_maximum    0.0
#property indicator_minimum    -100.0

Un búfer y un gráfico de líneas son suficientes para almacenar los valores y mostrar el indicador.

#property indicator_buffers    1
#property indicator_plots      1
#property indicator_type1      DRAW_LINE
#property indicator_color1     clrDodgerBlue

En el indicador WPR es habitual distinguir dos niveles: -20 y -80, como límites de las zonas de sobrecompra y sobreventa, respectivamente. Vamos a crear un par de líneas horizontales para ellos.

#property indicator_level1     -20.0
#property indicator_level2     -80.0
#property indicator_levelstyle STYLE_DOT
#property indicator_levelcolor clrSilver
#property indicator_levelwidth 1

La única variable de entrada permite establecer el periodo de cálculo para WPR.

input int WPRPeriod = 14// Period

El array para el búfer se declara a nivel global y se registra con OnInit.

double WPRBuffer[];
   
void OnInit()
{
   // check for correct input
   if(WPRPeriod < 1)
   {
      Alert(StringFormat("Incorrect Period value (%d). Should be 1 or larger"
         WPRPeriod));
   }
   
   // binding array as buffer
   SetIndexBuffer(0WPRBuffer);
}

El manejador OnInit se describe con el tipo void, que conlleva de forma implícita una inicialización exitosa. No obstante, si el periodo es inferior a 1, no permitirá realizar el cálculo y se mostrará un aviso al usuario.

Para simplificar el encabezado de la función OnCalculate se ha preparado el archivo de encabezado IndCommon.mqh para indicadores, con dos macros que describen las listas de parámetros estándar de ambas formas del manejador de eventos.

#define ON_CALCULATE_STD_FULL_PARAM_LIST \
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[]
   
#define ON_CALCULATE_STD_SHORT_PARAM_LIST \
const int rates_total,     \
const int prev_calculated, \
const int begin,           \
const double &data[]

Ahora podemos utilizar la definición concisa de OnCalculate en este y otros indicadores (siempre que estemos satisfechos con los nombres de los parámetros propuestos en las macros).

#include <MQL5Book/IndCommon.mqh>
 
int OnCalculate(ON_CALCULATE_STD_FULL_PARAM_LIST)
{
   if(rates_total < WPRPeriod || WPRPeriod < 1return 0;
   ...
   return rates_total;
}

Al principio de OnCalculate comprobamos si es posible calcular utilizando los valores actuales de WPRPeriod y rates_total. Si no hay datos suficientes o el periodo es demasiado corto, devuelve 0, lo que dejará vacía la ventana del indicador.

A continuación, rellenamos con un valor vacío las primeras barras para las que es imposible calcular el WPR de un periodo determinado.

int OnCalculate(ON_CALCULATE_STD_FULL_PARAM_LIST)
{
   ...
   if(prev_calculated == 0)
   {
      ArrayFill(WPRBuffer0WPRPeriod - 1EMPTY_VALUE);
   }
   ...
}

Por último, realizamos los cálculos de WPR y almacenamos los resultados. Observe que la última barra se actualiza en cada tick: esto se consigue iniciando el bucle con prev_calculated - 1.

int OnCalculate(ON_CALCULATE_STD_FULL_PARAM_LIST)
{
   ...
   for(int i = fmax(prev_calculated - 1WPRPeriod - 1);
      i < rates_total && !IsStopped(); i++)
   {
      double max_high = high[fmax(ArrayMaximum(highi - WPRPeriod + 1WPRPeriod), 0)];
      double min_low = low[fmax(ArrayMinimum(lowi - WPRPeriod + 1WPRPeriod), 0)];
      if(max_high != min_low)
      {
         WPRBuffer[i] = -(max_high - close[i]) * 100 / (max_high - min_low);
      }
      else
      {
         WPRBuffer[i] = WPRBuffer[i - 1];
      }
   }
   return rates_total;
}

ArrayMaximum y ArrayMinimum permiten buscar los índices del high más alto y del low más bajo.

El indicador aparece en una ventana independiente de la siguiente manera.

Indicador WPR

Indicador WPR

En las siguientes secciones seguiremos mejorando este indicador, añadiendo gradualmente otras propiedades de uso común.