English Русский 中文 Deutsch 日本語 Português 한국어 Français Italiano Türkçe
Implementación práctica de filtros digitales en MQL5 para principiantes

Implementación práctica de filtros digitales en MQL5 para principiantes

MetaTrader 5Ejemplos | 22 enero 2014, 14:02
1 199 0
Nikolay Kositsin
Nikolay Kositsin

Introducción

En mi artículo anterior he realizado un análisis del código de un indicador simple y he tratado brevemente la interacción de este indicador con el terminal de cliente de MetaTrader 5. Ahora, antes de continuar, debemos prestar más atención a los resultados de la compilación del experto en la pestaña "Errores" de la ventana "Caja de herramientas" en MetaEditor. A partir de aquí podemos empezar con un estudio en profundidad del código del indicador SMA que he propuesto anteriormente.


Errores de compilación del indicador

En nuestra situación, al compilar alguna de las dos versiones del código, en caso de que no haya cambios, el proceso de compilación no presenta muchas dificultades en relación con el resultado esperado:


No hay errores y junto con el archivo del indicador con extensión .mq5 apareció un archivo similar con la extensión .ex5.

Normalmente, cuando trabajamos con el código no podemos evitar los errores. Son cometidos frecuentemente por los programadores. Para este propósito MetaEditor tiene un mecanismo que comprueba el código compilado para detectar todo tipo de errores, y cuando los encuentra proporciona una lista completa de todos ellos.

Para detectar dónde se encuentra un error podemos hacer doble clic en la línea correspondiente con los contenidos del error en la ventana "Caja de herramientas". En la mayoría de casos, el compilador indicará de forma precisa la línea de código donde se ha encontrado el error usando el icono adecuado .

Debe tener en cuenta una cosa. Un error en el código puede generar toda una secuencia de errores de compilación. Por tanto, para eliminar la secuencia de errores, es suficiente con ir a la primera línea donde el compilador ha encontrado un error y corregir el código. No obstante, puede llevar a cabo una gran cantidad de estas secuencias de compilación de errores. Una vez corregido el error en el código debemos compilarlo de nuevo y si el compilador encuentra errores debemos mirar en la primera línea en la pestaña "Errores" de la ventana "Caja de herramientas".

Quizás el método más efectivo de abordar esto sea la observación de algún elemento significativo con efectos destructivos en el código para estudiar cómo el compilador reaccionará frente a los errores. La técnica es muy sencilla: situamos el error en una parte específica del código, presionamos el botón "compilar" en MetaEditor y observamos el resultado de la compilación. Sería aún mejor si recordáramos intuitivamente dicho resultado en el código. En cualquier caso esto puede ser útil en la práctica trabajando con el código MQL5.

Esta es la lista de posibles cambios dañinos en el código fuente del indicador:

  1. Introducir un espacio en cualquier operador o variable;
  2. Eliminar un punto y coma;
  3. Añadir un punto y coma en distintas partes del código;
  4. Borrar un operador;
  5. Borrar o añadir corchetes o paréntesis;
  6. Eliminar una coma;
  7. Añadir un parámetro de entrada adicional en la función OnCalculate();
  8. Dividir una variable por cero;
  9. Reemplazar "==" por "=" en la línea del operador "if";
  10. Cambiar la dirección del incremento en una variable de una barra++ a una barra--.

Naturalmente, el compilador no siempre encuentra el lugar del error en el que este se ha producido realmente. Por eso debe hacerse este trabajo preliminar, para comprender cómo gestionar estas situaciones. Bien, una explicación más sobre los errores. ¡El compilador de MetaEditor solo encuentra los errores del lenguaje MQL5 y en la mayoría de casos no encuentra los errores lógicos de la programación!


Su vocabulario MQL5

Si oye hablar a una persona con toda la riqueza de cualquier lenguaje humano, resulta que solo utilizará una pequeña parte de las herramientas para expresar sus ideas y necesidades. En la mayoría de las situaciones el vocabulario usado es bastante menor que el que hay disponible. Lo mismo puede aplicarse al lenguaje MQL5. De entrada, a medida que domine el lenguaje MQL5 debe acostumbrarse a los operadores y expresiones más usados de dicho lenguaje. A medida que lo aprenda podrá aumentar gradualmente los límites de su vocabulario.

Por ejemplo, puede usar cuatro tipos de variables (int, double, bool, string), if-else operador condicional, for operador loop, {} compound y return. También debe aprender en profundidad cómo usar un punto y coma ";" y una coma ",". Quizás sería una buena idea aprender matemáticas y funciones trigonométricas. ¡Estas herramientas son más que suficientes para tener la preparación y practicar con sus habilidades de programación!


Perfeccionamiento del indicador

Las capacidades de MQL5 para perfeccionar el indicador mostradas en el terminal de cliente de MetaTrader son muy simples. Consisten en operadores de nivel global:

