Cómo llamar a los indicadores en MQL5

KlimMalgin | 16 diciembre, 2013

Introducción

En MQL5 existen varias formas de llamar a los indicadores y la mayoría de ellas usan las funciones IndicatorCreate() y iCustom(). Además, estas funciones solo devuelven el controlador (handle) del indicador para, posteriormente, realizar sobre él las demás operaciones. ¿Qué es un controlador (handle)? ¿Cómo utilizar las funciones IndicatorCreate() y iCustom()? Y ¿cómo puede su experto obtener los datos de su indicador? Todas estas cuestiones se tratan en este artículo.

Crear un archivo fuente.

Para empezar con nuestro experto vamos a crear su archivo fuente. Vamos a proceder de manera muy similar a como hacíamos en Meta Trader 4 llamando al MQL5 Wizard desde el menú Archivo -> Nuevo. En primer lugar seleccionamos Asesor Experto y pulsamos Siguiente.


A continuación, el sistema nos pedirá el nombre, los datos de contacto del autor y los parámetros de entrada del asesor experto. Introduzca el nombre del asesor (dato requerido) y el autor. Posteriormente podrá añadir parámetros de entrada directamente en el código si es necesario.


Tras hacer clic en Finalizar, el Asistente creará el siguiente código fuente:

//+------------------------------------------------------------------+
//|                                                   SampleMQL5.mq5 |
//|                                             Copyright KlimMalgin |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "KlimMalgin"
#property link      ""
#property version   "1.00"
//+------------------------------------------------------------------+
//| Función de inicialización del Expert                             |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Función de deinicialización del Expert                           |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Función tick del Expert                                          |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
  }
//+------------------------------------------------------------------+

Estructura del archivo fuente

Vamos a examinar brevemente la estructura del archivo fuente de un experto y profundizar un poco más.

