English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Creazione di un Indicatore con più Indicatori Buffer per Principianti

Creazione di un Indicatore con più Indicatori Buffer per Principianti

MetaTrader 5Esempi | 16 dicembre 2021, 10:02
222 0
Nikolay Kositsin
Nikolay Kositsin

Introduzione

Nei miei precedenti articoli "Indicatori personalizzati in MQL5 per Principianti" e "Implementazione pratica di filer digitali in MQL5 per Principianti" Mi sono concentrato nel dettaglio sulla struttura dell'indicatore con un buffer di indicatori.

Ovviamente, un simile metodo può essere ampiamente applicato per scrivere indicatori personalizzati, ma la vita reale difficilmente può essere limitata al loro utilizzo e, quindi, è tempo di avvicinarsi a metodi più complessi per costruire il codice dell'indicatore. Fortunatamente le capacità di MQL5 sono davvero inesauribili e sono limitate solo dalla RAM dei nostri PC.


L'indicatore Aroon come esempio di raddoppio del codice

La formula di questo indicatore contiene due componenti: gli indicatori al rialzo e al ribasso che sono tracciati in una finestra del grafico separata:

BULLS =  (1 - (bar - SHIFT(MAX(HIGH(), AroonPeriod)))/AroonPeriod) * 100
ORSI = (1 - (bar - SHIFT(MIN (LOW (), AroonPeriod)))/AroonPeriod) * 100

dove:

  • BULLS - la forza del Toro;
  • BEARS - la forza dell'Orso;
  • SHIFT() - funzione di determinazione della posizione dell'indice della barra;
  • MAX() - funzione di ricerca del massimo nel periodo AroonPeriod;
  • MIN() - funzione di ricerca del minimo nel periodo AroonPeriod;
  • HIGH() e LOW() - i relativi array di prezzi;

Proprio dalle formule dell'indicatore, possiamo concludere che per costruire un indicatore, dobbiamo avere solo due buffer di indicatori, la struttura dell'indicatore differirà molto poco dalla struttura dello SMA_1.mq5, considerata nell'articolo precedente.

In pratica, è semplicemente lo stesso codice duplicato, con diversi numeri di buffer indicatori. Quindi, apriamo il codice di questo indicatore nel MetaEditor e salviamo come Aroon.mq5. Ora, nelle prime 11 righe del codice, che riguarda il copyright e il suo numero di versione, sostituiremo solo il nome dell'indicatore:

//+------------------------------------------------------------------+
//|                                                        Aroon.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
//---- copyright
#property copyright "2010, MetaQuotes Software Corp."
//---- link to the author's site
#property link      "http://www.mql5.com"
//---- version number
#property version   "1.00"

Successivamente, nella dodicesima riga di codice, è necessario modificare il tracciato dell'indicatore dalla finestra del grafico di base alla finestra separata:

//---- plot indicator in the separate window
#property indicator_separate_window

Poiché questo indicatore ha un intervallo di valori completamente diverso, il suo grafico verrà eseguito in una finestra separata.

Successivamente, nelle seguenti 4 righe del codice (le proprietà generali dell'indicatore), cambiamo il numero dei buffer dell'indicatore utilizzati in due:

//---- two buffers are used
#property indicator_buffers 2
//---- two plots are used 
#property indicator_plots   2

Le successive 10 righe di codice sono relative al tracciamento dell'indicatore da uno specifico buffer indicatore, la sua etichetta deve essere duplicata, dopodiché dobbiamo sostituire tutti gli indici da 1 a 2. Dobbiamo anche cambiare tutte le etichette dei buffer indicatori:

//+----------------------------------------------+
//| bullish strength indicator parameters        |
//+----------------------------------------------+
//---- drawing style = line
#property indicator_type1   DRAW_LINE
//---- drawing color = Lime
#property indicator_color1  Lime
//---- line style = solid line
#property indicator_style1  STYLE_SOLID
//---- line width = 1
#property indicator_width1  1
//---- label of the BullsAroon indicator
#property indicator_label1  "BullsAroon"
//+----------------------------------------------+
//|  bearish strength indicator parameters       |
//+----------------------------------------------+
//---- drawing style = line
#property indicator_type2   DRAW_LINE
//---- drawing color = Red
#property indicator_color2  Red
//---- line style = solid line
#property indicator_style2  STYLE_SOLID
//---- line width = 1
#property indicator_width2  1
//---- label of the BearsAroon indicator
#property indicator_label2  "BearsAroon"

Questo indicatore utilizza tre livelli orizzontali con i valori di 30, 50 e 70.

Per tracciare questi livelli, dobbiamo aggiungere altre cinque righe di codice al codice dell'indicatore.

//+----------------------------------------------+
//| Horizontal levels                            |
//+----------------------------------------------+
#property indicator_level1 70.0
#property indicator_level2 50.0
#property indicator_level3 30.0
#property indicator_levelcolor Gray
#property indicator_levelstyle STYLE_DASHDOTDOT

Per i parametri di input dell'indicatore, rispetto all'indicatore precedente, tutto rimane invariato, a parte piccole modifiche ai titoli:

//+----------------------------------------------+
//| Indicator input parameters                   |
//+----------------------------------------------+
input int AroonPeriod = 9; // Period 
input int AroonShift = 0// Horizontal shift of the indicator in bars 

 Ora, tuttavia, ci saranno due array, che verranno utilizzati come buffer indicatori e avranno nomi appropriati:

//--- declare the dynamic arrays used further as indicator buffers
double BullsAroonBuffer[];
double BearsAroonBuffer[]; 

Procediamo allo stesso modo con il codice della funzione OnInit().

Innanzitutto, modifichiamo le righe di codice del buffer zero:

//--- set BullsAroonBuffer dynamic array as indicator buffer 
SetIndexBuffer(0, BullsAroonBuffer, INDICATOR_DATA);
//--- horizontal shift (AroonShift) of the indicator 1
PlotIndexSetInteger(0, PLOT_SHIFT, AroonShift);
//--- plot draw begin (AroonPeriod) of the indicator 1
PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, AroonPeriod);
//--- label shown in DataWindow
PlotIndexSetString(0, PLOT_LABEL, "BearsAroon"); 

