English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Implementazione Pratica di Filtri Digitali in MQL5 per Principianti

Implementazione Pratica di Filtri Digitali in MQL5 per Principianti

MetaTrader 5Esempi | 15 dicembre 2021, 17:07
118 0
Nikolay Kositsin
Nikolay Kositsin

Introduzione

Quindi, nel mio precedente articolo ho fatto un'analisi del codice di un semplice indicatore e ho trattato leggermente l'interazione di questo indicatore con MetaTrader 5 Client Terminal. Ora, prima di andare oltre, dovremmo dare un'occhiata più da vicino ai risultati della compilazione degli expert nel tab "Errors" della finestra "Toolbox" in MetaEditor. Da qui puoi iniziare un ulteriore approfondimento del codice dell'indicatore SMA che avevo proposto in precedenza.

Errori di compilazione dell'indicatore

Nella nostra situazione, quando si compila una delle due versioni del codice, in caso di assenza di modifiche il processo di compilazione è abbastanza fluido con il risultato atteso:


Non ci sono errori e insieme al file indicatore con estensione .mq5 è apparso il file simile con estensione .ex5.

In genere, quando lavori con il codice non puoi evitare gli errori. Sono regolarmente realizzati da programmatori. A questo scopo MetaEditor ha un meccanismo integrato per controllare il codice compilato per tutti i tipi di errori e quando li trova fornirà un elenco completo degli errori generati.

Per rilevare la posizione di un errore è sufficiente fare doppio clic sulla riga appropriata con il contenuto dell'errore nella finestra "Casella degli strumenti". Il compilatore nella maggior parte dei casi indicherà accuratamente la riga di codice in cui è stato rilevato l'errore, utilizzando l'icona appropriata.

Dovresti considerare una cosa. Un errore nel codice può generare un'intera sequenza di errori di compilazione. Quindi, per rimuovere la sequenza di errori, è sufficiente andare alla prima riga dove il compilatore ha trovato un errore e correggere il codice. Naturalmente, ci possono essere molte di queste sequenze di errori di compilazione. Quindi, dopo aver corretto un errore nel codice, dobbiamo ricompilarlo di nuovo e se il compilatore trova errori, dobbiamo cercare la prima riga nella scheda "Errors" della finestra "Toolbox":

Forse il metodo più efficace per comprendere questo sarà un impatto significativo e distruttivo sul nostro codice per studiare come reagirà il compilatore agli errori commessi consapevolmente. La tecnica è abbastanza semplice: fai l'errore in una parte particolare del codice, premi il pulsante "Compila" in MetaEditor e guarda il risultato della compilazione. Sarà ancora meglio se ricordi intuitivamente tale risultato d’ impatto distruttivo sul codice. In ogni caso questo può essere utile in un’ulteriore pratica quando si lavora con il codice MQL5.

Ecco l'elenco dei possibili cambiamenti distruttivi nel codice sorgente dell'indicatore:

  1. Creare uno spazio in qualsiasi operatore o variabile.
  2. Cancellazione di un punto e virgola ";" segnare.
  3. Aggiungendo un ";" come contrassegno in diverse parti del codice.
  4. Eliminazione di un operatore.
  5. Rimozione o aggiunta di una parentesi graffa o di una parentesi.
  6. Rimozione di una virgola "," come contrassegno.
  7. Aggiunta di un parametro di input aggiuntivo nella funzione OnCalculate().
  8. Dividere una variabile per zero.
  9. Sostituzione di un segno "==" a "=" nella riga dell'operatore "if".
  10. Modifica della direzione di incremento in una variabile da bar++ a bar--.

Naturalmente, il compilatore non sempre trova il posto con un errore proprio dove è stato fatto. Ecco perché vale la pena fare questo lavoro preliminare per capire come affrontare tali situazioni. Bene, un'altra spiegazione sugli errori: il compilatore MetaEditor determina solo gli errori del linguaggio MQL5 stesso e nella maggior parte dei casi non trova errori logici di programmazione!

Il tuo vocabolario MQL5

Se ascolti, allora, un individuo in particolare con tutta la ricchezza di qualsiasi linguaggio umano, scoprirai che usa solo una piccola parte di strumenti che esprimono i suoi pensieri e le sue esigenze. Nella maggior parte delle situazioni, risulta che il vocabolario effettivamente utilizzato è significativamente più piccolo di quello disponibile. Lo stesso principio può essere applicato a MQL5. All'inizio, mentre impari il linguaggio MQL5, dovresti abituarti agli operatori e alle espressioni più comunemente usati di questo linguaggio di programmazione. E man mano che impari questa lingua, puoi espandere gradualmente i confini del tuo vero vocabolario.