//---- Indicator's author
#property copyright "2010, MetaQuotes Software Corp."
//---- Author's web-site link
#property link      "https://www.mql5.com"
//---- Indicator version number
#property version   "1.00"
//---- Drawing the indicator in the main window
#property indicator_chart_window
//---- One buffer is used for calculating and drawing the indicator
#property indicator_buffers 1
//---- Only one graphical plotting is used
#property indicator_plots   1
//---- Drawing the indicator as line
#property indicator_type1   DRAW_LINE
//---- Red is used as indicator's line color
#property indicator_color1  Red
//---- Indicator line is continuous curve
#property indicator_style1  STYLE_SOLID
//---- Indicator line thickness is equal to 1
#property indicator_width1  1
//---- Displaying indicator's label
#property indicator_label1  "SMA"

Y en llamadas de funciones de OnInit():

//---- Variable initialization for indicator's short name
   string shortname;
   StringConcatenate(shortname,"FATL(",FATLShift,")");
//--- Creating labels to display in Data Window
   PlotIndexSetString(0,PLOT_LABEL,shortname);
//--- Creating name to display in a separate window and in tool-tip
   IndicatorSetString(INDICATOR_SHORTNAME,shortname);
//--- Defining accuracy of displaying indicator's values
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits+1);
//--- Prohibition of displaying blank values
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
La función StringConcatenate() formula el string del nombre del indicador usando esta fórmula:
   shortname = shortname + "SMA(" + MAPeriod + "," + MAShift + ")";

De acuerdo con las recomendaciones que se hacen en el artículo aplicar un indicador a otro no debería costar añadir la llamada a la función PlotIndexSetInteger() en OnCalculate():

//---- Calculating the 'first' starting number for the bars recalculation loop
   if(prev_calculated==0)        // Checking the first start of the indicator calculation
     {
      first=FATLPeriod-1+begin;  // Starting number for calculation of all bars
      //--- Increasing the start of data position by 'begin' bars, because the 
      //    calculations are based on data of another indicator
      if(begin>0)
         PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,begin+FATLPeriod);
     }
   else first=prev_calculated-1; // Starting number for calculation of new bars
Es natural que después de incluir estas líneas adicionales de código nuestro indicador incremente ligeramente su tamaño y se haga un poco más complicado, pero tendrá también una interfaz más sencilla.


El resultado del trabajo anterior como plantilla para crear nuevos indicadores

Todo esto es muy interesante, pero surge una pregunta muy natural - ¿por qué inventar la rueda y repetir el código del indicador que ya está disponible en el terminal de cliente con dos versiones bajo la forma del indicador técnico Moving Average.mq5 y el indicador personalizado Custom Moving Average.mq5? La respuesta es simple. ¡Para aprender cómo escribir rápidamente el código de estos indicadores usando como plantilla el código de indicador SMA propuesto anteriormente y ahorrando nuestros recursos intelectuales tanto como sea posible! Por ejemplo, puede intentar escribir código en MQL5 para un filtro digital como FATL a partir de Finware.

En general, la fórmula para calcular el filtro digital es:

FILTER = SUM (K(i) * CLOSE (i), FilterPeriod)

donde:

  • SUM — la suma.
  • K(i) — el coeficiente de ponderación.
  • CLOSE (i) — el precio de cierre de la barra actual.
  • FilterPeriod — el número de barras para la promediación. 

Esta fórmula no es muy distinta a la fórmula del indicador SMA:

SMA = SUM ((1 / MAPeriod ) * CLOSE (i), MAPeriod)

La diferencia es que el periodo sobre el que se realizan los cálculos con un filtro digital es estrictamente fijo y es específico para cada filtro digital, así como los coeficientes de ponderación K(i). Los coeficientes de ponderación y el periodo del filtro digital se calculan usando algoritmos especializados. El análisis de estos algoritmos se encuentra fuera del alcance de este artículo, por lo que continuaremos usando los valores disponibles del filtro digital FATL. Los que estén interesados en el concepto de filtrado de señales digitales pueden visitar el sitio web (en ruso) generador de métodos digitales. La fórmula de una variante del indicador FATL en MQL4 no es ningún secreto:

     FATL =  0.4360409450 * Close[bar + 0]
           + 0.3658689069 * Close[bar + 1]
           + 0.2460452079 * Close[bar + 2]
           + 0.1104506886 * Close[bar + 3]
           - 0.0054034585 * Close[bar + 4]
           - 0.0760367731 * Close[bar + 5]
           - 0.0933058722 * Close[bar + 6]
           - 0.0670110374 * Close[bar + 7]
           - 0.0190795053 * Close[bar + 8]
           + 0.0259609206 * Close[bar + 9]
           + 0.0502044896 * Close[bar + 10]
           + 0.0477818607 * Close[bar + 11]
           + 0.0249252327 * Close[bar + 12]
           - 0.0047706151 * Close[bar + 13]
           - 0.0272432537 * Close[bar + 14]
           - 0.0338917071 * Close[bar + 15]
           - 0.0244141482 * Close[bar + 16]
           - 0.0055774838 * Close[bar + 17]
           + 0.0128149838 * Close[bar + 18]
           + 0.0226522218 * Close[bar + 19]
           + 0.0208778257 * Close[bar + 20]
           + 0.0100299086 * Close[bar + 21]
           - 0.0036771622 * Close[bar + 22]
           - 0.0136744850 * Close[bar + 23]
           - 0.0160483392 * Close[bar + 24]
           - 0.0108597376 * Close[bar + 25]
           - 0.0016060704 * Close[bar + 26]
           + 0.0069480557 * Close[bar + 27]
           + 0.0110573605 * Close[bar + 28]
           + 0.0095711419 * Close[bar + 29]
           + 0.0040444064 * Close[bar + 30]
           - 0.0023824623 * Close[bar + 31]
           - 0.0067093714 * Close[bar + 32]
           - 0.0072003400 * Close[bar + 33]
           - 0.0047717710 * Close[bar + 34]
           + 0.0005541115 * Close[bar + 35]
           + 0.0007860160 * Close[bar + 36]
           + 0.0130129076 * Close[bar + 37]
           + 0.0040364019 * Close[bar + 38]; 

