Descargar MetaTrader 5

Sobre nuevos raíles: Indicadores personalizados en MQL5

18 diciembre 2013, 11:55
Комбинатор
0
764

Introducción

Por fin tenemos la oportunidad de probar el nuevo terminal, Meta Trader 5. Es, sin duda, digno de mención y posee muchas características nuevas al compararlo con su predecesor. Las ventajas principales de esta plataforma son, entre otras, las siquientes:

  • Su lenguaje ha sido modificado en aspectos fundamentales, permitiendo ahora el uso de la programación orientada a objetos y manteniendo su capacidad para aprovechar las grandes ventajas de la programación estructurada.
  • La velocidad de ejecución del código, que ahora es mucho más rápida que en Meta Trader 4.
  • Aumento de la capacidad para mostrar en pantalla la información necesaria.

No voy a enumerar todas las posibilidades y características de la nueva terminal y el lenguaje. Son numerosas y algunas de ellas merecen ser tratadas en un artículo separado. Tampoco hay aquí código escrito en lenguaje de programación orientado a objeto. Es un tema demasiado importante como para ser tan solo mencionado como ventaja adicional para los programadores.

En este artículo vamos a considerar los indicadores, su estructura, diseño, tipos y detalles de su programación al compararlos con MQL4.

No hay nada complejo en este artículo y, además, todo lo que vamos a considerar aquí puede comprobarse directamente en el terminal usando los archivos adjuntos.

Espero que este artículo sea de utilidad, tanto para principiantes como para programadores experimentados. Puede que algunos de estos últimos encuentren algo nuevo.

 

La estructura general

La estructura general del indicador no ha cambiado, si se compara con MQL4.

Como antes, hay tres funciones: para inicialización, para procesamiento de datos y para la deinicialización del indicador.

Al igual que antes, muchos parámetros del indicador pueden definirse mediante propiedades (palabra clave #property). La mayoría de ellos son diseñados específicamente para indicadores. Las propiedades y parámetros de entrada se definen, al igual que antes, en un contexto global.

Como ejemplo, vamos a considerar la implementación de los colores personalizados para el indicador RSI. Esta es la versión truncada. La versión completa se encuentra en el archivo Color_RSI.mq5.

Vamos a ver las partes del código.

//--- group of data properties
#property copyright "TheXpert"
#property link      "theforexpert@gmail.com"
#property version   "1.00"
//--- description of the indicator should not exceed 511 symbols in total
//--- including newline symbols
#property description "      "
#property description "Demonstration of the indicator creation"
#property description "by the example of RSI coloring"

Las propiedades especificadas anteriormente se muestran en el panel de información del indicador (la pestaña "Común" de las propiedades). Sería de la siguiente forma:

//--- indicator properties
#property indicator_separate_window // the indicator will be displayed in a separate subwindow
#property indicator_buffers 2       // number of used buffers
#property indicator_plots   1       // number of displayed buffers
//--- plot 1
#property indicator_color1 clrDarkSalmon, clrDeepSkyBlue // use 2 colors
#property indicator_type1  DRAW_COLOR_LINE               // and the special color display type

Estas propiedades son las del indicador. La descripción de las demás propiedades puede encontrarse en la ayuda.

//---- buffers
double Values[];                 // buffer of values
double ValuesPainting[];         // buffer of color indices
//--- indicator input parameters
input string             _1           = "RSI parameters";
input int                RSIPeriod    = 5;
input int                SmoothPeriod = 5;
input ENUM_APPLIED_PRICE AppliedPrice = PRICE_CLOSE;
input string             _2           = "Color settings";
input color              Down         = clrDarkSalmon;
input color              Up           = clrDeepSkyBlue;
//--- variable for storing the indicator handle
int RSIHandle;

Estos son los parámetros de entrada del indicador y las variables globales (no confundir con las variables globales del terminal de cliente). Los parámetros de entrada del indicador se especifican con el identificador input.

Ahora, es posible establecer la enumeración para el parámetro de entrada. Algunas veces será útil para evitar la selección incorrecta de los parámetros.

Por ejemplo, el parámetro AppliedPrice se mostrará en pantalla en una lista desplegable con los valores válidos posibles.

Por tanto, todas las enumeraciones, incluidas las definidas por el usuario, se mostrarán en pantalla en la misma lista desplegable. Por ejemplo, el siguiente parámetro

//...
enum DayOfWeek
{
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
};

input DayOfWeek Day;

//...

se mostrará de la siguiente forma:

int OnInit()
  {
//--- bind indicator buffers
//--- Values serves as a display buffer
   SetIndexBuffer(0,Values,INDICATOR_DATA);
//--- ValuesPainting serves as the buffer for storing colors
   SetIndexBuffer(1,ValuesPainting,INDICATOR_COLOR_INDEX);
//--- Set the start of drawing Values buffer
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,RSIPeriod);
//--- Set the indicator name
   IndicatorSetString(INDICATOR_SHORTNAME,"Color RSI("+string(RSIPeriod)+")");
//--- Set an empty value for plots
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE);
//--- Set buffer colors
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,Down);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,1,Up);
//--- Receive indicator handles
   RSIHandle=iRSI(NULL,0,RSIPeriod,AppliedPrice);