Successivamente, copia l'intero codice negli appunti di Windows e incollalo subito dopo lo stesso codice.

Quindi, nel codice incollato, cambiamo il numero del buffer dell'indicatore da 0 a 1, cambiamo il nome dell'array dell'indicatore e l'etichetta dell'indicatore:

//--- set BearsAroonBuffer dynamic array as indicator buffer 
SetIndexBuffer(1, BearsAroonBuffer, INDICATOR_DATA); 
//--- horizontal shift (AroonShift) of the indicator 2 
PlotIndexSetInteger(1, PLOT_SHIFT, AroonShift); 
//--- plot draw begin (AroonPeriod) of the indicator 2 
PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, AroonPeriod); 
//--- label shown in DataWindow 
PlotIndexSetString(1, PLOT_LABEL, "BullsAroon");  

Anche il nome breve dell'indicatore ha subito lievi modifiche:

//--- initialization of the variable for a short indicator name
string shortname;
StringConcatenate(shortname, "Aroon(", AroonPeriod, ", ", AroonShift, ")"); 

Ora, consideriamo l'accuratezza nel tracciare l'indicatore. L'intervallo effettivo dell'indicatore va da 0 a 100 e questo intervallo viene sempre visualizzato.

In questa situazione, è del tutto possibile utilizzare solo i valori interi dell'indicatore, tracciati sul grafico. Per questo motivo, usiamo 0 per i numeri dopo la virgola, per l'indicatore che traccia:

//--- set accuracy of drawing of indicator values
IndicatorSetInteger(INDICATOR_DIGITS, 0);

Nell'indicatore SMA_1.mq5, abbiamo utilizzato la prima forma della chiamata alla funzione OnCalculate().

Non è adatto per l'indicatore Aroon, a causa della mancanza degli array di prezzo alto[] e basso[]. Questi array sono disponibili nella seconda forma di chiamata di questa funzione. E, quindi, è necessario modificare l'intestazione della funzione:

int OnCalculate( 
                const int rates_total,    // total bars on the current tick
                const int prev_calculated,// total bars on the previous tick
                const datetime& time[],
                const double& open[],    
                const double& high[],     // price array of the maximum prices for the indicator calculations
                const double& low[],      // price array of the minimum prices for the indicator calculations
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[]
              )

Dopo questa modifica, l'uso del parametro begin ha perso ogni significato, quindi deve essere rimosso dal codice!

Il codice per il calcolo dei limiti delle variazioni variabili del ciclo operativo, la verifica dei dati per la sufficienza di calcolo, è rimasto praticamente invariato.

//--- checking the number of bars
if (rates_total < AroonPeriod - 1) return(0);
   
//--- declare the local variables 
int first, bar;
double BULLS, BEARS; 

//--- calculation of the first (staring index) for the main loop
if (prev_calculated == 0)          // checking for the first call of the OnCalculate function
    first = AroonPeriod - 1;       // starting index for calculating all of the bars 
else first = prev_calculated - 1// starting index for calculating new bars

Tuttavia, alcuni problemi si presentano con gli algoritmi per il calcolo dei valori degli indicatori. Il problema è che MQL5 non ha le funzioni integrate per determinare gli indici del massimo e del minimo, per il periodo dalla barra corrente, nella direzione dell'indice decrescente.