En MQL5 las barras en los buffers del indicador se calculan en dirección opuesta a MQL4. Para usar esta fórmula en los indicadores de MQL5 debemos reemplazar la operación de incremento dentro de paréntesis con la operación decremento. Debido a la ausencia de la matriz de series de tiempo Close[] en MQL5 debemos también reemplazarla con una variable apropiada - price[]. Es muy natural automatizar esta tarea usando el siguiente comando de menú en MetaEditor.

El expresión habitual Close [bar + debe sustituirse por price [bar -:

En este cuadro de diálogo haga clic en el botón "Sustituir todo". Como resultado obtendremos la fórmula del cálculo del indicador FATL en MQL5:

     FATL =  0.4360409450 * price[bar - 0]
           + 0.3658689069 * price[bar - 1]
           + 0.2460452079 * price[bar - 2]
           + 0.1104506886 * price[bar - 3]
           - 0.0054034585 * price[bar - 4]
           - 0.0760367731 * price[bar - 5]
           - 0.0933058722 * price[bar - 6]
           - 0.0670110374 * price[bar - 7]
           - 0.0190795053 * price[bar - 8]
           + 0.0259609206 * price[bar - 9]
           + 0.0502044896 * price[bar - 10]
           + 0.0477818607 * price[bar - 11]
           + 0.0249252327 * price[bar - 12]
           - 0.0047706151 * price[bar - 13]
           - 0.0272432537 * price[bar - 14]
           - 0.0338917071 * price[bar - 15]
           - 0.0244141482 * price[bar - 16]
           - 0.0055774838 * price[bar - 17]
           + 0.0128149838 * price[bar - 18]
           + 0.0226522218 * price[bar - 19]
           + 0.0208778257 * price[bar - 20]
           + 0.0100299086 * price[bar - 21]
           - 0.0036771622 * price[bar - 22]
           - 0.0136744850 * price[bar - 23]
           - 0.0160483392 * price[bar - 24]
           - 0.0108597376 * price[bar - 25]
           - 0.0016060704 * price[bar - 26]
           + 0.0069480557 * price[bar - 27]
           + 0.0110573605 * price[bar - 28]
           + 0.0095711419 * price[bar - 29]
           + 0.0040444064 * price[bar - 30]
           - 0.0023824623 * price[bar - 31]
           - 0.0067093714 * price[bar - 32]
           - 0.0072003400 * price[bar - 33]
           - 0.0047717710 * price[bar - 34]
           + 0.0005541115 * price[bar - 35]
           + 0.0007860160 * price[bar - 36]
           + 0.0130129076 * price[bar - 37]
           + 0.0040364019 * price[bar - 38];

Ahora podemos comenzar con el código del indicador cuyo algoritmo de cálculo se acaba de considerar. Para hacer esto, en primer lugar abrimos el indicador SMA_1_en.mq5 en MetaEditor y lo guardamos como FATL_en.mq5. La plantilla del indicador está ya lista y ahora tenemos que sustituir el algoritmo de cálculo del indicador en ella para hacer algunos cambios en las variables, en su mayoría estéticos. Debe seleccionar todo el bloque de la fórmula última mencionada para el cálculo del filtro FATL y copiarla al portapapeles de Windows. A continuación, en el código del indicador eliminamos todo el código dentro del operador del bucle, excepto la última inicialización del buffer del indicador:

//---- Main loop of indicator calculation
   for(bar=first; bar<rates_total; bar++)
     {
     


      //---- Indicator buffer's cell initialization with FATL value
      ExtLineBuffer[bar]=FATL;
     }

En lugar del código borrado pegaremos el algoritmo de cálculo del filtro digital FATL del portapapeles de Windows. A continuación debemos reemplazar la palabra SMA con FATL usando el procedimiento de sustitución descrito anteriormente. De igual forma debemos sustituir los nombres de las variables de entrada MAPeriod y MAShift con FATLPeriod y FATLShft respectivamente. La variable FATLPeriod debe eliminarse de las variables externas ya que tiene un valor fijo igual a 39. Por la misma razón debe eliminarse del operador StringConcatenate() en la función OnInit(). Ahora ya no es necesaria la variable local iii por lo que puede eliminarse. Y finalmente puede cambiar el color de la línea del indicador a azul y hacer que la propia línea se un poco más gruesa.

Después de estos sencillos cambios en el código de SMA_1_en.mq5 obtenemos el código del indicador deseado FATL_en.mq5:

//+------------------------------------------------------------------+
//|                                                      Fatl_en.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
//---- Indicator's author
#property copyright "2010, MetaQuotes Software Corp."
//---- Author's web-site link
#property link      "https://www.mql5.com"
//---- Indicator version number
#property version   "1.00"
//---- Drawing the indicator in the main window
#property indicator_chart_window
//---- One buffer is used for calculating and drawing the indicator
#property indicator_buffers 1
//---- Only one graphical plotting is used
#property indicator_plots   1
//---- Drawing the indicator as line
#property indicator_type1   DRAW_LINE
//---- Blue is used as indicator's line color
#property indicator_color1  Blue
//---- Indicator line is continuous curve
#property indicator_style1  STYLE_SOLID
//---- Indicator line thickness is equal to 2
#property indicator_width1  2
//---- Displaying indicator's label
#property indicator_label1  "FATL"

//---- Input parameters of indicator
input int FATLShift=0; // FATL horizontal shift in bars

//---- Declaring and initializing a variable to store the number of calculated bars
int FATLPeriod=39;

//---- Declaration of dynamic array, which will be 
//     used later as indicator buffer
double ExtLineBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+  
void OnInit()
  {
//----+
//---- Transformation of ExtLineBuffer dynamic array into indicator buffer
   SetIndexBuffer(0,ExtLineBuffer,INDICATOR_DATA);
//---- Horizontal shift of indicator by FATLShift
   PlotIndexSetInteger(0,PLOT_SHIFT,FATLShift);
//---- Setting the position from which the drawing of indicator will start
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,FATLPeriod);
//---- Variable initialization for indicator's short name
   string shortname;
   StringConcatenate(shortname,"FATL(",FATLShift,")");
//--- Creating labels to display in Data Window
   PlotIndexSetString(0,PLOT_LABEL,shortname);
//--- Creating name to display in a separate window and in tool-tip
   IndicatorSetString(INDICATOR_SHORTNAME,shortname);
//--- Defining accuracy of displaying indicator's values
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits+1);
//--- Prohibition of displaying blank values
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
//----+
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(
                const int rates_total,     // amount of history in bars at the current tick
                const int prev_calculated, // amount of history in bars at the previous tick
                const int begin,           // beginning number of reliable count of bars
                const double &price[]      // price array for indicator calculation
                )
  {
//----+   
//---- Check if the number of bars is sufficient for calculation
   if(rates_total<FATLPeriod-1+begin)
      return(0);

//---- Declaring local variables
   int first,bar;
   double Sum,FATL;

//---- Calculating the 'first' starting number for the bars recalculation loop
   if(prev_calculated==0)        // Checking the first start of the indicator calculation
     {
      first=FATLPeriod-1+begin;  // Starting number for calculation of all bars
      //--- Increasing the start of data position by 'begin' bars, because the 
      //    calculations are based on data of another indicator
      if(begin>0)
         PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,begin+FATLPeriod);
     }
   else first=prev_calculated-1; // Starting number for calculation of new bars

//---- Main loop of indicator calculation
   for(bar=first; bar<rates_total; bar++)
     {
      //---- 
      FATL=0.4360409450*price[bar-0]
           + 0.3658689069 * price[bar - 1]
           + 0.2460452079 * price[bar - 2]
           + 0.1104506886 * price[bar - 3]
           - 0.0054034585 * price[bar - 4]
           - 0.0760367731 * price[bar - 5]
           - 0.0933058722 * price[bar - 6]
           - 0.0670110374 * price[bar - 7]
           - 0.0190795053 * price[bar - 8]
           + 0.0259609206 * price[bar - 9]
           + 0.0502044896 * price[bar - 10]
           + 0.0477818607 * price[bar - 11]
           + 0.0249252327 * price[bar - 12]
           - 0.0047706151 * price[bar - 13]
           - 0.0272432537 * price[bar - 14]
           - 0.0338917071 * price[bar - 15]
           - 0.0244141482 * price[bar - 16]
           - 0.0055774838 * price[bar - 17]
           + 0.0128149838 * price[bar - 18]
           + 0.0226522218 * price[bar - 19]
           + 0.0208778257 * price[bar - 20]
           + 0.0100299086 * price[bar - 21]
           - 0.0036771622 * price[bar - 22]
           - 0.0136744850 * price[bar - 23]
           - 0.0160483392 * price[bar - 24]
           - 0.0108597376 * price[bar - 25]
           - 0.0016060704 * price[bar - 26]
           + 0.0069480557 * price[bar - 27]
           + 0.0110573605 * price[bar - 28]
           + 0.0095711419 * price[bar - 29]
           + 0.0040444064 * price[bar - 30]
           - 0.0023824623 * price[bar - 31]
           - 0.0067093714 * price[bar - 32]
           - 0.0072003400 * price[bar - 33]
           - 0.0047717710 * price[bar - 34]
           + 0.0005541115 * price[bar - 35]
           + 0.0007860160 * price[bar - 36]
           + 0.0130129076 * price[bar - 37]
           + 0.0040364019 * price[bar - 38];

      //---- Indicator buffer's cell initialization with FATL value
      ExtLineBuffer[bar]=FATL;
     }
//----+     
   return(rates_total);
  }
