English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Implementação prática dos filtros digitais no MQL5 para principiantes

Implementação prática dos filtros digitais no MQL5 para principiantes

MetaTrader 5Exemplos | 31 dezembro 2013, 11:26
1 619 0
Nikolay Kositsin
Nikolay Kositsin

Introdução

Então, em meu artigo anterior eu fiz uma análise de código de indicador simples e cobri levemente a interação deste indicador com o terminal do cliente do MetaTrader 5. Agora, antes de prosseguirmos, nós devemos observar mais de perto os resultados da compilação especialista na aba "Erros" da janela "Toolbox" no MetaEditor. Daqui você pode iniciar estudos aprofundados do código do SMA indicador, que eu propus anteriormente.

Erros de compilação do indicador

Em nossa situação, ao compilar qualquer uma das duas versões do código, no caso de não haver mudanças, o processo de compilação é bastante suave com o resultado esperado:


Não há erros, e junto com o arquivo indicador com extensão .mq5, apareceu o arquivo parecido com extensão .ex5.

Tipicamente, quando você trabalha com o código, você não consegue evitar erros. Eles são cometidos regularmente por programadores. Para este propósito, o MetaEditor possui um mecanismo incorporado para verificar o código compilado para todos os tipos de erros, e quando ele encontra-os, ele dará uma lista completa dos erros gerados.

Para detectar a localização de um erro, você pode simplesmente clicar duas vezes na linha apropriada com os conteúdos do erro na janela "Toolbox". O compilador, na maioria dos casos indicará corretamente a linha de código onde o erro foi encontrado, usando o ícone apropriado.

Você deve considerar uma coisa. Um erro no código pode gerar uma sequência inteira de erros de compilação. Portanto, para remover a sequência de erros, é suficiente ir à primeira linha onde o compilador encontrou o erro, e corrigir o código. Bastante naturalmente, podem haver muitas de tais sequências de erro de compilação. Portanto, após corrigir um erro no código, nós devemos recompilá-lo novamente, e se o compilador encontrar erros, então nós devemos procurar a primeira linha na aba "Erros" na janela "Toolbox":

Talvez o método mais efetivo de compreender isto será um impacto significante e destrutivo em nosso código, a fim de estudar como o compilador reagirá em erros cometidos conscientemente. A técnica é bastante simples - faça o erro em uma parte em particular do código, pressione o botão "Compilar" no MetaEditor e veja o resultado da compilação. Será ainda melhor se você intuitivamente lembrar tal resultado do impacto destrutivo no código. Em todo caso, isto pode ser útil em práticas mais avançadas, ao trabalhar com o código MQL5.

Aqui está uma lista de possíveis mudanças destrutivas no código-fonte do indicador:

  1. Fazer um espaço em qualquer operador ou variável.
  2. Limpar uma pontuação de ponto e vírgula ";".
  3. Adicionar uma pontuação ";" em diferentes partes do código.
  4. Excluir um operador.
  5. Remover ou adicionar uma chave ou um parênteses.
  6. Remover uma pontuação de vírgula ",".
  7. Adicionar um parâmetro de entrada extra na função OnCalculate().
  8. Dividir uma variável por zero.
  9. Substituir uma marcação "==" para "=" na linha de operador "if".
  10. Alterar a direção de incremento em uma variável de bar++ para bar--.

Naturalmente, o compilador nem sempre descobre o lugar com um erro, exatamente onde ele foi cometido. é por isso que vale a pena fazer este trabalho preliminar a fim de entender como lidar com tais situações. Bem, mais uma explicação relacionada a erros - o compilador MetaEditor apenas determina os erros da própria linguagem MQL5, e na maioria dos casos, ele não encontra erros lógicos de programação!

Seu vocabulário de MQL5

Se ouvir algum indivíduo em particular, então, com toda a riqueza de qualquer linguagem humana, acontece que, ele utiliza apenas uma pequena porção de ferramentas, que expressam seus pensamentos e necessidades. Na maioria das situações, constata-se que o vocabulário realmente utilizado é significativamente menor que o disponível. O mesmo princípio pode ser aplicado ao MQL5. No começo, ao dominar a linguagem MQL5, você deve acostumar-se aos operadores e expressões mais comummente utilizados desta linguagem de programação. E conforme você aprende esta linguagem, você pode gradualmente expandir as fronteiras de seu vocabulário atual.

Por exemplo, você pode usar quatro tipos de variáveis (int, double, bool, string), operador condicional if-else, operador de loop for, operador {} compound e operador return. Você deve também aprender cuidadosamente como utilizar um ponto e vírgula ";" e uma vírgula ",". Talvez fosse inteligente aprender as funções matemáticas e de trigonometria. Estas ferramentas são mais do que suficientes para treinar e praticar suas habilidades de programação iniciais!