Una via d'uscita da questa situazione è scrivere noi queste funzioni. Fortunatamente, tali funzioni esistono già nell'indicatore ZigZag.mq5 all'interno degli indicatori personalizzati, che si trova nella cartella "MetaTrader5\MQL5\Indicators\Examples".

La via d'uscita più semplice è selezionare il codice di queste funzioni nell'indicatore ZigZag.mq5, copiarle negli appunti di Windows e incollarle nel nostro codice, ad esempio, subito dopo aver descritto la funzione OnInit(), al livello globale livello:

//+------------------------------------------------------------------+
//|  searching index of the highest bar                              |
//+------------------------------------------------------------------+
int iHighest(const double &array[], // array for searching for the index of the maximum element
             int count,            // number of the elements in the array (in the decreasing order), 
             int startPos          // starting index
             )                     
  {
//---+
   int index = startPos;
   
   //---- checking the starting index
   if (startPos < 0)
     {
      Print("Incorrect value in the function iHighest, startPos = ", startPos);
      return (0);
     } 
   //---- checking the startPos values
   if (startPos - count < 0) count = startPos;
    
   double max = array[startPos];
   
   //---- index search
   for(int i = startPos; i > startPos - count; i--)
     {
      if(array[i] > max)
        {
         index = i;
         max = array[i];
        }
     }
//---+ return of the index of the largest bar
   return(index);
  }
//+------------------------------------------------------------------+
//|  searching index of the lowest bar                               |
//+------------------------------------------------------------------+
int iLowest(
            const double &array[], // array for searching for the index of the maximum element
            int count,            // number of the elements in the array (in the decreasing order),
            int startPos          // starting index
            ) 
{
//---+
   int index = startPos;
   
   //--- checking the stating index
   if (startPos < 0)
     {
      Print("Incorrect value in the iLowest function, startPos = ",startPos);
      return(0);
     }
     
   //--- checking the startPos value
   if (startPos - count < 0) count = startPos;
    
   double min = array[startPos];
   
   //--- index search
   for(int i = startPos; i > startPos - count; i--)
     {
      if (array[i] < min)
        {
         index = i;
         min = array[i];
        }
     }
//---+ return of the index of the smallest bar
   return(index);
  }