//+------------------------------------------------------------------+

Después de compilar el indicador este puede ser probado en el gráfico en el terminal de cliente:

Es natural que el código resultante del indicador FATL pueda usarse como plantilla para construir otros filtros similares. Pero ahora el problema es mucho más sencillo. En nuestro código es suficiente sustituir la fórmula para el cálculo del filtro, sustituir la palabra FATL e inicializar (ahora) la variable DIGFILTERPeriod con la dimensión adecuada del filtro digital.


Solución común para crear filtros digitales en el terminal de cliente

El indicador que acabamos de ver es solo una posible forma de solucionar el problema del filtrado de señales digitales. Estaría bien tener un indicador que representara una solución común y que permitiera construir cualquier filtro digital usando un solo indicador. Este problema se solucionó hace tiempo en el terminal de cliente de MetaTrader 4 usando el módulo DF.dll de Sergei Ilyuhin. Por lo que sería fácil utilizarlo para resolver nuestro problema en el terminal de cliente de MetaTrader 5. En este módulo se presenta la función DigitalFilter():

DigitalFilter(int FType, int P1, int D1, int A1, int P2, int D2, int A2, double Ripple, int Delay, double& array[]); 

Nos permite recibir los coeficientes del filtro digital como la matriz array[]. La función escribe los coeficientes del filtro digital en esta matriz con tamaño 1.500 usando la referencia (la marca "&" después de la declaración de este tipo de variable en esta matriz). La función acepta los valores de diez parámetros de entrada y devuelve el tamaño del filtro digital. Esto es suficiente para construir el filtro digital universal. Todo el problema se reduce a organizar la importación de la DLL en el indicador existente a nivel global, obteniendo la matriz de coeficientes en el bloque de código de la inicialización del indicador y en base a estos coeficientes ejecutando el cálculo universal del filtro en OnCalculate(). Las variables de entrada de la función DigitalFilter() deben situarse en las variables de entrada del indicador. Lo haremos ahora mismo.

