
Creazione di un Indicatore con più Indicatori Buffer per Principianti
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





- App di trading gratuite
- Oltre 8.000 segnali per il copy trading
- Notizie economiche per esplorare i mercati finanziari
Accetti la politica del sito e le condizioni d’uso