Ad esempio, è possibile utilizzare quattro tipi di variabili (int, double, bool, string), operatore condizionale if-else, operatore ciclo for, operatore compound {} e operatore di return. Dovresti anche imparare a fondo come usare un punto e virgola ";" e una virgola ",". Forse sarebbe saggio imparare le funzioni matematiche e trigonometriche. Questi strumenti sono più che sufficienti per allenare e mettere in pratica le tue abilità di programmazione iniziali!

Ulteriore affinamento dell'indicatore

Le funzionalità MQL5 dell'indicatore di raffinamento, visualizzate in MetaTrader Client Terminal, sono abbastanza semplici e standard. Sono costituiti da operatori di livello globale:

//---- 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 delle chiamate di funzione di 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 funzione StringConcatenate() assembla la stringa del nome dell'indicatore utilizzando questa formula:
   shortname = shortname + "SMA(" + MAPeriod + "," + MAShift + ")";

Secondo i consigli nell'articolo Applicazione di un Indicatore a un Altro, non sarebbe male aggiungere la chiamata alla funzione PlotIndexSetInteger() in 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
È naturale che dopo l'inclusione di queste righe di codice aggiuntive, il nostro indicatore sia leggermente aumentato di dimensioni e sia diventato un po' più complicato, ma ora ha un'interfaccia più intuitiva.

Il risultato del lavoro precedente come modello per la creazione di nuovi indicatori

Tutto questo è sicuramente interessante, ma sorge spontanea una domanda: perché inventare la ruota e ripetere il codice dell'indicatore, già disponibile nel Client Terminal in due versioni? Sotto forma di indicatore tecnico Moving Average.mq5 e indicatore personalizzato Custom Moving Average.mq5. La risposta è semplice. Per imparare a scrivere rapidamente il codice di indicatori simili, semplicemente utilizzando il codice dell'indicatore SMA precedentemente proposto come modello, risparmiando così il più possibile le tue risorse intellettuali! Ad esempio, puoi provare a scrivere codice in MQL5 per un filtro digitale, come FATL da Finware.

In generale, la formula per il calcolo del filtro digitale è:

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

dove:

  • SUM— la somma.
  • K(i) — il coefficiente di ponderazione.
  • CLOSE (i) — il prezzo dI Chiusura della barra corrente.
  • FilterPeriod — il numero di barre per la media. 

Questa formula non differisce molto dalla formula dell'indicatore SMA:

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

La differenza è che il periodo su cui vengono effettuati i calcoli con un filtro digitale, è strettamente fisso ed è individuale per filtro digitale specifico, come i coefficienti di ponderazione K(i). I coefficienti di ponderazione stessi e il periodo del filtro digitale sono calcolati utilizzando algoritmi specializzati. L'analisi di questi algoritmi va oltre lo scopo di questo articolo, quindi ci limiteremo a utilizzare i valori pronti per il filtro digitale FATL. Coloro che sono interessati all'idea del filtraggio del segnale digitale, possono visitare il sito Web Digital Methods Generator (in russo). La formula di una variante dell'indicatore FATL in MQL4 non è un segreto:

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

In MQL5 le barre nei buffer indicatori sono calcolate in direzione opposta a quella in MQL4. Quindi, per utilizzare questa formula negli indicatori MQL5, dobbiamo sostituire l'operazione di incremento all'interno delle parentesi con l'operazione di decremento. A causa dell'assenza dell'array della serie temporale Close[] in MQL5, dobbiamo anche sostituirlo con una variante più adatta - price[]. È abbastanza naturale automatizzare questa attività utilizzando il seguente comando di menu in MetaEditor:

L'espressione Close [bar +regolarmente soddisfatta, dovrebbe essere sostituita con prezzo [bar - :

In questa finestra di dialogo fare clic sul pulsante "Sostituisci tutto". Di conseguenza, otteniamo la formula richiesta per il calcolo dell'indicatore FATL in 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];

Ora possiamo iniziare a codificare l'indicatore, quale algoritmo di calcolo è stato appena considerato. Per fare ciò, prima di tutto apri l'indicatore SMA_1_en.mq5 in MetaEditor e salvalo come FATL_en.mq5. Il modello di indicatore è pronto e ora dobbiamo sostituire l'algoritmo di calcolo dell'indicatore al suo interno e apportare alcune modifiche alle variabili, per lo più estetiche. È necessario selezionare l'intero blocco dell'ultima formula menzionata per il calcolo del filtro FATL e copiarlo negli appunti di Windows. Quindi, ora nel codice dell'indicatore FATL.mq5, rimuovere tutto il codice all'interno dell'operatore del ciclo, tranne l'ultima inizializzazione del buffer dell'indicatore:

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


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