La importación del archivo DF.dll no es muy complicada. Son solo tres líneas de código:

//---- DLL import
#import "DF.dll"
int DigitalFilter(int FType, int P1, int D1, int A1, int P2, int D2, int A2, double Ripple, int Delay, double& array[]); 
#import

Después de esto convertiremos todas las variables externas de la función DigitalFilter() en variables de entrada del indicador.

//---- Input parameters of indicator
input FType_ FType=LPF;     //Filter Type
                            //0 - Low-Pass Filter (FATL / SATL / KGLP), 1 - High-Pass Filter (KGHP), 
                            //2 - Band-Pass Filter (RBCI / KGBP), 3 - Band-Stop Filter (KGBS)
input int    P1 = 28;       //Cut-off period 1, in bars
input int    D1 = 19;       //Transient process cut-off period 1, in bars
input int    A1 = 40;       //Fading in delay band 1, in dB
input int    P2 = 0;        //Cut-off period 2, in bars
input int    D2 = 0;        //Transient process cut-off period 2, in bars
input int    A2 = 0;        //Fading in delay band 2, in dB
input int    Delay=0;       //Delay, in bars
input double Ripple=0.08;   //Beats in bandwidth, in dB
input int    FILTERShift=0; //Moving Average horizontal shift, in bars

A nivel global declararemos la variable FILTERPeriod sin inicialización:

//---- Declaring and initializing a variable to store the number of calculated bars
int FILTERPeriod;

A nivel global declararemos una matriz dinámica para almacenar los coeficientes del filtro:

//---- Declaration of dynamic array, which will be 
//     used later as indicator buffer
double FILTERTable[];

Ahora vamos con la parte interna del bloque de la función OnInit(). No es muy lógico usar la matriz FILTERTable[] como parámetro de la función DigitalFilter(). Para esto deberíamos darle un tamaño de hasta 1.500 elementos de los que solo se usarán en el bloque de la función OnCalculate() 100-200. En esta situación sería mejor usar la matriz Array[1500] declarada localmente dentro de la función OnInit(). La cantidad necesaria de datos de esta matriz se escribirá en la matriz FILTERTable[] . Después de salir de la función OnInit() la matriz grande Array[] será destruida y los datos necesarios permanecerán en la matriz FILTERTable[] que tendrá un tamaño igual a la longitud del filtro digital FILTERPeriod. Esta es la variante del código usado para esta finalidad:

//---- Calculation of digital filter coefficients and determining the size of FILTERTable[] buffer
   double Array[1500];
   FILTERPeriod=DigitalFilter(FType,P1,D1,A1,P2,D2,A2,Ripple,Delay,Array);
//----  Changing the size of FILTERTable[] buffer for required number of digital filter coefficients
   if(FILTERPeriod<=0)
     {
      Print("Input parameters are incorrect. Indicator can't operate!");
      return;
     }
//---- Copying data from temporary array with size of 1500 to the main array with size of FILTERPeriod
   ArrayCopy(FILTERTable,Array,0,0,FILTERPeriod);

Dentro de la función OnCalculate() el código para el cálculo del filtro es muy sencillo:

      //---- Digital filter calculation formula
      FILTER=0.0;
      for(iii = 0; iii<FILTERPeriod; iii++)
         FILTER+= FILTERTable[iii] * price[bar - iii];

La versión final del código de este indicador se encuentra en el archivo DFilter_en.mq5. La interfaz de este indicador puede mejorarse ligeramente. El hecho de que la variable de entrada del indicador tome valores desde 0 hasta 3.

input int FType = 0; //Тип фильтра
                     //0 - ФНЧ (FATL/SATL/KGLP), 1 - ФВЧ (KGHP), 2 - полосовой (RBCI/KGBP), 3 - режекторный (KGBS)

Estos valores se perciben con mayor facilidad como nombres del filtro que en forma numérica: 0 - Low-Pass Filter (FATL/SATL/KGLP), 1 - High-Pass Filter (KGHP), 2 - Band-Pass Filter (RBCI/KGBP), 3 - Band-Stop Filter (KGBS). Para este caso en MQL5 hay tipos especiales de variables llamadas enumeraciones. En nuestro caso tenemos que declarar e inicializar la enumeración antes de los parámetros de entrada del indicador:

//---- Declaration and initialization of digital filters types
enum FType_ //Filter Type
  {
   LPF, //Low-Pass Filter (FATL/SATL/KGLP)
   HPF, //High-Pass Filter (KGHP)
   BPF, //Band-Pass Filter (RBCI/KGBP)
   BSF, //Band-Stop Filter (KGBS)
  };

Después de esto tenemos que sustituir el tipo de variable usada en la declaración del parámetro externo del indicador:

input FType_ FType = LPF; //Filter Type

Como resultado la elección de los valores de este parámetro en el cuadro de diálogo del indicador es como se muestra a continuación:

Como en la declaración de la enumeración, las constantes nombradas van seguidas por comentarios de una sola línea y a continuación se eligen como parámetros de entrada. Ahora tenemos la versión final del código fuente del filtro digital universal:

//+------------------------------------------------------------------+
//|                                                      ProjectName |
//|                                      Copyright 2010, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
/*
 * <<< DIGITAL FILTERS FOR METATRADER 5 >>> *
 *
 * DF.dll file should be placed in "\MetaTrader 5\MQL5\Libraries\" folder.
 *DLL.dll requiere tres DLL adicionales, conteniendo un bloque de expresiones matemáticas
 * Estas DLLs deben instalarse en la carpeta  "C:\Windows\System32\" folder para sistemas operativos
 * Windows 32-bit o en la carpeta "C:\Windows\SysWOW64\" 
 * para sistemas operativos Windows 64-bit.
 *
 * Antes de usarloasegúresee de que:
 * 
 * 1. La opción "permitir la importación de DLL" está habilitada en la configuración del terminal de cliente
 *    (Herramientas->Opciones->Pestaña Expert Advisors).
 * 2. En "C:\Windows\System32\" o en  "C:\Windows\SysWOW64\" se encuentran las librerías matemáticas auxiliares
 *    Bdsp.dll, lapack.dll and mkl_support.dll.
 *
 * Descripción de los parámetros de entrada:
 * 
 * Ftype  - Tipo de filtro: 0 - Filtro Low-Pass (FATL/SATL/KGLP), 1 - Filtro High-Pass (KGHP),
 *          2 - Filtro Band-Pass (RBCI / KGBP), 3 - Filtro Band-Stop (KGBS)
 * P1     - Periodo de corte P1, en barras
 * D1     - Periodo de corte del proceso transitorio D1, en barras
 * A1     - Banda de retraso en la aparición A1, en dB
 * P2     - Periodo de corte P2, en barras
 * D2     - Periodo de corte del proceso transitorio D2, en barras
 * A2     - Banda de retraso en la aparición A2, en dB
 * Ripple - Pulsaciones en el ancho de banda, en dB
 * Delay  - Retraso, en barras
 *
 * Para el filtro Low-Pass y HPF se ignoran los valores de P2, D2, A2 
 *
 * Condiciones:
 * Filtro Low-Pass:                       P1>D1
 * Filtro High-Pass:                      P1<D1
 * Filtro Band-Pass y Band-Stop: D2>P2>P1>D1
 */