Maior apuração do indicador

As capacidades do MQL5 como indicador de refinação, mostradas no terminal do cliente do MetaTrader, são bastante simples e comuns. Elas consistem de operadores de nível 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"

E de subrotinas 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);
A função StringConcatenate() monta a string do nome do indicador utilizando a fórmula:
   shortname = shortname + "SMA(" + MAPeriod + "," + MAShift + ")";

De acordo com as recomendações no artigo Aplicando um indicador a outro, não machucaria adicionar a chamada da função PlotIndexSetInteger() em 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
É natural que após a inclusão destas linhas adicionais de código, nosso indicador aumente ligeiramente em tamanho e torne-se um pouco mais complicado, mas agora ele possui uma interface mais amigável ao utilizador.

O resultado do trabalho anterior como um modelo para criar novos indicadores

Tudo isso é certamente interessante, mas há uma pergunta bastante natural - por que inventar a roda e repetir o código do indicador, o qual já está disponível no terminal do cliente em duas versões? Na forma de indicador técnico Moving Average.mq5 e indicador personalizado Custom Moving Average.mq5. A resposta é simples. Saber como escrever um código de indicadores similares rapidamente, apenas usando meu indicador SMA proposto como template, poupando assim seus recursos intelectuais o máximo possível! Por exemplo, você pode tentar escrever código em MQL5 para um filtro digital, como FATL da Finware.

Em geral, a fórmula para calcular o filtro digital é:

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

onde:

  • SUM — a soma.
  • K(i) — o coeficiente de ponderação.
  • CLOSE (i) — o preço Close da barra atual.
  • FilterPeriod — o número de barras para calcular a média.

Esta fórmula não difere-se muito da fórmula do indicador SMA:

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

A diferença é que o período, no qual os cálculos com um filtro digital são feitos, é estritamente fixo e é individual para o filtro digital específico, também como os coeficientes de ponderação K(i). Os próprios coeficientes de ponderação e o período do filtro digital são calculados utilizando algoritmos especializados. Analisar estes algoritmos está além do escopo deste artigo, portanto nós nos limitaremos a utilizar valores prontos para o filtro digital FATL. Aqueles que estão interessados na ideia da filtragem de sinal digital podem visitar o site Gerador de métodos digitais (em Russo). A fórmula de uma variante do indicador FATL em MQL4 não é um segredo:

     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]; 

Em MQL5, as barras nos buffers indicadores são calculadas em direção, ao contrário de um em MQL4. Portanto, para utilizar esta fórmula em indicadores MQL5, nós devemos substituir a operação incremento dentro das chaves com operação de decréscimo. Devido à ausência da ordem de série de tempo Close[] em MQL5, nós devemos também substituí-la com uma variante mais adequada - price[]. É bastante natural automatizar esta tarefa utilizando o comando de menu seguinte no MetaEditor:

A expressão regularmente encontrada Close [bar + deve ser substituída com price [bar -:

Nesta caixa de diálogo, clique no botão "Substituir todos". Como resultado, nós obtemos a fórmula necessária para o cálculo do indicador FATL em 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];

Agora nós podemos começar a codificar o indicador, cujo algoritmo de cálculo acabou de ser considerado. Para fazer isso, primeiro abra o indicador SMA_1_en.mq5 no MetaEditor e salve-o como FATL_en.mq5. O modelo do indicador está pronto, e agora nós temos que substituir o algoritmo de cálculo do indicador nele, e fazer algumas alterações nas variáveis, a maioria estéticas. Você deve selecionar o bloco inteiro da fórmula mencionada por último para o cálculo do filtro FATL, e copiá-lo à área de transferência do Windows. Depois, no código indicador FATL.mq5, remova todos os códigos dentro do operador de loop, exceto a última inicialização do buffer indicador:

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


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

Ao invés deste código excluído, nós colaremos o algoritmo de cálculo do filtro digital FATL da área de transferência do Windows. Então nós devemos substituir a palavra SMA com a FATL mais apropriada, utilizando o procedimento de substituição descrito por mim acima. De forma absolutamente igual, nós devemos substituir os nomes das variáveis de entrada MAPeriod e MAShift com FATLPeriod e FATLShift respectivamente. A variável FATLPeriod deve ser removida das variáveis externas, pois ela possui um valor fixo igual a 39. Pelo mesmo motivo, ela deve ser removida do operador StringConcatenate() na função OnInit(). Agora, não há a necessidade na variável local iii então ela pode ser removida. E, finalmente, você pode mudar a cor da linha do indicador para azul e tornar a linha azul em si um pouco mais grossa.

Após esta simples manipulação com código SMA_1_en.mq5, nós obtemos o código de indicador desejado 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);
  }