Invece di questo codice cancellato, incolleremo l'algoritmo di calcolo del filtro digitale FATL dagli appunti di Windows. Quindi dovremmo sostituire la parola SMA con FATL più appropriato, utilizzando la procedura di sostituzione descritta da me sopra. Assolutamente lo stesso, dovremmo sostituire i nomi delle variabili di input MAPeriod e MAShift rispettivamente con FATLPeriod e FATLShft. La variabile FATLPeriod deve essere rimossa dalle variabili esterne, perché ha un valore fisso pari a 39. Per lo stesso motivo, dovrebbe essere rimosso dall'operatore StringConcatenate() nella funzione OnInit(). Ora non c'è bisogno della variabile locale iii, quindi può essere rimossa. E infine, puoi cambiare il colore della linea dell'indicatore in blu e rendere la linea stessa un po' più spessa.

Dopo queste semplici manipolazioni con il codice SMA_1_en.mq5 otteniamo il codice indicatore desiderato 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);
  }
//+------------------------------------------------------------------+

Dopo aver compilato l'indicatore può essere testato sul grafico nel Terminale Client:

È naturale che il codice risultante dell'indicatore FATL possa essere utilizzato come modello per la costruzione di altri filtri simili. Ma ora il problema è molto più semplice. Nel nostro codice è sufficiente sostituire la formula di calcolo del filtro, sostituire la parola FATL con DIGFILTER, e inizializzare (ora) la variabile DIGFILTERPeriod con la dimensione richiesta del filtro digitale.

Soluzione comune per la creazione di filtri digitali nel Terminale Client

L'indicatore, che abbiamo appena considerato, è un'unica variante per risolvere il problema generale del filtraggio del segnale digitale. Sarebbe bello avere un indicatore che rappresenti una soluzione comune che permetta di costruire qualsiasi filtro digitale utilizzando un solo indicatore. Questo problema è stato risolto molto tempo fa per MetaTrader 4 Terminale Client utilizzando il modulo DF.dll di Sergei Ilyuhin. Quindi, sarebbe facile usarlo per risolvere il nostro problema in MetaTrader 5 Terminale Client. In questo modulo viene introdotta la funzione DigitalFilter():

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

Consente di ricevere i coefficienti del filtro digitale come l’array [] array. La funzione scrive i coefficienti del filtro digitale in questo array con dimensione 1500 utilizzando il riferimento (il segno '&' dopo la dichiarazione di questo tipo di variabile in questo array). La funzione accetta i valori di dieci parametri di input e restituisce la dimensione del filtro digitale. Quindi, questo è abbastanza per costruire il filtro digitale universale. L'intero problema si riduce all'organizzazione dell'importazione DLL nell'indicatore esistente a livello globale, ottenendo l'array di coefficienti nel blocco di codice di inizializzazione dell'indicatore e sulla base di questi coefficienti eseguendo il calcolo universale del filtro in OnCalculate(). Le variabili di input della funzione DigitalFilter() devono essere inserite nelle variabili di input dell'indicatore. Lo faremo subito.

L'importazione del file DF.dll non causa alcuna difficoltà. Sono solo tre righe di codice:

//---- 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

Dopodiché, faremo in modo che tutte le variabili esterne di DigitalFilter()funzionino come variabili di input dell'indicatore:

//---- 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 livello globale dichiareremo la variabile FILTERPeriod senza inizializzazione:

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

A livello globale dichiareremo un array dinamico per memorizzare i coefficienti di filtro:

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

Ora entriamo nel blocco della funzione OnInit(). Non è del tutto logico utilizzare l'array FILTERTable[] come parametro della funzione DigitalFilter(). Per questo lo faremmo dimensionare fino a 1500 elementi, di cui nel blocco funzione OnCalculate() verranno utilizzati solo 100 - 200. In tale situazione sarebbe meglio utilizzare l'array Array[1500]dichiarato localmente all'interno della funzione OnInit(). La quantità necessaria di dati da questo array verrà scritta nell'array FILTERTable[]. Dopo essere usciti dalla funzione OnInit(), l'array grande Array[] verrà distrutto e i dati necessari rimarranno nell'array FILTERTable[], che avrà una dimensione pari alla lunghezza del filtro digitale FILTERPeriod. Ecco la variante di codice che viene utilizzata per questo scopo:

//---- 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);

All'interno della funzione OnCalculate() il codice per il calcolo del filtro è abbastanza semplice:

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

La versione finale di questo codice indicatore è presentata nel file DFilter_en.mq5. L'interfaccia di questo indicatore può essere leggermente migliorata. Il fatto è che la variabile di input dell'indicatore assume valori da 0 a 3.

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