//+------------------------------------------------------------------+
//|      Digital Low Pass (FATL/SATL, KGLP) Filter    DFilter_en.mq5 | 
//|                    Digital Filter: Copyright (c) Sergey Ilyukhin |
//|                           Moscow, qpo@mail.ru  http://fx.qrz.ru/ |
//|                              MQL5 CODE: 2010,   Nikolay Kositsin |
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+
//---- Indicator's author
#property copyright "2005, Sergey Ilyukhin, Moscow"
//---- Author's web-site link
#property link      "http://fx.qrz.ru/"
//---- Indicator version number
#property version   "1.00"
//---- Drawing the indicator in main window
#property indicator_chart_window
//---- One buffer is used for calculating and drawing the indicator
#property indicator_buffers 1
//---- Only one graphical plotting is used
#property indicator_plots   1
//---- Drawing the indicator as line
#property indicator_type1   DRAW_LINE
//---- Blue is used as indicator's line color
#property indicator_color1  DarkViolet
//---- Indicator line is continuous curve
#property indicator_style1  STYLE_SOLID
//---- Indicator line thickness is equal to 2
#property indicator_width1  2
//---- Displaying indicator's label
#property indicator_label1  "DFilter"
//---- Declaration and initialization of digital filters types
enum FType_ //Filter Type
  {
   LPF, //Low-Pass Filter (FATL/SATL/KGLP)
   HPF, //High-Pass Filter (KGHP)
   BPF, //Band-Pass Filter (RBCI/KGBP)
   BSF, //Band-Stop Filter (KGBS)
  };

//---- Input parameters of indicator
input FType_ FType=LPF;     //Filter Type
                            //0 - Low-Pass Filter (FATL / SATL / KGLP), 1 - High-Pass Filter (KGHP), 
                            //2 - Band-Pass Filter (RBCI / KGBP), 3 - Band-Stop Filter (KGBS)
input int    P1 = 28;       //Cut-off period 1, in bars
input int    D1 = 19;       //Transient process cut-off period 1, in bars
input int    A1 = 40;       //Fading in delay band 1, in dB
input int    P2 = 0;        //Cut-off period 2, in bars
input int    D2 = 0;        //Transient process cut-off period 2, in bars
input int    A2 = 0;        //Fading in delay band 2, in dB
input int    Delay=0;       //Delay, in bars
input double Ripple=0.08;   //Beats in bandwidth, in dB
input int    FILTERShift=0; //Moving Average horizontal shift, in bars

//---- DLL Import
#import "DF.dll"
int DigitalFilter(int FType,int P1,int D1,int A1,int P2,int D2,int A2,double Ripple,int Delay,double &array[]);
#import

//---- Declaring and initializing a variable to store the number of calculated bars
int FILTERPeriod;

//---- Declaration of dynamic array, which will be 
//     used later as indicator buffer
double ExtLineBuffer[];

//---- Declaring and initializing an array for the digital filter coefficients
double FILTERTable[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+  
void OnInit()
  {
//----+
//---- Transformation of ExtLineBuffer dynamic array into indicator buffer
   SetIndexBuffer(0,ExtLineBuffer,INDICATOR_DATA);
//---- Horizontal shift of indicator by FILTERShift
   PlotIndexSetInteger(0,PLOT_SHIFT,FILTERShift);
//---- Setting the position from which the drawing of indicator will start
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,FILTERPeriod);
//---- Variable initialization for indicator's short name
   string shortname;
   StringConcatenate(shortname,"FILTER(",FILTERShift,")");
//---- Creating label to display in Data Window
   PlotIndexSetString(0,PLOT_LABEL,shortname);
//---- Creating name to display in a separate window and in tool-tip
   IndicatorSetString(INDICATOR_SHORTNAME,shortname);
//---- Defining accuracy of displaying indicator's values
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits+1);
//---- Prohibition of empty values plotting
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
//---- Calculation of digital filter coefficients and determining the size of FILTERTable[] buffer
   double Array[1500];
   FILTERPeriod=DigitalFilter(FType,P1,D1,A1,P2,D2,A2,Ripple,Delay,Array);
//----  Changing the size of FILTERTable[] buffer for required number of digital filter coefficients
   if(FILTERPeriod<=0)
     {
      Print("Input parameters are incorrect. Indicator can't operate!");
      return;
     }
//---- Copying data from temporary array with size of 1500 to the main array with size of FILTERPeriod
   ArrayCopy(FILTERTable,Array,0,0,FILTERPeriod);
