Cómo escribir un indicador basado en otro indicador

Dmitry Fedoseev | 18 diciembre, 2013

Introducción

En MQL5 no sólo puedes escribir un indicador desde cero como se muestra en el artículo "MQL5: Crea tu propio Indicador", sino que puedes escribir uno a partir de otro indicador, integrado en el terminal de cliente o personalizado. Hay dos maneras: la primera es para mejorar un indicador, añadiéndole nuevos cálculos y representaciones gráficas (esta opción se aplica sólo a los indicadores personalizados con código abierto), la segunda manera es utilizar un indicador integrado en el terminal de cliente o utilizar un indicador personalizado que ya existe mediante las funciones iCustom() o IndicatorCreate().

Primera manera. Añadir una representación gráfica

En esta manera de creación de un indicador, vamos a analizar en detalle el ejemplo de perfeccionamiento del indicador True_Strength_Index_ver3 a partir del artículo "Aplicar un indicador a otro indicador". Vamos a añadir una línea de señal con la posibilidad de escoger el tipo y el período del suavizado para el indicador. El proceso entero consiste en 8 etapas.

1. Hacer una copia del archivo

Abre el indicador True_Strength_Index_ver3 en el MetaEditor y guárdalo con un nuevo nombre, por ejemplo, TSIs. Hay que guardar el nuevo archivo en la carpeta MQL5/Indicators de la carpeta raíz del terminal.

2. Cambiar las propiedades del indicador

Busca las propiedades indicator_buffers y indicator_plots en el código del indicador. La propiedad indicator_buffers define el número total de los buffers de indicadores y la propiedad indicator_plots indica el número de buffers que se muestran en el gráfico. De momento se usan ocho buffers en el indicador; uno de ellos se muestra en el gráfico. Tenemos que añadir otro buffer que debe mostrarse en el gráfico. Incrementa los valores de indicator_buffers y indicator_plots en uno.

#property indicator_buffers 8 
#property indicator_plots 2

3. Definir las propiedades de visualización del nuevo buffer

Definir las propiedades de visualización del nuevo buffer. Utiliza el código ya existente de este indicador. Mediante el ratón, copia todo el código que define las propiedades de visualización de la primera línea del indicador.

//---- dibujar de TSI
#property indicator_label1 "TSI"
#property indicator_type1 DRAW_LINE
#property indicator_color1 Blue
#property indicator_style1 STYLE_SOLID
#property indicator_width1 1

inserta el código debajo de las propiedades de la primera línea y cámbialo.

//---- dibujar las señal TSI
#property indicator_label2 "TSISignal" // El nombre de línea que se muestra en una ventana emergente de ayuda al pasar el ratón encima de la línea 
#property indicator_type2 DRAW_LINE    // Tipo de buffer 
#property indicator_color2 Red         // Color de la línea
#property indicator_style2 STYLE_SOLID // Estilo
#property indicator_width2 1           // Grosor de la línea

Antes que nada, cambia el número de propiedades de 1 a 2, ya que se trata de la propiedad del segundo buffer. Cambia la propiedad indicator_label2 a TSISignal -es el nombre de la línea que se muestra en la ventana emergente de ayuda al pasar el ratón encima de la línea y también el nombre que se muestra en la ventana de datos. No hay que cambiar nada en la propiedad indicator_type2, el buffer debe aparecer como una línea. Cambia la propiedad indicator_color2 a Red - la nueva línea tendrá el color rojo. La propiedad indicator_style2 se queda tal cual -la línea de señal es sólida igual que la primera. La propiedad indicator_width2 no debe cambiar tampoco -la nueva línea tendrá un grosor de 1 píxel.

4. Declarar de la variables externas

Las variables externas que se pueden cambiar a través del indicador (líneas que empiezan con la palabra "input") se encuentran debajo de las propiedades de las líneas del código. La línea de señal debe tener sus propios parámetros - período y tipo de suavizado.