Questi valori sono molto più facili da percepire non in forma numerica, ma come i nomi del filtro: 0 - Filtro Low-Pass (FATL/SATL/KGLP), 1 - Filtro High-Pass (KGHP), 2 - Filtro Band-Pass (RBCI/KGBP), 3 - Filtro Band-Stop (KGBS). Per un caso del genere in MQL5 ci sono tipi speciali di variabili, chiamate enumerazioni. Nel nostro caso, dobbiamo dichiarare e inizializzare l'enumerazione prima dei parametri di input dell'indicatore:

//---- 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)
  };

Successivamente, dobbiamo sostituire il tipo di variabile utilizzata nella dichiarazione del parametro esterno dell'indicatore:

input FType_ FType = LPF; //Filter Type

Di conseguenza, la scelta dei valori di questo parametro nella finestra di dialogo dell'indicatore appare come segue:

Come nella dichiarazione di enumerazione le costanti nominate sono seguite da commenti a riga singola, quindi devono essere scelte come parametri di input. Ora abbiamo la versione finale del codice sorgente del filtro digitale universale:

//+------------------------------------------------------------------+
//|                                                      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.
 * 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:                      P1<D1
 * Band-Pass Filter and Band-Stop Filter: 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);
  }
//+------------------------------------------------------------------+
L'implementazione MQL5 di tale filtro digitale universale solo tramite Terminale Client elimina completamente la necessità di qualsiasi filtro digitale della società FinWare. Questa è una comodità significativa che apre nuove possibilità nell'uso di questi indicatori.

Conclusione

Dopo tutte queste manipolazioni con il codice ha ottenuto molti dettagli. Ma con uno sguardo più attento ai dettagli di questo processo, tutto funziona perfettamente in maniera logica e comprensibile, se iniziamo con l'analisi delle cose più semplici e continuiamo a fare una transizione significativa e deliberata dal semplice al complesso.

Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/32

File allegati |
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: Analisi ed Elaborazione dei Report della Commodity Futures Trading Commission (CFTC) in MetaTrader 5 MQL5: Analisi ed Elaborazione dei Report della Commodity Futures Trading Commission (CFTC) in MetaTrader 5
In questo articolo, svilupperemo uno strumento per l'analisi dei report CFTC. Risolveremo il seguente problema: sviluppare un indicatore che consenta di utilizzare i dati del report CFTC direttamente dai file di dati forniti dalla Commissione senza un'elaborazione e una conversione intermedie. Inoltre, può essere utilizzato per i diversi scopi: tracciare i dati come indicatore, procedere con i dati negli altri indicatori, negli script per l'analisi automatizzata, negli Expert Advisor per l'uso nelle strategie di trading.
Come Esportare Quotazioni da МetaTrader 5 ad Applicazioni .NET Utilizzando i Servizi WCF Come Esportare Quotazioni da МetaTrader 5 ad Applicazioni .NET Utilizzando i Servizi WCF
Vuoi organizzare l'esportazione delle quotazioni da MetaTrader 5 alla tua applicazione? La giunzione MQL5-DLL permette di creare tali soluzioni! Questo articolo ti mostrerà uno dei modi per esportare le quotazioni da MetaTrader 5 ad applicazioni scritte in .NET. Per me è stato più interessante, razionale e facile implementare l'esportazione dei preventivi utilizzando proprio questa piattaforma. Sfortunatamente, la versione 5 non supporta ancora .NET quindi, come ai vecchi tempi, utilizzeremo win32 dll con supporto .NET come interlayer.
Gestione degli Eventi in MQL5: Modifica del periodo MA al volo Gestione degli Eventi in MQL5: Modifica del periodo MA al volo
Supponiamo che un semplice indicatore MA (Media Mobile) con periodo 13 sia applicato a un grafico. E vogliamo cambiare il punto in 20, ma non vogliamo andare alla finestra di dialogo delle proprietà dell'indicatore e modificare il numero da 13 a 20: semplicemente stanchi di queste noiose azioni con mouse e tastiera. E soprattutto non vogliamo aprire il codice dell'indicatore e modificarlo. Vogliamo fare tutto questo premendo un pulsante - "frecce su" accanto al tastierino numerico. In questo articolo descriverò come farlo.
Disegnare le Emissioni di Indicatori in MQL5 Disegnare le Emissioni di Indicatori in MQL5
In questo articolo, prenderemo in considerazione l'emissione di indicatori: un nuovo approccio alla ricerca di mercato. Il calcolo dell'emissione si basa sull'intersezione di diversi indicatori: dopo ogni tick, compaiono sempre più punti con colori e forme differenti. Formano numerosi ammassi come nebulose, nuvole, tracce, righe, archi, ecc. Queste forme aiutano a rilevare le molle e le forze invisibili che influenzano il movimento dei prezzi di mercato.