//----+
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(
                const int rates_total,     // amount of history in bars at the current tick
                const int prev_calculated, // amount of history in bars at the previous tick
                const int begin,           // beginning number of reliable count of bars
                const double &price[]      // price array for indicator calculation
                )
  {
//----+   
//---- Check if the number of bars is sufficient for calculation
   if(rates_total<FILTERPeriod-1+begin)
      return(0);

//---- Declaring local variables
   int first,bar,iii;
   double Sum,FILTER;

//---- Calculating the 'first' starting number for the bars recalculation loop
   if(prev_calculated==0)         // Checking the first start of the indicator calculation
     {
      first=FILTERPeriod-1+begin; // Starting number for calculation of all bars
      //---- Increasing the start of data position by 'begin' bars, 
      //     because the calculations are based on data of another indicator
      if(begin>0)
         PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,begin+FILTERPeriod);
     }
   else first=prev_calculated-1;  // Starting number for calculation of new bars

//---- Main loop of indicator calculation
   for(bar=first; bar<rates_total; bar++)
     {
      //---- Digital filter calculation formula
      FILTER=0.0;
      for(iii = 0; iii<FILTERPeriod; iii++)
         FILTER+= FILTERTable[iii] * price[bar - iii];

      //---- Indicator buffer's cell initialization with FILTER value
      ExtLineBuffer[bar]=FILTER;
     }
//----+     
   return(rates_total);
  }
//+------------------------------------------------------------------+
La implementación en MQL5 de estos filtros digitales universales mediante el terminal de cliente acaba por completo con la necesidad de cualquier filtro digital de la empresa FinWare. Esta es una ventaja importante que abre nuevas posibilidades en el uso de estos indicadores.


Conclusión

Después de todos estos cambios en el código este contiene una gran cantidad de detalles. Pero si miramos más de cerca a los detalles de este proceso todo parece funcionar de una forma perfectamente lógica y comprensible si empezamos por el análisis de las cosas más simples y continuamos haciendo una transición de lo simple a lo complejo de forma razonable y deliberada.

Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/32

Archivos adjuntos |
dll.rar (1302.47 KB)
sma__en.mq5 (3.56 KB)
sma_1_en.mq5 (4.51 KB)
fatl_en.mq5 (6.08 KB)
dfilter_0_en.mq5 (8.17 KB)
dfilter_en.mq5 (8.42 KB)
MQL5: análisis y procesado de informes de la Comisión de Operaciones del Mercado de Futuros (CFTC) en MetaTrader 5 MQL5: análisis y procesado de informes de la Comisión de Operaciones del Mercado de Futuros (CFTC) en MetaTrader 5
En este artículo vamos a desarrollar una herramienta para el análisis de informes de la CFTC (Commodity Futures Trading Commission). Vamos a resolver los siguientes problemas: desarrollar un indicador que permita el uso de los datos de los informes de la CFTC directamente de los archivos de datos suministrados por la Comisión sin necesidad de un procesado o conversión intermedia. Además puede usarse para diferentes finalidades: para trazar los datos como un indicador, para proceder con los datos en los demás indicadores, en los scripts para el análisis automatizado y en los Expert Advisors para su uso en las estrategias de trading.
Como exportar cotizaciones desde MetaTrader 5 a aplicaciones .NET usando los servicios de WCF Como exportar cotizaciones desde MetaTrader 5 a aplicaciones .NET usando los servicios de WCF
¿Quiere organizar la exportación de cotización desde MetaTrader 5 a su propia aplicación? ¡La compatibilidad entre MQL5 y DLL permite crear este tipo de soluciones! Este artículo le mostrará una de las formas de exportar cotizaciones desde MetaTrader 5 a aplicaciones escritas en .NET. Para mí, la exportación de cotizaciones usando esta plataforma fue más interesante, racional y fácil de implementar. Por desgracia, la versión 5 todavía no soporta .NET, por lo que, como en los viejos tiempos, usaremos win32 dell con .NET como capa intermedia.
Control de eventos en MQL5: cambiar el periodo de la media móvil sobre la marcha Control de eventos en MQL5: cambiar el periodo de la media móvil sobre la marcha
Supongamos que se aplica al gráfico un simple indicador de media móvil con periodo 13. Y queremos cambiar el periodo a 20, pero no queremos ir al cuadro de diálogo de las propiedades del indicador y cambiar el número 13 por el 20: simplemente porque estamos cansados de realizar estas acciones tan tediosas con el ratón y el teclado. Y especialmente no queremos abrir el código del indicador y modificarlo. Queremos hacer todo esto con solo pulsar un botón -"flecha arriba" junto al teclado numérico. En este artículo veremos cómo hacer esto.
Dibujando emisiones de indicador en MQL5 Dibujando emisiones de indicador en MQL5
En este artículo vamos a considerar la emisión de indicadores, un nuevo enfoque de la investigación de mercados. El cálculo de la emisión se basa en la intersección de indicadores distintos: aparecen más y más puntos con diferentes colores y formas después de cada tick. Forman numerosas agrupaciones como nebulosas, nubes, rastros, líneas, arcos, etc. Estas formas ayudan a detectar los resortes ocultos y las fuerzas que afectan al movimiento de los precios del mercado.