Declara una variable externa del tipo int con el valor 5 y llámala "sp" (smoothing period), y una variable del tipo ENUM_MA_METHOD llamada "sm" (smoothing method) con el valor MODE_EMA (la línea de señal tendrá un período de suavizado 5 y un tipo de suavizado predeterminado exponencial). Esta es la parte del código que contiene las variables externas:

input int r=25;
input int s=13;
input int sp=5;
input ENUM_MA_METHOD sm=MODE_EMA;

5. Declarar un array para un nuevo buffer

Vamos a declarar un array que va a utilizar el buffer del indicador. Busca la función OnInit() en el código y localiza las llamadas de la función SetIndexBuffer() para guiarte a través de los arrays de los buffers de indicadores que ya existen. En el indicador True_Strength_Index_ver3 estos arrays son TSIBuffer, MTMBuffer, AbsMTMBuffer, EMA_MTMBuffer, EMA2_MTMBuffer, EMA_AbsMTMBuffer y EMA2_AbsMTMBuffer.

Se llama a la función SetIndexBuffer() del array TSIBuffer con el parámetro INDICATOR_DATA, lo que significa que este buffer se muestra en el gráfico. Se llama a todos los demás arrays con el parámetro INDICATOR_CALCULATIONS. Esto significa que los arrays son complementarios y que se usan para los cálculos intermedios.

El nuevo buffer debe aparecer en el gráfico, así que vamos a declararlo después de declarar el array de TSIBuffer para mantener el orden lógico y una navegación más fácil por el código en el caso de futuras mejoras del indicador.

Por lo tanto, primero declaramos dos arrays para los buffers que se muestran en el gráfico, y después para los buffers utilizados en los cálculos intermedios.

//--- buffers de indicadores
double TSIBuffer[];
double TSISigBuffer[]; // Array para un nuevo buffer de la línea de señal
double MTMBuffer[];
double AbsMTMBuffer[];
double EMA_MTMBuffer[];
double EMA2_MTMBuffer[];
double EMA_AbsMTMBuffer[];
double EMA2_AbsMTMBuffer[]; 

6. Asociar un Array con un Buffer

Este es un momento crucial y requiere una especial atención y cuidado -asociar un array con un buffer de indicador. Se lleva a cabo la asociación mediante la función SetIndexBuffer(). El primer parámetro de la llamada de la función es el índice del array; el segundo es el nombre del array; el tercero -un identificador que indica el propósito del buffer. Los buffers se ubican en la pestaña "Colores" de la ventana de propiedades del indicador en función del índice (el primer parámetro), en el mismo orden se dibujan en un gráfico, primero el buffer 0, luego el buffer 1 encima, etc.

No hace falta llamar a la función SetIndexBuffer() de manera secuencial para los buffers con los índices 0,1,2,..., pero aún así, vamos a mantener el orden de llamadas de las funciones SetIndexBuffer(). Ejecuta la llamada del array TSISigBuffer después de llamar la función para el array TSIBuffer. El buffer de la línea principal (el array TSIBuffer) tiene un índice 0, lo que quiere decir que el siguiente buffer (el array TSISigBuffer) debe tener un índice 1.

El tercer parámetro de la llamada a la función SetIndexBuffer() para el array es la constante INDICATOR_DATA (se muestra el buffer en el gráfico).

SetIndexBuffer(0,TSIBuffer,INDICATOR_DATA);
SetIndexBuffer(1,TSISigBuffer,INDICATOR_DATA);

Volver a indexar el resto de los buffers para que la función SetIndexBuffer() sea llamada de forma compatible con el incremento del valor del primer parámetro.