//+------------------------------------------------------------------+

Após compilar o indicador, ele pode ser testado na tabela no terminal do cliente:

É natural que o código resultante do indicador FATL possa ser usado como template para construir outros filtros similares. Mas agora o problema é muito mais simples. Em nosso código, é suficiente substituir a fórmula de cálculo do filtro, substituir a palavra FATL com DIGFILTER e inicializar (agora) a variável DIGFILTERPeriod com a dimensão requerida do filtro digital.

Solução comum para criação de filtros digitais no terminal no cliente

O indicador, que acabamos de considerar, é uma variante única de solução do problema geral da filtragem de sinal digital. Seria interessante possuir um indicador, que representa uma solução comum, permitindo construir qualquer filtro digital utilizando apenas um indicador. Este problema foi resolvido há muito tempo para o Terminal do cliente do Meta Trader 4 usando o módulo DF.dll por Sergei Ilyuhin. Portanto, seria fácil utilizá-lo para solucionar nosso problema no terminal do cliente do MetaTrader 5. Neste módulo a função DigitalFilter() é introduzida:

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

Ela permite que você receba os coeficientes do filtro digital como uma ordem array[]. A função escreve os coeficientes do filtro digital neste array com o tamanho 1500 usando referência (a marca '&' após a declaração deste tipo de variável neste array). A função aceita os valores de dez parâmetros de entrada e retorna o tamanho do filtro digital. Portanto, isto é suficiente para construir o filtro digital universal. O problema inteiro reduz-se a organizar a importação de DLL no indicador existente em um nível global, obter a ordem de coeficientes no bloco de código de inicialização do indicador, e na base destes coeficientes, executar o cálculo universal do filtro em OnCalculate(). As variáveis de entrada da função DigitalFilter() devem ser colocadas dentro de variáveis de entrada do indicador. Nós faremos isso agora mesmo.

Importar o arquivo DF.dll não causa nenhuma dificuldade. São apenas três linhas 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

Depois disso, nós tornaremos todas as variáveis externas da função DigitalFilter() variáveis de entrada de 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

Em nível global, nós vamos declarar a variável FILTERPeriod sem inicialização:

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

Em nível global nós vamos declarar uma ordem dinâmica para armazenar coeficientes de filtro:

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

Agora, vejamos o bloco da função OnInit(). Não é muito lógico utilizar a ordem FILTERTable[] como parâmetro da função DigitalFilter(). Para isso, devemos aumentar o tamanho para 1500 elementos, nos quais no bloco da função OnCalculate() apenas 100 - 200 serão usados. Nesta situação, seria melhor usar o array Array[1500] declarado localmente dentro da função OnInit(). A quantidade de dados necessária desta ordem será escrita à ordem FILTERTable[]. Após sair da função OnInit() a grande ordem Array[] será destruída, e os dados necessários permanecerão na ordem FILTERTable[], a qual terá um tamanho igual ao comprimento do filtro digital FILTERPeriod. Aqui está a variante de código que é utilizada para este propósito:

//---- 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 da função OnCalculate() o código para o cálculo do filtro é bastante simples.

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

A versão final deste código de indicador é apresentado no arquivo DFilter_en_mq5. A interface deste indicador pode ser ligeiramente melhorada. O fato de que a variável de entrada do indicador leva valores de 0 a 3.

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

Estes valores são muito mais facilmente perceptíveis não em forma numérica, mas como os nomes do filtro: 0 - Low-Pass Filter (FATL/SATL/KGLP), 1 - High-Pass Filter (KGHP), 2 - Band-Pass Filter (RBCI/KGBP), 3 - Band-Stop Filter (KGBS). Para tal caso em MQL5, há tipos especiais de variáveis chamadas de enumerações. Em nosso caso, nós temos que declarar e inicializar a enumeração antes dos parâmetros de entrada do 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)
  };

Depois disso, nós temos que substituir o tipo de variável utilizada em declaração do parâmetro externo indicador:

input FType_ FType = LPF; //Filter Type

Como um resultado, escolher os valores deste parâmetro na caixa de diálogo do indicador, fica o seguinte:

Como na declaração de enumeração as constantes nomeadas são seguidas por comentários de uma linha, então elas devem ser escolhidas como parâmetros de entrada. Agora nós temos a versão final do código-fonte do filtro digital universal:

//+------------------------------------------------------------------+
//|                                                      ProjectName |
//|                                      Copyright 2010, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
/*
 * <<>> *
 *
 * DF.dll file should be placed in "\MetaTrader 5\MQL5\Libraries\" folder.
 * DF.dll requires three additional DLLs, containing a block of mathematical 
 * processing - bdsp.dll, lapack.dll, mkl_support.dll.
 * These DLLs must be installed in "C:\Windows\System32\" folder for 
 * Windows 32-bit operating systems or in "C:\Windows\SysWOW64\" folder 
 * for Windows 64-bit operating systems.
 *
 * Before using, make sure that:
 * 
 * 1. "Allow DLL import" option is enabled in Client Terminal settings 
 *    (Tools->Options->Expert Advisors tab).
 * 2. In "C:\Windows\System32\" or in "C:\Windows\SysWOW64\" folders the
 *    Bdsp.dll, lapack.dll and mkl_support.dll auxiliary math libraries are present.
 *
 * Description of input parameters:
 * 
 * Ftype  - 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)
 * P1     - Cut-off period P1, in bars
 * D1     - Transient process cut-off period D1, in bars
 * A1     - Fading in delay band A1, in dB
 * P2     - Cut-off period P2, in bars
 * D2     - Transient process cut-off period D2, in bars
 * A2     - Fading in delay band A2, in dB
 * Ripple - Beats in bandwidth, in dB
 * Delay  - Delay, in bars
 *
 * For Low-Pass Filter and HPF the values of P2, D2, A2 are ignored
 *
 * Conditions:
 * Low-Pass Filter:                       P1>D1
 * High-Pass Filter:                      P1P2>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);
  }
//+------------------------------------------------------------------+
A implementação de MQL5 de tal filtro digital universal apenas por meio do terminal cliente encerra completamente a necessidade para qualquer filtro digital da companhia FinWare. Esta é uma conveniência significante, que abre novas possibilidades para utilizar estes indicadores.

Conclusão

Após todas estas manipulações com código, esta obteve muitos detalhes. Mas em uma observação mais próxima destes detalhes do processo, tudo funciona com lógica e entendimento perfeito, se nós iniciarmos com a análise da maioria das coisas simples e continuarmos a fazer a transição significativa e deliberada de simples para complexas.

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/32

Arquivos anexados |
dfilter_0_en.mq5 (8.17 KB)
dfilter_en.mq5 (8.42 KB)
fatl_en.mq5 (6.08 KB)
sma__en.mq5 (3.56 KB)
sma_1_en.mq5 (4.51 KB)
MQL5: análise e processamento dos relatórios Commodity Futures Trading Commission (CFTC) no MetaTrader 5 MQL5: análise e processamento dos relatórios Commodity Futures Trading Commission (CFTC) no MetaTrader 5
Neste artigo, desenvolverei uma ferramenta para análise de relatório CFTC. Resolveremos o seguinte problema: desenvolver um indicador que permita usar os dados do relatório CFTC diretamente dos arquivos de dados fornecidos pela Comissão sem conversão e processamento intermediários. Além disso, ele pode ser utilizado para diferentes propósitos: organizar dados como um indicador, prosseguir com os dados em outros indicadores, em scripts para análise automatizada, em Expert Advisors para uso em estratégias de trading.
Como exportar cotações do MetaTrader5 para aplicações .NET usando serviços WCF Como exportar cotações do MetaTrader5 para aplicações .NET usando serviços WCF
Quer organizar a exportação de cotas do MetaTrader 5 para sua própria aplicação? A junção MQL5-DLL permite criar essas soluções! Este artigo mostrará a você um dos meios de exportação de cotas do MetaTrader 5 para aplicações escritas no .NET. Para mim, é mais interessante, racional e fácil implementar a exportação de cotas usando esta mesma plataforma. Infelizmente, a versão 5 ainda não suporta .NET, então, como antigamente, usaremos o win32 dll com suporte .NET como intercamada.
Tratamento de eventos no MQL5: mudando período MA rapidamente Tratamento de eventos no MQL5: mudando período MA rapidamente
Suponha que um simples indicador MA (média móvel) com período 13 seja aplicado ao gráfico. Queremos mudar o período para 20, mas não queremos ir até a caixa de diálogo de propriedades do indicador e editar o número 13 para 20: por simples cansaço destas ações tediosas com o mouse e teclado. E, especialmente, não queremos abrir o código do indicador e modificá-lo. Queremos fazer tudo isso simplesmente pressionando um botão - "setas para cima" próximas ao teclado numérico. Neste artigo, descreverei como fazer isso.
Desenhando emissões de indicador no MQL5 Desenhando emissões de indicador no MQL5
Neste artigo, consideraremos a emissão dos indicadores - uma nova abordagem para pesquisa de mercado. O cálculo da emissão é baseado na intersecção de diferentes indicadores: mais e mais pontos com diferentes cores e formas aparecem após cada tick. Eles formam vários clusters na forma de uma nebulosa, nuvens, pistas, linhas, arcos, etc. Estas formas podem ajudar a detectar as molas e forças invisíveis que afetam o movimento dos preços do mercado.