//--- Set the sequence of buffer indexation
   ArraySetAsSeries(Values,true);
   ArraySetAsSeries(ValuesPainting,true);
//--- successful execution
   return(0);
  }

OnInit es la función de inicialización del indicador. Aquí configuramos los buffers del indicador y sus propiedades y definimos las variables del indicador que no pueden definirse en las propiedades o que deben establecerse dinámicamente. También hay una inicialización de datos que incluye la asignación de controladores necesaria para los indicadores.

int OnCalculate(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[])
  {
//--- number of bars for calculation
   int toCount=(int)MathMin(rates_total,rates_total-prev_calculated+1);
//--- try to copy iRSI indicator data
   if(CopyBuffer(RSIHandle,0,0,toCount,Values)==-1)
     {
      Print("Data copy error, №",GetLastError());
      //--- return command for recalculation of the indicator values
      return(0);
     }
//--- coloring. Yer, now it has become that easy
   for(int i=toCount-2;i>=0;--i)
     {
      //--- coloring the first line
      if(Values[i+1]!=EMPTY_VALUE && Values[i]>Values[i+1])
         ValuesPainting[i]=1;
      else
         ValuesPainting[i]=0;
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }

OnCalculate es la función para el calculo de los datos. Esta función puede ser de dos tipos. Esta es su forma estándar. Los detalles se muestran más abajo.

Función:

//--- this function usage in not obligatory
/*
void OnDeinit()
{

}
*/

OnDeinit es la función de deinicialización del indicador. A menudo es necesario disponer de recursos, por ejemplo, los controladores de archivo. Para otros casos no es necesaria esta función.

 

Dos conceptos de indicadores

El primero es estándar, el mismo que hemos usado en MQL4, pero con una forma ligeramente modificada. La función OnCalculate se usa en lugar de la función Start.

Para la versión estándar adopta la siguiente forma:

int OnCalculate(const int rates_total,      // Arrays size
                const int prev_calculated,  // Bars processed on the previous call
                const datetime& time[],     // Data for the current chart and timeframe...
                const double& open[],
                const double& high[],       
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
{
   return rates_total;
}

Para reducir la cantidad de código destinado a la copia de datos, los datos sobre el gráfico se pasan a los parámetros de la función directamente como matrices. Ademas, el número de barras disponibles se pasa como primer parámetro de la función y el número de barras procesadas después de la última llamada ó 0 (cero), se pasa como segundo parámetro.

El valor 0 (cero) puede pasarse en la primera llamada del indicador y también cuando se cargan nuevos datos o datos perdidos. Este parámetro reemplaza (de forma alternativa o equivalente, depende de usted) a IndicatorCounted(), aunque no resulta apropiado para muchos programadores.

El segundo concepto es el reemplazo y la expansión de i<…>OnArray como las funciones de MQL4. Hay un indicador de este tipo en los ejemplos del terminal (media móvil personalizada). Este tipo de indicadores está pensado para el procesamiento de datos según la elección del usuario, incluyendo los indicadores personalizados.

La función para el procesamiento de los datos para los indicadores de este tipo es como se muestra a continuación:

int OnCalculate (const int rates_total,      // the size of the price[] array
                 const int prev_calculated,  // bars calculated in the previous call
                 const int begin,            // where notional data start from
                 const double& price[]       // data array for calculation
                 )
  {
   return rates_total;
  }

El último parámetro de la función es el dato elegido por el usuario para el procesamiento. Si quiere aplicar un indicador con una gran cantidad de buffers, se pasará el primer buffer del indicador para el procesamiento de datos.

Los datos del primer indicador significan que el indicador se aplicará al primer indicador adjunto a la ventana elegida del gráfico.

Los datos del indicador previo significan que el indicador se aplicará al último indicador ajunto a la ventana elegida del gráfico.

Estos indicadores pueden usarse para ensamblar todas las pilas. Por ejemplo, usando el indicador de media móvil personalizada es posible obtener un triple suavizado forzando al primer indicador a trabajar con los datos necesarios, al segundo con el primero y al tercero con el segundo:

Hay muchos indicadores estándar que implementan este concepto. Por tanto, cuando vea aparecer el parámetro de función applied_price_or_handle:

esto indica que el indicador se implementa para que pueda ser calculado sobre los datos del usuario. El controlador de estos datos debe pasarse como parámetro applied_price_or_handle.

Usando la misma forma es posible organizar el procesamiento de los datos directamente en el código del indicador:

  {
   //...
   RSIHandle = iRSI(NULL, 0, RSIPeriod, AppliedPrice);
   SmoothHandle = iMA(NULL, 0, SmoothPeriod, 0, MODE_EMA, RSIHandle);
   //...
  }

Hay otra nueva aplicación de este concepto: la capacidad de escribir indicadores de servicio universales. Un ejemplo de tal indicador se incluye en el archivo Direction_Brush.mq5.

Los resultados se presentan en el gráfico superior. La coloración de la dirección en este caso se separa como una identidad independiente y se implementa en el otro indicador.

Ciertamente, su universalidad es limitada, ya que solo son aplicables al buffer cero del indicador. No obstante, creo que estos indicadores pueden ser útiles.

Desde otro punto de vista, cuando escribimos un indicador personalizado éste debe tenerse en cuenta, ya que la información principal que se procesa en el buffer cero permitirá evitar la implementación de una máquina multifuncional en un indicador. Muchas de las demás acciones pueden realizarse y ejecutarse en los indicadores de servicio externos. Todo lo que tendrá que hacer será adjuntar indicadores de servicio con la funcionalidad que requiera su personalización.

El rango de aplicación no es tan reducido como puede parecer a primera vista:

  • la coloración de las características del indicador (partes superiores, direcciones, niveles, segmentos, etc.), incluyendo la visualización del tono;
  • diferentes señales en distintas condiciones;
  • recopilar y mostrar las estadísticas, por ejemplo, la distribución de datos;
  • la construcción de indicadores universales que pueden ser calculados para un buffer, por ejemplo, medias móviles, zigzag.

Estas características no son una lista exhaustiva de la implementación del concepto. Creo que más adelante encontraremos muchas otras implementaciones efectivas.

 

Accediendo a los datos

Los principios de acceso a los datos han cambiado en MQL5. Ahora el trabajo tiene lugar directamente en las matrices y, como resultado, la velocidad de cálculo ha aumentado considerablemente. Ya no es necesario crear una matriz y llamar a la función iCustom para cada valor. En lugar de esto, es posible obtener el recuento de datos necesario llamando a una función y usar directamente los datos requeridos copiados en una matriz local especificada.

El proceso de copia de datos se implementa usando la función del sistema CopyBuffer. Puede encontrar la descripción de la función en la ayuda.

El máximo recuento de datos a copiar para el indicador y las matrices estáticas (con un tamaño predefinido) se determina por el tamaño de la matriz. El tamaño de la matriz dinámica puede cambiarse si el número de datos copiados excede su tamaño.

Ademas, hay funciones especiales para acceder a los datos históricos:

Función Descripción
CopyBuffer Obtiene datos de un buffer especificado de un cierto indicador en la cantidad necesaria.
CopyRates Obtiene el historial de la estructura MqlRates de un símbolo-período especificado en la cantidad indicada en la matriz rates_array.
CopyTime La función introduce en time_array el historial de datos del tiempo de apertura de la barra para el par símbolo-período en la cantidad especificada.
CopyOpen La función introduce en open_array el historial de datos de los precios abiertos de la barra para el par símbolo-período seleccionado en la cantidad solicitada.
CopyHigh La función introduce en high_array el historial de datos de los precios más altos de la barra para el par símbolo-período seleccionado en la cantidad solicitada.
CopyLow La función introduce en low_array el historial de datos de los precios mínimos de la barra para el par símbolo-período seleccionado en la cantidad solicitada.
CopyClose La función introduce en close_array el historial de datos de los precios cerrados de la barra para el par símbolo-período seleccionado en la cantidad solicitada.
CopyTickVolume La función introduce en volume_array el historial de datos de los volúmenes de ticks para el par símbolo-período seleccionado en la cantidad solicitada.
CopyRealVolume La función introduce en volume_array el historial de datos de los volúmenes de transacciones para el par símbolo-período seleccionado en la cantidad solicitada.
CopySpread La función introduce en spread_array el historial de datos de los los valores del margen diferencial para el par símbolo-período seleccionado en la cantidad solicitada.

Pueden consultarse los detalles en la ayuda.

Estos datos se pasan solo en una forma del indicador y para los demás deben obtenerse los suyos propios.

Debido al hecho de que el tipo de matriz de datos históricos no es necesariamente doble, para su almacenamiento se recomienda usar solo buffers dinámicos que no estén pensados para un uso con indicadores.

Hay también un detalle adicional que no está documentado. Si el recuento de datos copiados es igual a 0 (cero), la función CopyBuffer generará un error con el código Nº4003, y por tanto, el recuento de datos a copiar no debe ser menor que 1 (un) elemento.

 

Los buffers del indicador

El recuento de buffers no está limitado.

Ahora no tiene que pensar cómo poner en orden la información correctamente ni cómo realizar eficientemente los cálculos intermedios al trabajar en la creación del indicador cluster.

Pero no debemos olvidar que el almacenamiento de los buffers requiere memoria. Por tanto, si especifica una profundidad del historial del terminal en torno a 1.000.000 de barras y adjunta el indicador cluster "denso" en el gráfico de minutos, no se sorprenda cuando el terminal consuma Gb de memoria.

La esencia del buffer también ha experimentado algunos cambios. La cantidad de buffers usados se especifica en la propiedad.

#property indicator_buffers 2       // buffers used

Este valor debe corresponderse con el recuento total de buffers.

El número de buffers mostrados en pantalla es definido por la propiedad:

#property indicator_plots 1         // buffers displeyed

Aquí ahy algo de información. La mayoría de los estilos de trazado solo necesitan un buffer INDICATOR_DATA para el trazado. Sin embargo, hay algunos estilos que requieren algunos buffers de indicador para el trazado.

Nos referimos a los siguientes estilos de trazado:

  • DRAW_HISTOGRAM2 - requiere dos buffers de indicador (HistogramSample.mq5)

  • DRAW_FILLING - requiere dos buffers de indicador (CrossMa.mq5)

  • DRAW_CANDLES - requiere cuatro buffers de indicador (CandleSample.mq5)

  • DRAW_BARS - requiere cuatro buffers de indicador (BarsSample.mq5)

Todos los tipos anteriores, excepto el estilo DRAW_FILLING (no puede ser coloreado), tienen análogos coloreados.

Todos los buffers de indicador se dividen ahora en 3 tipos:

  • INDICATOR_DATA - buffers cuyos datos se muestran en el gráfico. Estos buffers están pensados para el trazado y el trabajo con iCustom. Deben registrarse en primer lugar. En caso de que se ordenen arbitrariamente (erróneo), el código se compilará con éxito y se mostrará en un gráfico, aunque probablemente de forma incorrecta.

  • INDICATOR_COLOR_INDEX - buffers para almacenar colores. Son necesarios para almacenar los índices del buffer de color del tipo INDICATOR_DATA, que tiene uno de los tipos especiales de color (#property indicator_typeN). Tal buffer (lo llamamos su buffer de color) debe registrarse justo después del buffer principal que lo utiliza.

  • INDICATOR_CALCULATIONS - Este tipo de buffers está pensado para almacenar los resultados de los cálculos auxiliares. No se muestran en el gráfico.

int OnInit()
{
   // ...
   SetIndexBuffer(0, V2, INDICATOR_DATA);
   SetIndexBuffer(1, V2C,INDICATOR_COLOR_INDEX);
   SetIndexBuffer(2, V4, INDICATOR_DATA);
   SetIndexBuffer(3, V4C,INDICATOR_COLOR_INDEX);
   SetIndexBuffer(4, V1, INDICATOR_CALCULATIONS);
   SetIndexBuffer(5, V3, INDICATOR_CALCULATIONS);

   // ...
   return 0;
}

Existen también algunas características al referimos a los indicadores a través de iCustom.

  • Los buffers para el trazado (aquellos que se muestran en el gráfico) se encuentran disponibles para su lectura. El número del buffer (índice) debe coincidir con el usado para registrar el buffer.
  • Los buffers para almacenar el color pueden estar disponibles para lectura, pero no siempre. Por ejemplo, en el código anterior, el buffer V2C puede leer y obtener los valores necesarios, pero el buffer V4C no está disponible.
  • Los buffers para cálculos intermedios no están disponibles como lo estaban en MQL4. Si quiere tener el acceso garantizado al buffer de datos externos, declárelo como INDICATOR_DATA.

En caso de solicitud para un buffer inaccesible, se generará el error 4806 ("No se encuentra el dato solicitado").

Vamos a ver en detalle los buffers de color.

En MQL4, para cada color era necesario crear un buffer separado, pero ahora, con el uso de los estilos de color, puede especificar hasta 63 colores para un buffer. En algunos casos permitirá optimizar el número de buffers usados y, de esta forma, ahorrar memoria. También abre nuevas posibilidades para escribir indicadores, en particular, el uso de la visualización del tono.

Además, en algunos casos esta innovación simplifica enormemente la lógica de la aplicación de varios colores en comparación con MQL4. El ejemplo más obvio es la separación de tendencias mediante colores. En MQL4, para el caso más económico (de los casos correctos) de implementación, ha requerido tres (3) buffers y una programación nada trivial.

Ahora es más fácil que nunca. Estos son los ejemplos de código. La implementación completa se encuentra en el archivo Color_RSI.mq5.

#property indicator_color1 clrDarkSalmon, clrDeepSkyBlue // use 2 colors
#property indicator_type1  DRAW_COLOR_LINE               // and the special color display type
//---- buffers
double Values[];                 // buffer of values
double ValuesPainting[];         // buffer of color indices
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- bind indicator buffers
//--- Values serves as a display buffer
   SetIndexBuffer(0,Values,INDICATOR_DATA);
//--- ValuesPainting serves as the buffer for storing colors
   SetIndexBuffer(1,ValuesPainting,INDICATOR_COLOR_INDEX);
//...
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(/*...*/)
  {
//--- number of bars for calculation
   int toCount=(int)MathMin(rates_total,rates_total-prev_calculated+1);
//--- try to copy iRSI indicator data
   if(CopyBuffer(RSIHandle,0,0,toCount,Values)==-1)
     {
      Print("Data copy error, №",GetLastError());
      //--- return command for recalculation of the indicator values
      return(0);
     }
//--- coloring. Yer, now it has become that easy
   for(int i=toCount-2;i>=0;--i)
     {
      //--- coloring the first line
      if(Values[i+1]!=EMPTY_VALUE && Values[i]>Values[i+1])
         ValuesPainting[i]=1;
      else
         ValuesPainting[i]=0;
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }

Algo más de código y tenemos lo siguiente:

Notará algunos detalles cuando use los tipos de color para el trazado.

Para los buffers de color, al usar un esquema de definición de color dinámico, el recuento de colores máximo está limitado por el recuento de colores definido en la propiedad indicator_colorN. Por ejemplo

#property indicator_color1 clrDarkSalmon, clrDeepSkyBlue // use 2 colors

El esquema de colores del buffer tendrá un máximo de dos colores, incluso si establece un mayor número de colores dinámicamente (usando PlotIndexSetInteger).

Por tanto, debe escribirse el número requerido de colores en una línea (línea de definición de la propiedad). A partir de entonces pueden cambiarse dinámicamente. El color más corto que he encontrado ("rojo"). Sin embargo, siempre puede hacer lo siguiente:

En lugar de

#property indicator_color1  clrRed, clrRed, clrRed, clrRed, clrRed, clrRed, clrRed, clrRed, //…

puede escribir:

#define C clrRed
#property indicator_color1  C, C, C, C, C, C, C, C, C, C, C, C, C, C, //…

El número máximo de colores para un buffer es 63. Cuando el número de color es mayor que el máximo (definido por la propiedad indicator_colorN), el buffer no se mostrará.

A continuación se muestra un ejemplo de visualización del tono usando el máximo número de colores:

En general, las posibilidades de trazado han aumentado considerablemente y eso está muy bien.

 

Matrices

Durante la referencia directa a los datos de la matriz por parte de los índices, es necesario indicar el tipo de ordenación de los datos -propiedad AsSeries. No puede ser definido para algunos tipos de matrices.

Esta señal no puede establecerse para las matrices multidimensionales ni para las estáticas. Para los tipos de matrices que se pasan a la función OnCalculate, es posible establecer dicha señal.

El copiado de datos usando la función CopyBuffer no depende de la propiedad AsSeries, pero su implementación es diferente para cada tipo de buffer.

Para los buffers de indicador es necesario copiar toda la profundidad del historial disponible. Debe recordarse esto.

Para matrices dinámicas y estáticas (con un tamaño predefinido), el copiado de datos se realiza desde el presente al pasado.

La función CopyBuffer cambia el tamaño de los buffers dinámicos (excepto el de los indicadores) para adoptar el adecuado.

No se recomienda usar las matrices estáticas para el copiado de datos.

En general, siempre aconsejo que se revise cómo se copian los datos y cómo utilizarlos. El modo más simple y seguro es el siguiente:

  • establecer la propiedad AsSeries para todos los buffers usados para almacenar datos históricos.
  • tener en cuenta las estructuras del buffer para los diferentes buffers.
  • verificar siempre el valor de la variable _LastError (código del último error).

Además, aconsejo encarecidamente estudiar la ayuda para la función CopyBuffer y para todas las funciones conectadas con la propiedad AsSeries.

 

IndicatorCounted

Ahora, las discusiones sobre la necesidad de la función IndicatorCounted van a pasar a un segundo plano, ya que su valor lo definimos directamente nosotros como valor devuelto por la llamada a la función previa.

int OnCalculate(const int rates_total,      // array size
                const int prev_calculated,  // bars processed after last call
                //...)
  {
   return rates_total;
  }

A menudo, es suficiente devolver el valor rates_total que contiene el recuento de barras de la llamada a la función actual.

Sin embargo, si el dato de precio se hubiera cambiado a partir de la última llamada OnCalculate() (por ejemplo, los datos históricos se cargaron o los espacios en blanco de los datos históricos se rellenaron), entonces el valor del parámetro de entrada prev_calculated sería establecido a 0 (cero) por el terminal de cliente.

Además, si la función OnCalculate devuelve cero los valores del indicador no se muestran en el DataWindow del terminal de cliente. Por tanto, si quiere ver el indicador y realizar su recálculo al completo durante el proceso de carga del historial o después de un fallo de conexión, devuelva 1 en lugar de 0.

Otra característica útil que ha sido añadida es la determinación del número de barras que han sido calculadas por el indicador. Es más útil para los asesores expertos que realizan cálculos con grandes cantidades de datos. La función es BarsCalculated y sus detalles se encuentran en la ayuda.

Esta función tiene otra útil aplicación. Si el indicador no ha sido cargado, su carga puede llevar algún tiempo -el tiempo que transcurre entre la creación del controlador del indicador y su uso para los cálculos.

Este tiempo es necesario para la inicialización y su precálculo inicial. Depende de la velocidad de cálculo y de los detalles del indicador.

Durante este tiempo, la llamada para la función CopyBuffer genera el error 4806 - "El dato solicitado no existe".

La función BarsCalculated puede usarse para determinar la disponibilidad del dato del indicador para el copiado:

//--- number of bars for calculation
   int toCount=rates_total-(int)MathMax(prev_calculated-1,0);
//--- try to copy iWPR indicator data
   int copied=CopyBuffer(WPRHandle,0,0,toCount,Values);
   int err=GetLastError();
//--- check coying result
   if(copied==-1)
     {
      //--- if error number is 4806, the data simply have not been uploaded yet
      if(err==4806)
        {
         //--- wait till the data is uploaded
         for(int i=0;i<1000;++i)
            if(BarsCalculated(WPRHandle)>0)
               break;
         //--- try to copy iWPR indicator data again
         copied=CopyBuffer(WPRHandle,0,0,rates_total,Values);
         err=GetLastError();
        }
     }
//--- check coying result
   if(copied==-1)
     {
      Print("Error when trying to get WPR values, last error is ",err," bars ",rates_total);
      return(0);
     }
//...

 

Resumen

En conclusión, me gustaría decir que solo se han tratado algunos detalles en este artículo. Aunque espero que los aspectos fundamentales hayan sido incluidos.

Estaría bien si este artículo fuera una referencia útil sobre la materia, donde siempre se pudiera mirar y encontrar información detallada.

Si ha encontrado algún error en este artículo o ha descubierto algo importante, por favor, indíquemelo e intentaré corregirlo y mejorar el artículo tan pronto como sea posible.

Estoy pensando en esbozar los cambios recientes y, además de eso, espero que parte de la información útil aparezca en los comentarios.

Por eso hay que leerlos con detenimiento.

 

Apéndice

  • Color.mqh - incluye el archivo, copia este archivo en la carpeta MQL5/Include. Este archivo es necesario para el indicador Toned_WPR.
  • Color.mq5 - librería, copia este archivo en la carpeta MQL5/Libraries. Este archivo es necesario para el indicador Toned_WPR.

Todos los archivos anteriores son indicadores.

 

Reconocimientos

De nuevo, me gustaría dar las gracias al Sr. Victor Rustamov (granit77) por su lectura del manuscrito y sus útiles comentarios y consejos.

Traducción del inglés realizada por MetaQuotes Software Corp.
Artículo original: https://www.mql5.com/en/articles/5

Archivos adjuntos |
barssample.mq5 (4.75 KB)
candlesample.mq5 (4.75 KB)
color.mq5 (8.7 KB)
color.mqh (2.11 KB)
color_rsi.mq5 (11.96 KB)
crossma.mq5 (5.13 KB)
toned_wpr.mq5 (10.03 KB)
El prototipo del Robot de trading El prototipo del Robot de trading

Este artículo resume y sistematiza los principios para la creación de algoritmos de sistemas de trading. El artículo aborda el diseño del algoritmo del experto. Como ejemplo, se aborda la clase CExpert Advisor, que se puede utilizar para un desarrollo rápido y sencillo de los sistemas de trading.

20 señales de trading en MQL5 20 señales de trading en MQL5

En este artículo aprenderás a recibir las señales de trading necesarias para el funcionamiento de un sistema de trading. Los ejemplos de formación de las 20 señales de trading se dan aquí como funciones personalizadas separadas, que se pueden utilizar durante el desarrollo de los Expert Advisors. Para tu comodidad, todas las funciones utilizadas en este artículo están incluidas en un archivo mqh, que se puede conectar fácilmente a un futuro Expert Advisor.

Jeremy Scott es un vendedor de gran éxito en el mercado MQL5 Jeremy Scott es un vendedor de gran éxito en el mercado MQL5

Jeremy Scott, más conocido en MQL5.community con el nick Johnnypasado, ha adquirido fama en el terreno de nuestro servicio de mercado MQL5. Ya ha ganado varios miles de dólares en el Mercado y este no es el límite, ni mucho menos. Hemos decidido estudiar atentamente al futuro millonario y preguntarle el secreto del éxito para los vendedores del mercado MQL5.

Cómo crear su propio Trailing Stop Cómo crear su propio Trailing Stop

La regla básica del trader: dejar correr el beneficio, cortar las pérdidas! Este artículo aborda una de las técnicas básicas, permitiendo seguir esta regla: mover el tope de pérdida dinámico (Stop Loss level) después de incrementar el beneficio de la posición, es decir el nivel Trailing Stop. Encontrará el procedimiento paso a paso para crear una clase Trailing Stop en los indicadores SAR y NRTR. Cualquiera podrá insertar este Trailing Stop en sus expertos o utilizarlo independientemente para controlar las posiciones de sus cuentas.