Successivamente, il codice della funzione OnCalculate() avrà il seguente aspetto:

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate( const int rates_total,    // total number of bars on the current tick
               const int prev_calculated,// number of calculated bars on the previous tick
               const datetime& time[],
               const double& open[],    
               const double& high[],     // price array for the maximum price for the indicator calculation
               const double& low[],      // price array for the minimum price for the indicator calculation
               const double& close[],
               const long& tick_volume[],
               const long& volume[],
               const int& spread[]
             )
  {
//---+   
   //--- checking the number of bars
   if (rates_total < AroonPeriod - 1)
    return(0);
   
   //--- declare the local variables 
   int first, bar;
   double BULLS, BEARS;
   
   //--- calculation of the starting bar number
   if (prev_calculated == 0// checking for the first start of the indicator calculation
     first = AroonPeriod - 1; // starting number for the calculation of all of the bars

   else first = prev_calculated - 1; // starting number for the calculation of new bars

   //--- main loop
   for(bar = first; bar < rates_total; bar++)
    {
     //--- calculation of values
     BULLS = 100 - (bar - iHighest(high, AroonPeriod, bar) + 0.5) * 100 / AroonPeriod;
     BEARS = 100 - (bar - iLowest (low,  AroonPeriod, bar) + 0.5) * 100 / AroonPeriod;

     //--- filling the indicator buffers with the calculated values 
     BullsAroonBuffer[bar] = BULLS;
     BearsAroonBuffer[bar] = BEARS;
    }
//---+     
   return(rates_total);
  }
//+------------------------------------------------------------------+

Per la simmetria degli assi ho leggermente corretto nel codice, aggiungendo lo spostamento verticale dell'indicatore, rispetto a quello originale, utilizzando il valore di 0,5.

Ecco i risultati del lavoro di questo indicatore sul grafico:

                                                                              

Per trovare la posizione dell'elemento con i valori massimo o minimo su una distanza non superiore ad AroonPeriod dalla barra corrente possiamo utilizzare le funzioni ArrayMaximum() e ArrayMinimum() di MQL5 che cercano anche gli estremi, ma queste le funzioni eseguono la ricerca utilizzando l'ordine crescente.

Tuttavia, la ricerca deve essere eseguita in ordine decrescente di indici. Per questo caso la soluzione più semplice è cambiare la direzione dell'indicizzazione nell'indicatore e nei buffer dei prezzi, utilizzando la funzione ArraySetAsSeries().

Ma dobbiamo anche cambiare la direzione dell'ordinamento delle barre nel ciclo di calcolo e cambiare l'algoritmo del primo calcolo della variabile.

In questo caso la funzione OnCalculate() risultante sarà simile a questa:

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(
                const int rates_total,    // total number of bars on the current tick
                const int prev_calculated,// number of calculated bars on the previous tick
                const datetime& time[],
                const double& open[],    
                const double& high[],     // price array for the maximum price for the indicator calculation
                const double& low[],      // price array for the minimum price for the indicator calculation
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[]
              )
  {
//---+   
   //--- checking the number of bars
   if (rates_total < AroonPeriod - 1)
    return(0);
    
   //--- set indexation as timeseries
   ArraySetAsSeries(high, true);
   ArraySetAsSeries(low,  true);
   ArraySetAsSeries(BullsAroonBuffer, true);
   ArraySetAsSeries(BearsAroonBuffer, true);
   
   //--- declare the local variables 
   int limit, bar;
   double BULLS, BEARS;
   
   //--- calculation of the starting bar index
   if (prev_calculated == 0)                      // check for the first call of OnCalculate function
       limit = rates_total - AroonPeriod - 1// starting index for the calculation of all of the bars
   else limit = rates_total - prev_calculated; // starting index for the calculation of new bars
   
   //--- main loop
   for(bar = limit; bar >= 0; bar--)
    {
     //--- calculation of the indicator values
     BULLS = 100 + (bar - ArrayMaximum(high, bar, AroonPeriod) - 0.5) * 100 / AroonPeriod;
     BEARS = 100 + (bar - ArrayMinimum(low,  bar, AroonPeriod) - 0.5) * 100 / AroonPeriod;

     //--- filling the indicator buffers with the calculated values 
     BullsAroonBuffer[bar] = BULLS;
     BearsAroonBuffer[bar] = BEARS;
    }
//----+     
   return(rates_total);
  }
//+------------------------------------------------------------------+

Ho cambiato il nome della variabile "first" in "limit", è più appropriato in questo caso.

In questo caso, il codice del ciclo principale è simile a come è stato fatto in MQL4. Quindi, questo stile di scrittura della funzione OnCalculate() può essere utilizzato per la conversione degli indicatori da MQL4 a MQL5 con modifiche minime del codice.


Conclusione

Allora, è fatta! L'indicatore è scritto e anche in due versioni.

Per un caso del modo giusto, conservatore e intelligente di risolvere tali problemi, le soluzioni risultano leggermente più complicate della costruzione di un giocattolo utilizzando il costruttore Lego per bambini.

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

File allegati |
sma_1.mq5 (3.92 KB)
aroon.mq5 (8.04 KB)
aroons.mq5 (6.28 KB)
zigzag.mq5 (9.17 KB)
MQL per "Duri di Comprendonio": Come Progettare e Costruire Classi di Oggetti MQL per "Duri di Comprendonio": Come Progettare e Costruire Classi di Oggetti
Creando un programma di esempio di visual design, dimostriamo come progettare e costruire classi in MQL5. L'articolo è scritto per i programmatori principianti che stanno lavorando su applicazioni MT5. Proponiamo una tecnologia semplice e di facile comprensione per la creazione di classi, senza la necessità di immergersi profondamente nella teoria della programmazione orientata agli oggetti.
Interazione MetaTrader 5 e MATLAB Interazione MetaTrader 5 e MATLAB
In questo articolo si parlerà dei dettagli dell'interazione tra MetaTrader 5 e il pacchetto matematico MatLab. Mostra il meccanismo di conversione dei dati, il processo di sviluppo di una libreria universale per interagire con il desktop MatLab. Copre anche l'uso di DLL generate dall'ambiente MatLab. Questo articolo è destinato a lettori esperti che conoscono C++ e MQL5.
Algoritmi Genetici - È Facile! Algoritmi Genetici - È Facile!
In questo articolo, l'autore parla di calcoli evolutivi con l'uso di un algoritmo genetico sviluppato personalmente. Dimostra il funzionamento dell'algoritmo, usando esempi e fornisce consigli pratici per il suo utilizzo.
Creazione di un Indicatore con Opzioni di Controllo del Grafico Creazione di un Indicatore con Opzioni di Controllo del Grafico
Coloro che hanno familiarità con i sentiment del mercato conoscono l'indicatore MACD (il suo nome completo è Moving Average Convergence/Divergence) - il potente strumento per analizzare il movimento dei prezzi, utilizzato dai trader fin dai primi momenti della comparsa dei metodi di analisi del computer. In questo articolo considereremo possibili modifiche del MACD e le implementeremo in un indicatore con la possibilità di passare graficamente tra le modifiche.