El código del programa comienza con un encabezado. Se trata de un comentario que contiene el nombre del archivo y del autor. A continuación del título nos encontramos con las Propiedades del Programa (#property) de un experto. Aquí, la versión del programa se indica automáticamente, así como el nombre del autor y el enlace a su página en caso de haber introducido estos datos. Después de describir las propiedades, se introducen los parámetros de entrada (aún no los hemos introducido) y se declaran las variables globales.

Debe recordar que las propiedades deben establecerse en el archivo mql5 principal. ¡Todas las propiedades de los archivos incluidos serán ignoradas!

A continuación nos encontramos con tres funciones que procesan los eventos:

Conectar indicadores

En MQL5, ¡los métodos de trabajo con indicadores han cambiado! En MQL4, para obtener el valor del indicador en una barra concreta, el índice de dicha barra se pasaba a la función iCustom() como parámetro. Ahora no es necesario obtener el valor del buffer del indicador sino solo su controlador. Por medio de este controlador podemos obtener los valores de los indicadores para un intervalo gracias a una función especial llamada CopyBuffer(). Pero ¿qué es un controlador?

Un controlador es un identificador único creado para su uso con ciertos indicadores. Se representa como un entero y se almacena en el tipo int de la variable. Hay dos formas de obtener el controlador del indicador en MQL5:

Ambos métodos son igualmente válidos y la decisión sobre el uso de uno u otro es solo suya. A continuación vamos a ver ambos métodos en mayor profundidad.

Obtener el controlador del indicador usando la función IndicatorCreate().

Como resultado de la ejecución con éxito de la función IndicatorCreate() vamos a obtener el controlador del indicador y, en caso de fallo de la función, ésta devolverá el valor INVALID HANDLE igual a -1. Si el indicador que ha sido llamado tiene parámetros, antes de llamar a la función debemos introducir una matriz de parámetros del tipo MqlParam. Cada elemento de esta matriz se representa como una estructura del tipo MqlParam con cuatro campos. El primer campo de esta estructura indica cuál de los restantes tres campos se usa como parámetro para el indicador.

Vamos a escribir el código que creará los controladores de los indicadores Media Móvil y SAR parabólico. Comenzaremos declarando las variables globales que almacenarán los controladores y también declararemos una matriz del tipo MqlParam para poder establecer los parámetros para los indicadores:

int MA1 = 0,            // Declarando la variable para almacenar rápidamente el controlador MA 
    MA2 = 0,            // Declarando la variable para almacenar lentamente el controlador MA 
    SAR = 0;            // Declarando la variable para almacenar el controlador SAR 
    
MqlParam params[];      // Matriz para almacenar los parámetros de los indicadores

Este código puede introducirse inmediatamente después de definir las propiedades del experto.

Una vez que las variables se han declarado, podemos introducir la matriz de parámetros y llamar a la función IndicatorCreate(). Es mejor hacer esto en la función OnInit(), ya que el indicador se creará una vez al inicio del programa ¡y no con cada tick!

Vamos a introducir la matriz de parámetros y llamar al primer indicador:

int OnInit()
{
//---
   // Estableciendo el tamaño de params igual al número de parámetros de indicador llamados
   ArrayResize(params,4);

   // Estableciendo el período de MA rápido
   params[0].type         =TYPE_INT;
   params[0].integer_value=5;
   // Offset
   params[1].type         =TYPE_INT;
   params[1].integer_value=0;
   // Método de cálculo: promedio simple
   params[2].type         =TYPE_INT;
   params[2].integer_value=MODE_SMA;
   // Tipo de precio para el cálculo: Los precios Close 
   params[3].type         =TYPE_INT;
   params[3].integer_value=PRICE_CLOSE;
   
   MA1 = IndicatorCreate(Symbol(), // Símbolo usado para calcular el indicador
                         0,        // Período de tiempo. 0 means current
                         IND_MA,   // Tipo de indicador de la enumeración ENUM_INDICATOR 
                         4,        // Número de parámetros usados en la matriz params
                         params    // Matriz de parámetros
                         );   
//---
return(0);
}

Como la matriz params ha sido declarada como matriz dinámica, es decir, el tamaño de la matriz no se estableció entre corchetes, antes de usarla debemos establecer su tamaño. Usando la función ArrayResize() podremos definir el tamaño igual al número de parámetros que luego asignaremos a la matriz. Para la media móvil se necesitan cuatro parámetros.

El primer parámetro es el período MA. Se establece como un entero. Por tanto, al campo type del primer parámetro le asignaremos el valor TYPE_INT, y de esta forma nuestra función IndicatorCreate() "comprenderá" que el valor debe ser tomado del campo integer_value. Al ser todos los parámetros de la media móvil del tipo int, estos se establecerán adecuadamente.

Una vez que se ha introducido la matriz, podemos llamar a la función IndicatorCreate(). Su salida será almacenada en la variable MA1. No debemos encontrar dificultades al llamar a la función y es preciso asignar a esta cinco parámetros:

¡Y eso es todo! Tenemos el controlador MA rápido y hemos de obtener el MA lento y los controladores de indicadores SAR. Como resultado, la función OnInit() se mostrará de la siguiente forma:

int OnInit()
  {
//---

   // Estableciendo el tamaño de params igual al número de parámetros de indicador llamados
   ArrayResize(params,4);

//*    Llamando a los indicadores   *
//***************************
   // Estableciendo el período del MA rápido
   params[0].type         =TYPE_INT;
   params[0].integer_value=5;
   // Offset
   params[1].type         =TYPE_INT;
   params[1].integer_value=0;
   // Método de cálculo: simple promedio
   params[2].type         =TYPE_INT;
   params[2].integer_value=MODE_SMA;
   // Tipo de precio para el cálculo: los precios Close 
   params[3].type         =TYPE_INT;
   params[3].integer_value=PRICE_CLOSE;
   
   MA1 = IndicatorCreate(Symbol(), 0, IND_MA, 4, params);
   
   // Estableciendo el período del MA lento
   params[0].type         =TYPE_INT;
   params[0].integer_value=21;
   // Offset   
   params[1].type         =TYPE_INT;
   params[1].integer_value=0;
   // Método de cálculo: simple promedio
   params[2].type         =TYPE_INT;
   params[2].integer_value=MODE_SMA;
   // Tipo de precio para el cálculo: los precios Close 
   params[3].type         =TYPE_INT;
   params[3].integer_value=PRICE_CLOSE;
   
   MA2 = IndicatorCreate(Symbol(), 0, IND_MA, 4, params);
   
   
   // Cambiando el tamaño de la matriz para almacenar los parámetros del indicador SAR 
   ArrayResize(params,2);
   // Paso
   params[0].type         =TYPE_DOUBLE;
   params[0].double_value = 0.02;
   // Máximo
   params[1].type         =TYPE_DOUBLE;
   params[1].double_value = 0.2;
   
   SAR = IndicatorCreate(Symbol(), 0, IND_SAR, 2, params);
   
//---
   return(0);
  }

Para obtener el controlador MA lento solo podemos cambiar el período de 5 a 21. Cuando el SAR parabólico es llamado, los números de coma flotante (dobles) se transfieren a sus parámetros. Cuando introducimos la matriz debemos tener esto en cuenta y poner el valor TYPE_BOUBLE en el campo "type" y el propio parámetro en el campo "double_value". Además, el SAR requiere solo dos parámetros, de forma que el tamaño de la matriz cambie a 2 usando ArrayResize().

En este punto finaliza la función IndicatorCreate(). En mi opinión, esta forma de llamar a los indicadores es más apropiada en los enfoques orientados a objeto, en los que la librería de clases ha sido creada para trabajar con indicadores. Esta librería hará que los proyectos de grandes dimensiones sean más fáciles de procesar. Para escribir y probar los expertos rápidos es mejor usar el siguiente método.

Obtener el controlador usando funciones de indicadores técnicos.

El segundo método, que nos permitirá obtener el controlador del indicador, consiste en llamar a una de las funciones de indicadores técnicos. Cada una de estas funciones pretende obtener el controlador de uno de los indicadores estándar incluidos en Meta Trader 5. Todos ellos tienen un cierto número de parámetros dependiendo del indicador para el que estén pensados. Por ejemplo, para el indicador CCl se llama a la función iCCl() como se muestra a continuación:

   CCI = iCCI(
              Symbol(),            // nombre del símbolo
              PERIOD_CURRENT,      // período
              20,                  // período de promedio
              PRICE_CLOSE          // tipo de precio o controlador
              );

Puede utilizarse otro controlador de indicador como último parámetro en la función de indicadores técnicos en lugar del tipo precio. El indicador, una vez que ha sido llamado de esta forma, será calculado mediante el uso de los datos de otro indicador, en lugar de utilizar el precio.

La función iCustom() resulta especialmente interesante, ya que permite llamar a cualquier indicador, incluso los indicadores personalizados. Vamos a escribir un código similar al anterior pero usando la función iCustom():

int OnInit()
  {
//---

   MA1 = iCustom(NULL,0,"Custom Moving Average",
                          5,          // Period
                          0,          // Offset
                          MODE_SMA,   // Calculation method
                          PRICE_CLOSE // Calculating on Close prices
                 );

   MA2 = iCustom(NULL,0,"Custom Moving Average",
                          21,         // Period
                          0,          // Offset
                          MODE_SMA,   // Calculation method
                          PRICE_CLOSE // Calculating on Close prices
                 );

   SAR = iCustom(NULL,0,"ParabolicSAR",
                          0.02,        // Step
                          0.2          // Maximum
                 );

//---
   return(0);
  }

Debe recordarse que es mejor obtener el indicador durante el inicio del experto y, por tanto, debemos hacer la llamada en la función OnInit().

La función iCustom() contiene los siguientes parámetros:

  1. El nombre de la herramienta utilizada, dato que es usado para calcular el indicador. NULL es la herramienta actual. Puede usar Symbol () en lugar de NULL, no hay grandes diferencias. En el caso de Symbol (), se transfiere el nombre de un instrumento a iCustom(), pero en el caso de NULL, iCustom() encuentra el instrumento financiero por sí mismo.
  2. Período del gráfico. Para especificar el período podemos usar los períodos de tiempo para gráficos predefinidos, así como 0 para hacer referencia al período actual.
  3. Nombre del indicador. El indicador llamado debe ser compilado y debe encontrarse en la carpeta "MQL5\Indicators\" o en alguna de sus subcarpetas.
  4. Parámetros restantes. Estos valores se usarán como parámetros de entrada para el indicador llamado, de forma que su tipo y la secuencia deben coincidir entre ellos. Si no han sido especificados se usarán los valores por defecto.

Tal y como se ha mencionado con anterioridad - este método es más apropiado para el trabajo con indicadores si no ha usado librerías. Ahora, una vez que se han recibido los controladores, ¡podemos comenzar a trabajar con los valores de los indicadores!

Obtener los datos del indicador

Lo bueno de trabajar con datos de indicadores en MQL5 es que ahora es posible obtener los datos solo para el intervalo que necesitemos. Podemos establecer dicho intervalo de varias formas:

Para obtener la fecha del indicador se utiliza la función CopyBuffer(). El método de obtención de datos a utilizar dependerá del tipo de parámetros de entrada que van a ser transferidos a esta función.

A continuación, vamos a escribir el código que copia el dato del indicador (hemos obtenido los controladores anteriormente) en las matrices:

void OnTick()
  {
//---

// Matrices dinámicas para almacenar los valores de los indicadores
double _ma1[],
       _ma2[],
       _sar[];

// Estableciendo el indexado en las matrices de igual forma que en los períodos de tiempo, es decir, el elemento de la matriz con cero
// el índice almacenará los valores de la última barra, con el primer índice, el último excepto uno, etc.
   ArraySetAsSeries(_ma1, true);
   ArraySetAsSeries(_ma2, true);
   ArraySetAsSeries(_sar, true);

// Usando controladores de indicadores, copia los valores del indicador
// buffers a matrices, preparados específicamente para este propósito
   if (CopyBuffer(MA1,0,0,20,_ma1) < 0){Print("CopyBufferMA1 error =",GetLastError());}
   if (CopyBuffer(MA2,0,0,20,_ma2) < 0){Print("CopyBufferMA2 error =",GetLastError());}
   if (CopyBuffer(SAR,0,0,20,_sar) < 0){Print("CopyBufferSAR error =",GetLastError());}


//---
  }

Ahora, todo nuestro trabajo se centrará en la función OnTick(), ya que con cada tick cambian los datos de los indicadores y, por tanto, deben actualizarse.

En primer lugar, vamos a declarar las matrices dinámicas para cada buffer del indicador. En mi opinión, es mejor utilizar datos del indicador si el indexado de la matriz va a ser el mismo que en las series de tiempo, es decir, en el elemento 0 de la matriz habrá datos de la última barra, en el elemento número 1, el último excepto uno, etc. El método de indexado se establece mediante la función ArraySetAsSeries().

Una vez que se ha establecido el método de indexado, podemos comenzar a rellenar las matrices. Para calcular cada indicador llamaremos a la función CopyBuffer() con el siguiente conjunto de parámetros:

  1. El controlador del indicador del que queremos obtener el dato.
  2. El número del buffer del indicador. Como los indicadores MA y SAR tienen un solo buffer, les asignaremos el valor 0. Si hubiera más de un buffer, el segundo sería el número 1, el tercero el número 2, etc.
  3. La barra inicial a partir de la que se empieza a contar.
  4. El número de barras que queremos copiar.
  5. La matriz {/0} en la que el dato es copiado.

Si la llamada tiene éxito, la función CopyBuffer() devuelve el número de elementos copiados, mientras que si falla nos devolverá el valor -1. En caso de fallo, debe hacerse un seguimiento del error, de forma que si los valores devueltos son inferiores a 0 escribiremos el error en el registro de expertos mediante la función Print().

Conclusión

Llegados a este punto, nuestro trabajo con los indicadores está aún lejos de finalizar. Este artículo trata solo los métodos básicos para acceder a los datos de los indicadores. Y para una mayor comodidad, es mejor utilizar el enfoque orientado a objetos incluido en MQL5 ¡a un nivel considerable!