SetIndexBuffer(0,TSIBuffer,INDICATOR_DATA);
SetIndexBuffer(1,TSISigBuffer,INDICATOR_DATA);
SetIndexBuffer(2,MTMBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(3,AbsMTMBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(4,EMA_MTMBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(5,EMA2_MTMBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(6,EMA_AbsMTMBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(7,EMA2_AbsMTMBuffer,INDICATOR_CALCULATIONS);

Para este caso concreto se recomienda mantener la secuencia de llamadas a la función SetIndexBuffer() de acuerdo con el incremento de los índices. Por lo tanto, en el caso de nuevas mejoras haría falta menos atención y trabajo.

Ahora tenemos ocho buffers, dos de ellos se muestran en el gráfico. Asegúrate de que se han especificado los mismos valores en las propiedades de los indicadores indicator_buffers y indicator_plots (etapa 2).

7. Calcular los valores de la línea de señal

La línea de señal representa un promedio móvil basado en los datos de la línea principal del indicador. No tenemos que hacer ningún cálculo para ello; la entrega del terminal de cliente incluye una librería para el cálculo de los promedios móviles en un array de datos (el archivo MovingAverages.mqh). Que por cierto, ya está incluido en el código del indicador (línea 14):

#include <MovingAverages.mqh>

Lo único que queda por hacer es utilizar sus características.

Encuentra en la función OnCalculate() un punto donde los cálculos de la línea principal del indicador se han terminado (el array TSIBuffer). Vamos a utilizar la función de búsqueda; selecciona el nombre del array TSIBuffer, por ejemplo, en la parte del código donde está declarado (fig. 1). A continuación, ejecuta en el MetaEditor desde "Barra de herramientas" - "Editar" - "Buscar y reemplazar" - "Buscar" o mediante la combinación de teclas Ctrl+F


Fig. 1. El nombre elegido del array.

La palabra "TSIBuffer" ya está escrita en el campo "Buscar Siguiente" de la ventana abierta de "Buscar". Selecciona "Arriba" en la parte de "Dirección". Ahora, cuando la ventana "Buscar" está abierta, pon el cursor justo después de la función OnCalculate(), pulsa el botón "Buscar Siguiente" una vez y encontrarás la ubicación donde se llevan a cabo los cálculos del array TSIBuffer. Los cálculos se llevan a cabo en el bucle "for". Añadiremos el código para el cálculo de la línea de señal justo después de este bucle (fig. 2).


Última ubicación encontrada del cálculo del valor de TSIBuffer (flecha roja). El bucle donde se llevan a cabo los cálculos está señalado con un marco rojo.
Fig. 2. Última ubicación encontrada del cálculo del valor de TSIBuffer (flecha roja). El bucle donde se llevan a cabo los cálculos está señalado con un marco rojo.

Las funciones para el cálculo de los cuatro principales tipos de promedios móviles están incluidas en la librería MovingAverages.mqh:

Todas estas funciones tiene el mismo conjunto de parámetros: 

const int rates_total, const int prev_calculated, const int begin, const int period, const double& price[],double& buffer[]

El parámetro price[] de la función define un array con los datos iniciales para el cálculo del promedio móvil que se llevará a cabo. El parámetro buffer es el array que va a almacenar los valores del promedio móvil. Los parámetros rates_total y prev_calculated son idénticos a los parámetros rates_total y prev_calculated de la función OnCalculate(), definen el tamaño del array price[] y el número de los elementos ya procesados del array. El parámetro begin es el índice de un elemento del array a partir del cual los datos empiezan a ser relevantes. 

Teniendo en cuenta las peculiaridades de los algoritmos de cálculo de los promedios móviles en la librería MovingAverages.mqh (estas características no son relevantes para el tema de este artículo), necesitamos definir el parámetro begin de manera cuidadosa.

No se debe apuntar en ningún caso este parámetro a un elemento del array que sea anterior al elemento desde el cual comienzan los valores de los datos de origen (el array TSIBuffer). Se permite especificar un elemento posterior si no da lugar a errores en los cálculos.

Para definir un valor aceptable de begin, presta atención a los parámetros del bucle for , donde se calculan los valores del array TSIBuffer - el bucle empieza desde el valor de la variable start. Necesitamos averiguar el valor la variable start durante el primer cálculo del indicador (cuando el valor de prev_calculated es igual a 0). El valor de la variable "start" se calcula justo antes del bucle, cuando prev_calculated=0; los cálculos se llevan a cabo mediante la siguiente fórmula:

start=begin+r+s-1;

El valor de la variable begin que se ha transmitido a la función de cálculo de los promedios móviles debe ser igual a este valor.

Después del bucle del cálculo del array TSIBuffer, declara la variable begin2 y le asignas el valor begin+r+s-1.

int begin2=begin+r+s-1; 

Para poder permitir el uso de distintas funciones de suavizado en función del valor del parámetro externo "sm", utiliza el operador switch operator. Para cada variante del valor de la variable sm,escribe la llamada de la correspondiente función.

switch(sm)
  {
   case MODE_EMA:
      ExponentialMAOnBuffer(rates_total,prev_calculated,begin2,sp,TSIBuffer,TSISigBuffer);
      break;
   case MODE_LWMA:
      LinearWeightedMAOnBuffer(rates_total,prev_calculated,begin2,sp,TSIBuffer,TSISigBuffer);
      break;
   case MODE_SMA:
      SimpleMAOnBuffer(rates_total,prev_calculated,begin2,sp,TSIBuffer,TSISigBuffer);
      break;
   case MODE_SMMA:
      SmoothedMAOnBuffer(rates_total,prev_calculated,begin2,sp,TSIBuffer,TSISigBuffer);
      break;
  }

Después de eso podemos ver el indicador con la línea de señal. Pulsa el botón "Compilar", abre el terminal de cliente y asocia el indicador a un gráfico (fig. 3).



Fig. 3. Línea de señal del indicador, azul -línea principal, rojo -nueva.

8. Truncar el inicio del dibujo del buffer

Si te desplazas por el gráfico del indicador hacia la izquierda, veras que el indicador dibuja unas líneas en la parte en la que no se han calculado los valores. No ofrece una buena estética (fig. 4).



Fig. 4. Representación del indicador en la parte en la que no se lleva a cabo el cálculo. 

Mediante la función PlotIndexSetInteger() a la que se llama con el identificador PLOT_DRAW_BEGIN, define el número de las primeras barras en las que no se dibuja el buffer. La llamada a la función debe realizarse desde la función OnInit() del indicador. Añade la llamada de la función al final de OnInit(), pero por supuesto, antes de la llamada de return(0).

PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,r+s+sp);

Pulsa el botón "Compilar" otra vez y consigue un inicio correcto del dibujo del indicador (fig. 5).  



Fig. 5. Corrección del comienzo de la representación del indicador. 

Segunda manera. Creación de un indicador a partir de uno que ya existe


Analizaremos está manera mediante el ejemplo de creación de un indicador de convergencia y divergencia de las líneas principal y de señal del indicador TSIs. Se representa el indicador en forma de histograma y tendrá dos colores al igual que los indicadores AO, AC. Si el valor del indicador aumenta, el histograma será de color verde; si disminuye será de color rojo. Como ya se ha comentado en la introducción, para hacer referencia a otro indicador puedes utilizar la función iCustom() o IndicatorCreate(). Primero, echemos un vistazo a la creación de un indicador mediante la función iCustom().

Crear un indicador mediante la función iCustom()


1. Crear un nuevo indicador

Vamos a crear un nuevo indicador. Para crear un nuevo indicador en MetaEditor hay que ejecutar desde la "Barra de herramientas" - "Archivo" - "Nuevo" - "Indicador personalizado" o mediante la combinación de teclas "Ctrl+N". En el campo "Nombre" de la ventana que se abre, especifica el nombre del nuevo indicador - TSIsCDiCust, y luego pulsa el botón "Añadir". Añade un parámetro externo, su nombre sirve sólo para indicar la parte de los parámetros externos en el código; asimismo será más fácil copiar todos los parámetros externos desde el indicador TSIs (fig. 6).


Primer paso para crear un indicador personalizado con el asistente.
Fig. 6. Primer paso para crear un indicador personalizado con el asistente.

Pulsa el botón "Siguiente".

En la siguiente ventana, especifica que el indicador se va a representar en una ventana separada. No indiques ni mínimo ni máximo. Pulsa el botón "Añadir" y se mostrará un nuevo buffer en la lista de buffers de indicadores; indica su nombre - TSIsCD (se mostrará en una ventana emergente al pasar el ratón por encima de la línea del indicador y en la ventana de datos) y su tipo - Color Histogram.

A continuación, aparecerán varios ejemplos de color en el campo "Colores". Indica el color Green para el primer ejemplo, el rojo para el segundo, y no cambies los otros. Añade dos buffers más, llamados Tsi y TsiSignal, se van a utilizar para recibir y almacenar los valores del indicador TSIs (fig. 7).


Segundo paso para crear un indicador personalizado con el asistente. 
Fig. 7. Segundo paso para crear un indicador personalizado con el asistente.

Pulsa el botón "Finalizar" y se abrirá la plantilla del nuevo indicador en MetaEditor.

2. Modificar las propiedades del indicador y de los buffers de indicadores

En la etapa 1 hemos definido 3 buffers; sin embargo, el valor de #property indicator_buffers es igual a 4. La cuestión es que el histograma en color usa dos buffers - uno se muestra en el gráfico y se usa para los valores del indicador; y el otro se usa para definir los colores de representación del primer buffer. No cambies el valor de #property indicator_buffers. Cambia el valor de #property indicator_plots a 1 - se debe mostrar un sólo buffer en el gráfico.

Los buffers Tsi y TsiSignal no deben aparecer en el gráfico, por eso elimina todas sus propiedades (todas la propiedades del indicador que acaban con 2 y 3).

//--- dibujar Tsi
#property indicator_label2 "Tsi"
#property indicator_type2 DRAW_LINE
#property indicator_color2 Red
#property indicator_style2 STYLE_SOLID
#property indicator_width2 1
//--- dibujar TsiSignal
#property indicator_label3 "TsiSignal"
#property indicator_type3 DRAW_LINE
#property indicator_color3 Red
#property indicator_style3 STYLE_SOLID
#property indicator_width3 1
Encuentra en la función OnInit() las llamadas de la función SetIndexBuffer() a estos buffers (los nombres de los arrays son TsiBuffer y TsiSignalBuffer), cambia el valor del tercer parámetro de INDICATOR_DATA a INDICATOR_CALCULATIONS.
SetIndexBuffer(2,TsiBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(3,TsiSignalBuffer,INDICATOR_CALCULATIONS);

Cambia la propiedad de indicator_color1 - deja sólo los dos primeros colores. 

#property indicator_color1 Green,Red

3. Declaración de los parámetros externos

Abre el indicador TSIs en MetaEditor y copia todas sus variables externas, sustituye la actual variable externa Input1 por estos parámetros.

//--- parámetros de entrada
input int r=25;
input int s=13;
input int sp=5;                 // período de suavizado
input ENUM_MA_METHOD sm=MODE_EMA; // tipo de suavizado

4. Declarar una variable para controlar y llamar el indicador

Declara en la parte general del indicador una variable de tipo int y llámala Handle. Llama la función iCustom() al final de OnInit(). La función devuelve el control del indicador que hemos creado; nos hace falta para recibir los valores del indicador. Asigna el valor que nos ha devuelto la función a la variable Handle.

Los dos primeros parámetros de la función iCustom() definen el símbolo y el período de tiempo utilizados en los cálculos del indicador. Vamos a definir un símbolo y un período de tiempo para el indicador - _Symbol y PERIOD_CURRENT. El tercer parámetro es el nombre del indicador personalizado; en este caso es TSIs. Todos los parámetros externos del indicador llamado se enumeran más adelante:

Handle=iCustom(_Symbol,PERIOD_CURRENT,"TSIs",r,s,sp,sm);

5. Preparar la función OnCalculate()

Vamos a pasar a la función OnCalculate(). Se calcula el indicador TSIs con los datos de un buffer, así que usaremos la primera forma de la función InCalculate(). Cambia función OnCalculate() de la segunda forma que está en la plantilla a su primera forma.

int OnCalculate(const int rates_total,         // tamaño del array price[]
                const int prev_calculated,   // barras procesadas durante la llamada anterior
                const int begin,             // a partir de donde empiezan los datos relevantes
                const double &price[]        // array para los cálculos
                )
  {
   return(rates_total);
  }

Se llevarán a cabo más trabajos del indicador dentro de esta función.

6. Definir los límites de los cálculos del indicador

Lo más importante y prioritario en el desarrollo de un indicador es definir los límites del rango de barras procesadas. Al inicio del indicador debemos llevar a cabo el cálculo del indicador para cada barra, durante su ejecución - sólo para la que está actualmente formada. Puedes identificar el momento de inicio del indicador a través del valor de la variable prev_calculated. Si este valor es igual a cero, entonces es la primera ejecución de la función OnCalculate() desde que se inició el indicador.

En la primera ejecución de la función OnCalculate() debes definir el índice de la primera barra a partir de la cual deben empezar los cálculos. Su valor viene determinado por el número de barras necesarias para el cálculo del valor del indicador (la indexación se lleva a cabo de izquierda a derecha).

La pendiente de la línea del indicador requiere dos barras, así que necesitamos otra barra anterior. El índice de una barra, a partir de la cual empiezan los datos relevantes del array price[], es conocido - es el valor de la variable begin; por lo tanto comenzamos el cálculo de las barras desde la barra start=begin+1.

Además, durante la ejecución del indicador, el índice de la barra a partir de la cual empiezan los cálculos viene determinado por el valor de la variable prev_calculated - esta variable contiene el número de las barras ya procesadas. Por lo tanto, para averiguar el índice de la última barra en la cual se han llevado a cabo cálculos, debes restar 1 a prev_calculated.

Se tomará la última de las barras ya procesadas en los nuevos cálculos ya que puede ser una barra en proceso de formación. El límite de los cálculos viene determinado por el tamaño del array price[] - la variable rates_total. El índice de la última barra por la cual se hicieron los cálculos es igual a rates_total-1 (es el tamaño del array menos uno).

Puesto que el indicador usa los datos de otro indicador para sus cálculos, necesitamos estos datos. Puedes obtener los datos de otro indicador mediante la función CopyBuffer(). En el primer parámetro de la función debes especificar el control del indicador, el dato que hay que copiar (control se obtiene en la etapa 4); en el segundo parámetro tienes que especificar el índice del buffer copiado (Se puede determinar este valor necesario a través de la pestaña "Colores" de las propiedades del indicador copiado, la cuenta empieza desde cero).

El tercer parámetro es el índice de la barra a partir de la cual se empieza a copiar; en este caso, se lleva a cabo la indexación de derecha a izquierda, con lo cual el cero corresponde a la barra más a la derecha. El cuarto parámetro es el número de elementos a copiar del array. Hay que tener cuidado al determinar el número de elementos a copiar así que el rango de barras a tener en cuenta en el cálculo. Esto afecta el rendimiento del indicador. El índice de la barra a partir de la cual empieza el cálculo del indicador se define previamente, así que se calcula el número de elementos copiados como rates_total-start. Durante el proceso de funcionamiento, se copia solamente un elemento del array cuando se lleva a cabo el cálculo solamente para la barra en proceso de formación.

El hecho de que la función CopyBuffer() devuelva -1 cuando intenta copiar los datos, significa que no se han podido copiar los datos, así que no tiene sentido realizar los cálculos. Hay que tratar este error. Al principio CopyBuffer() declara una variable estática de tipo booleano y le asigna el nombre "error". Si ocurre un error durante el proceso de cálculo del indicador, en particular el error de la copia de datos del indicador, asigna el valor True a esta variable y detener el proceso de ejecución de la función OnCalculate().

Vuelve a calcular todo el indicador al siguiente tick si el valor del error indica que hubo un error durante la ejecución anterior de la función OnCalculate(). Por lo tanto, el principio de la función OnCalculate será así:

   static bool error=true; 
   int start;
   if(prev_calculated==0) // Primera ejecución de la función OnCalculate() después del inicio del indicador
     {
      error=true; // Poner True al indicador a calcular para todas las barras
     }
   if(error) // si el valor de error=true, entonces es la primera ejecución de la función después 
             // del inicio del indicador, o hubo un error en la copia de los datos durante el inicio anterior
     {
      start=begin+1;
      error=false;
     }
   else
     {
      start=prev_calculated-1;
     }

   if(CopyBuffer(Handle,0,0,rates_total-start,TsiBuffer)==-1) // Copiar datos de la línea principal del indicador
     {
      error=true; // Fallo en la copia de los datos, poner el valor True a la variable error para calcular de nuevo
                 // todo el indicador a la siguiente llamada de OnCalculate()
      return(0);  // Fin del proceso de la función
     }
   if(CopyBuffer(Handle,1,0,rates_total-start,TsiSignalBuffer)==-1) // Copiar los datos de la línea de la señal al indicador
     {
      error=true; // Fallo en la copia de los datos, poner el valor True a la variable error para calcular de nuevo
                 // todo el indicador a la siguiente llamada de OnCalculate()
      return(0);  // Fin del proceso de la función
     }

Se han definido los límites de cálculo del indicador, haz un bucle de cálculos en este rango de barras.

for(int i=start;i<rates_total;i++)
  {

  }

Calcula el valor del indicador (el código se encuentra dentro del bucle recién creado).

TsiCDBuffer[i]=TsiBuffer[i]-TsiSignalBuffer[i];

Ahora la parte más divertida - colorear el buffer. Anteriormente en la etapa 1 hemos optado por el uso de un histograma en color para el buffer del indicador. Este tipo de dibujos requiere dos buffers - uno para el valor del indicador y el otro para el color. La lista de colores está establecida en la propiedad indicator_color1. Cuando el valor del elemento del buffer es 0, se muestra el indicador con color verde; si el valor es 1, el indicador es rojo (según su ubicación en indicator_color1 en la lista; la numeración empieza desde cero)

Es imposible evitar el caso de unos valores iguales del indicador en dos barras adyacentes; en este caso, el indicador debe mostrarse con el color anterior (porque sólo tenemos dos colores para los movimientos hacia arriba y abajo). Por lo tanto, al principio de los cálculos copiaremos el valor del buffer TsiCDColors de la barra anterior: 

TsiCDColors[i]=TsiCDColors[i-1];

Para los movimientos hacia arriba asigna al indicador el color Green:

if(TsiCDBuffer[i]>TsiCDBuffer[i-1])TsiCDColors[i]=0;

Para los movimientos hacia abajo asigna al indicador el color Red:

if(TsiCDBuffer[i]<TsiCDBuffer[i-1])TsiCDColors[i]=1;

Esto nos lleva casi al final del proceso del indicador; queda por determinar el inicio de la representación del indicador.

7. Finalizar el proceso del indicador 

El hecho de que la variable begin se usa para determinar el cálculo del indicador, no significa que los datos del indicador empiezan desde la barra identificada con la variable begin. Si se desconoce el algoritmo del indicador personalizado, es casi imposible identificar el número de barras necesarias para el cálculo del indicador. Por lo que se puede saltar esta etapa o detectar un valor basándote en la experiencia. Sin embargo, conocemos el algoritmo del indicador TSIs, y por lo tanto podemos detectar de manera exacta el inicio del indicador. Añade la llamada de la función PlotIndexSetInteger() con el identificador PLOT_DRAW_BEGIN a la función OnInit()

PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,r+s+sp);

El indicador TSIs muestra unos valores precisos con dos decimales; establece la misma precisión mediante la función IndicatorSetInteger() con el identificador INDICATOR_DIGITS:

IndicatorSetInteger(INDICATOR_DIGITS,2);

Compila el indicador y lo asocias al gráfico (fig. 8).

 
Fig. 8. El indicador TSIsCDiCust.

Crear un indicador mediante la función IndicatorCreate() 


La creación de un indicador mediante la función IndicatorCreate() es igual a su creación mediante la función iCustom(), excepto la etapa 4 - se usa la función IndicatorCreate() en lugar de iCustom().

1. Guarda una copia del indicador TSIsCDiCust con el nombre TSIsCDiCreate.

2. Encuentra donde se llama a la función iCustom() en el código. A partir de ahora se llevará cabo la llamada de la función IndicatorCreate() en lugar de iCustom(). Al igual que en iCustom(), los dos primeros parámetros de la función IndicatorCreate() definen el símbolo y el período de tiempo utilizados en el cálculo del indicador. El tercer parámetro es un identificador del tipo de indicador, para un indicador personalizado es IND_CUSTOM. Se pasan los parámetros de creación del indicador a la función mediante el array de estructuras MqlParam.

El array MqlParam contiene cuatro variables - tres de ellas para los distintos tipos de variables y se usan para los valores: double_value, integer_value and string_value; y la otra es type, define el tipo de variable que se utiliza. El indicador TSIs tiene cuatro parámetros externos. Puesto que se trata de un indicador personalizado, el primer elemento del array define el nombre del indicador personalizado, por lo tanto, el array debe tener cinco elementos. Declara un array de estructuras (en la ubicación de la llamada a iCustom() se encuentra el código):

MqlParam Params[5];

Rellena el array con los valores:

   Params[0].type=TYPE_STRING;
   Params[0].string_value="TSIs"; // Especificar el nombre del indicador personalizado llamado en el primer parámetro
   
   Params[1].type=TYPE_INT;
   Params[1].integer_value=r;
   
   Params[2].type=TYPE_INT;
   Params[2].integer_value=s;   
   
   Params[3].type=TYPE_INT;
   Params[3].integer_value=sp;      
   
   Params[4].type=TYPE_INT;
   Params[4].integer_value=sm;  

Ya hemos visto los tres primeros parámetros que se pasan a la función IndicatorCreat(). El cuarto parámetro recibe el tamaño del array de los parámetros; el último es el array con los parámetros en si:

Handle=IndicatorCreate(_Symbol,PERIOD_CURRENT,IND_CUSTOM,5,Params);

Sólo nos queda pulsar el botón "Compilar" y comprobar el indicador en el terminal de cliente.

Conclusión

Hagamos una breve reseña de los principales puntos a los que debes prestar especial atención a la hora de crea un indicador personalizado basado en otro indicador.

A la hora de mejorar un indicador, debes especificar correctamente el número de buffers y el número de buffers a dibujar (las propiedades de indicator_buffers, indicator_plots); debes definir las propiedades de los nuevos buffers (las propiedades de indicator_label, indicator_type, indicator_color, indicator_style, indicator_width). A la hora de llamar a la función SetIndexBufer() para los nuevos buffers, debes indicar el valor correcto del tercer parámetro (INDICATOR_DATA o INDICATOR_CALCULATIONS); e indicar correctamente los valores del primer parámetro (índice del buffer); volver a indexar los buffers si hace falta.

A la hora de crear un nuevo indicador mediante otro indicador personalizado, Debes pasar correctamente los parámetros a la función iCustom(); y rellenar la estructura de parámetros al utilizar la función IndicatorCreate(). Aquí también debes fijarte en especificar correctamente los parámetros la llamar a la función SetIndexBuffer(); y lo más importante es no olvidar realizar la llamada a la función SetIndexBuffer() para los nuevos buffers.

Cada vez que trabajas con indicadores, debes prestar atención al establecimiento del rango de cálculo de las barras - usa las variables prev_calculated, rates_total, begin. MetaEditor te ayudará a resolver los otros errores que puedan surgir durante la programación (los mensajes de los errores que surgen durante la compilación se muestran en la pestaña "Errores").