English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Media delle Serie di Prezzi per i Calcoli Intermedi Senza Utilizzare Buffer Aggiuntivi

Media delle Serie di Prezzi per i Calcoli Intermedi Senza Utilizzare Buffer Aggiuntivi

MetaTrader 5Indicatori | 16 dicembre 2021, 11:26
80 0
Nikolay Kositsin
Nikolay Kositsin

Introduzione

Nel mio articolo "I principi del calcolo economico degli indicatori" ho eseguito test abbastanza convincenti che dimostrano il fatto che non ogni singola chiamata di un indicatore personalizzato o tecnico in un codice è il modo più ottimale per eseguire calcoli intermedi in un indicatore sviluppato.

La velocità finale di esecuzione può sembrare molto più bassa, rispetto a quella che avremmo se posizionassimo il codice per i calcoli intermedi proprio nel nostro indicatore.

Questo tipo di approccio alla scrittura di un codice sarebbe molto interessante, se fosse abbastanza semplice. In effetti, sembra essere una grave complicazione di un codice con la descrizione di buffer aggiuntivi utilizzati per la memorizzazione di risultati intermedi di calcolo.

Nonostante la varietà di calcoli intermedi, i più necessari in essi sono diversi algoritmi di media. Nella maggior parte dei casi, per loro possiamo usare funzioni semplici e personalizzate dell'universo che semplificano significativamente il compito di scrivere tale codice. Il processo di creazione di queste funzioni e di lavoro con esse sarà descritto in questo articolo.


1. L'Idea Generale delle Funzioni di Media che Funzionano con Una Barra

L'approccio classico alla media su una barra corrente consiste in un buffer di indicatori intermedi che riempiamo con le informazioni richieste, quindi selezioniamo un intervallo di valori precedenti, che è uguale al periodo di media, e calcoliamo il valore medio.

La procedura di elaborazione di questa selezione è la seguente:

SmoothVar(bar) = Function(Var(bar - (n-1)), Var(bar - (n-2)), ......... Var(bar)) 

dove:

  • SmoothVar(bar) — parametro medio;
  • barra — numero di una barra per la quale viene eseguito il calcolo;
  • Var(bar - (n-1)) — parametri medi con uno spostamento su (n-1) barre;
  • n — numero di barre per la media.

Tale approccio alla media, nel nostro caso, porta alla comparsa di due cicli di calcolo. Nel primo ciclo, i dati vengono calcolati e inseriti in un buffer intermedio. Nel secondo ciclo, la media utilizzando un altro ciclo di ricerca aggiuntiva delle celle del buffer dell'indicatore viene eseguita sulla base della formula suggerita sopra. Questo calcolo sembrerà molto più semplice, se accumuliamo la selezione di dati intermedi all'interno della funzione stessa. In questo caso, la funzione di media sarà la seguente:

SmoothVar(bar) = Function(Var(bar), bar)

Un nuovo valore Var(bar) viene scritto per la selezione dei valori all'interno della funzione su una barra corrente e i valori di Var(bar - n) che diventano non necessari vengono eliminati dalla selezione. Con questo approccio, un codice di media sembra piuttosto banale e non richiede buffer di indicatori aggiuntivi. All'interno della funzione, l'array memorizza l'esatta quantità necessaria di dati necessari per il calcolo di una barra, non l'intera cronologia.

In questo caso, c'è anche un solo ciclo di calcolo dei dati. Va notato che per chiamare questa funzione di media su una barra corrente, dovresti prima chiamarla su tutte le barre precedenti!


2. La Media Classica come Esempio di Implementazione di una Funzione che Funziona con Una Barra

Tali funzioni di media dovrebbero contenere variabili che non devono perdere i loro valori tra le chiamate di tali funzioni. Inoltre, la media di tipo singolo con parametri diversi può essere utilizzata in un codice per molte volte; pertanto, per evitare un conflitto di utilizzo di risorse di memoria condivise, dovremmo implementare quelle funzioni come classi; ed è quello che ho fatto io.

Gli algoritmi della media classica sono descritti nella classe CMoving_Average:

class CMoving_Average : public CMovSeriesTools
  {
public:  
   double    MASeries  (uint begin,               // Index of start of reliable bars
                       uint prev_calculated,      // Amount of history in bars at a previous tick
                       uint rates_total,          // Amount of history in bars at a current tick
                       int Length,               // Period of averaging
                       ENUM_MA_METHOD MA_Method, // Method of averaging (MODE_SMA, MODE_EMA, MODE_SMMA, MODE_LWMA)
                       double series,              // Value of price series calculated for the bar with the 'bar' number
                       uint bar,                   // Bar index
                       bool set                  // Direction of indexing of arrays.
                      );

   double    SMASeries (uint begin,          // Index of start of reliable bars
                       uint prev_calculated,// Amount of history in bars at a previous tick
                       uint rates_total,     // Amount of history in bars at a current tick
                       int Length,            // Period of averaging
                       double series,         // Value of price series calculated for the bar with the 'bar' number
                       uint bar,              // Bar index
                       bool set              // Direction of indexing of arrays.
                      );
                        
   double    EMASeries (uint begin,            // Index of start of reliable bars
                       uint prev_calculated, // Amount of history in bars at a previous tick
                       uint rates_total,     // Amount of history in bars at a current tick
                       double Length,         // Period of averaging
                       double series,        // Value of price series calculated for the bar with the 'bar' number
                       uint bar,              // Bar index
                       bool set              // Direction of indexing of arrays.
                      );
                        
   double    SMMASeries(uint begin,              // Index of start of reliable bars
                         uint prev_calculated, // Amount of history in bars at a previous tick
                         uint rates_total,     // Amount of history in bars at a current tick
                         int Length,            // Period of averaging
                         double series,         // Value of price series calculated for the bar with the 'bar' number
                         uint bar,              // Bar index
                         bool set              // Direction of indexing of arrays.
                      );

   double    LWMASeries(uint begin,               // Index of start of reliable bars
                         uint prev_calculated, // Amount of history in bars at a previous tick
                         uint rates_total,      // Amount of history in bars at a current tick
                         int Length,             // Period of averaging
                         double series,          // Value of price series calculated the bar with the 'bar' number
                         uint bar,               // Bar index
                         bool set               // Direction of indexing of arrays.
                        );

protected:
   double            m_SeriesArray[];
   int               m_Size_, m_count, m_weight;
   double            m_Moving, m_MOVING, m_Pr;
   double            m_sum, m_SUM, m_lsum, m_LSUM;
  };

Questa classe deriva dalla classe base CMovSeriesTools che contiene ulteriori funzioni-metodi protetti e un controllo della correttezza del periodo delle medie mobili.

La classe base contiene un codice universale aggiuntivo che viene utilizzato in tutte le classi che suggerisco e non ha senso copiarlo per molte volte nelle classi derivate. Nelle attività applicate di utilizzo della media, i membri della classe protetta non vengono utilizzati in forma esplicita, quindi per il momento sospendiamo la loro panoramica.

La classe CMoving_Average è costituita da cinque funzioni di media di tipo singolo, i cui nomi parlano da soli e non hanno bisogno di essere descritte nel dettaglio.

La prima funzione MASeries() è una raccolta integrale di altre quattro funzioni che consentono di selezionare un algoritmo di media utilizzando il parametro MA_Method. Il codice degli algoritmi di media è ottimizzato per le massime prestazioni, ed è per questo che i principali parametri delle funzioni (Lunghezza, serie, barra) sono integrati con parametri aggiuntivi che iniziano con, prev_calculated, rates_total e set, il cui scopo è assolutamente identico alle variabili dell’indicatore con gli stessi nomi.

Il parametro 'set' imposta il flag di indicizzazione degli elementi di una serie di prezzi 'serie' nelle funzioni di media per essere lo stesso delle matrici di variabili.

Dovremmo considerare che tutte le funzioni di media di questa classe hanno il parametro Length fisso e non può essere modificato quando viene eseguito il codice del programma! La funzione EMASeries() della classe CMoving_Average ha questo parametro del tipo double!

Ora, come abbiamo familiarizzato con la classe CMoving_Average, possiamo iniziare a usarla negli indicatori. A tale scopo, utilizzando la direttiva #include aggiungi il contenuto del file MASeries_Cls.mqh nell'ambito globale al codice dell'indicatore che si sviluppa:

#include <MASeries_Cls.mqh> 

È quindi necessario determinare il numero necessario di procedure della media nel codice dell'indicatore e quindi nella parte OnCalculate() (prima degli operatori di loop e delle parentesi graffe) dichiarare le variabili statiche della classe CMoving_Averagein base al numero richiesto di procedure della media. Deve esserci una variabile separata della classe e una cella separata nell’array della classe per ogni procedura di media.

//---- declaration of variables of the class CMoving_Average из файла MASeries_Cls.mqh
static CMoving_Average MA1, MA2, MA3, MA4;

Le variabili della classe nella funzione OnCalculate() sono dichiarate statiche, perché i loro valori devono essere mantenuti tra le chiamate di questa funzione. Ora possiamo iniziare a lavorare con la media stessa. Ad esempio, mostrerò quattro procedure consecutive di media delle serie di prezzi - SMA / EMA / SMMA / LWMA (l'indicatore MAx4.mq5):

//---- The main cycle of indicator calculation 
for(bar = first; bar < rates_total; bar++) 
 {
  //----+ Four calls of the function MASeries.  
  ma1_ = MA1.MASeries(start1, prev_calculated, rates_total, Length1, MODE_SMA,  price[bar], bar, false);
  ma2_ = MA2.MASeries(start2, prev_calculated, rates_total, Length2, MODE_EMA,  ma1_,       bar, false);
  ma3_ = MA3.MASeries(start3, prev_calculated, rates_total, Length3, MODE_SMMA, ma2_,       bar, false);
  ma4_ = MA4.MASeries(start4, prev_calculated, rates_total, Length4, MODE_LWMA, ma3_,       bar, false);
  //----       
  MAx4[bar] = ma4_ + dPriceShift;
 }

Il risultato di ogni media precedente (esclusa l'ultima) viene utilizzato nell'algoritmo successivo della media e il risultato finale viene passato al buffer dell'indicatore.

Penso che la parte più cruciale di questo codice sia un'inizializzazione preliminare molto attenta delle variabili degli indici che mostrano l'inizio di barre affidabili. In questo caso, avrà il seguente aspetto:

//---- Initialization of variables of start of reliable information
start1 = 0 + begin;
start2 = Length1 + begin;
start3 = Length1 + begin; // the previous EMA averaging doesn't change the start of reliable information
start4 = Length1 + Length3 + begin;

Si noti che in questa situazione, l'algoritmo LWMA della media è l'ultimo e non influisce su nulla; ma se non fosse l'ultimo, allora lo spostamento di inizio di informazioni affidabili sarebbe uguale a Length4+1, non Lenght4!

Voglio aggiungere, se non è chiaro dal codice precedente, da quale numero partono le informazioni affidabili, scegli un numero maggiore e poi diminuiscilo sperimentalmente se necessario.


3. Confronto dell'Indicatore Creato utilizzando le Classi con i suoi Analoghi che Utilizzano Indicatori Tecnici e Personalizzati

Sarebbe molto interessante confrontare le prestazioni dell'indicatore creato MAx4.mq5 con il suo identico analogo (iMAx4.mq5) che utilizza l'indicatore tecnico iMA().

Ebbene, non appena avremo deciso di eseguire il test, sarà ragionevole testare un altro indicatore (MAx3x1.mq5) simile a MAx4.mq5, ma questo avendo la prima media effettuata utilizzando la chiamata dell'indicatore tecnico iMA() e gli altri tre utilizzando la classe CMoving_Average. E non appena il set standard di indicatori del terminale client include l'indicatore Custom Moving Average.mq5, ho creato un altro indicatore analogo sulle sue basi a scopo di test (cMAx4.mq5).

Per la prossima analisi ho preparato per il test gli Expert Advisor: rispettivamente MAx4_Test.mq5, iMAx4_Test.mq5, MAx3x1_Test.mq5 e cMAx4_Test.mq5. Le condizioni per condurre tali test sono state descritte in dettaglio nell'articolo "I Principi del Calcolo Economico degli Indicatori". In questo articolo, non descriverò i dettagli del test, ma mostrerò i risultati finali dell'esecuzione di tutti e quattro gli Expert Advisor nello strategy tester degli ultimi 12 mesi su EURUSD Н4 con il modeling di ogni tick e il valore dei parametri di input “period” di tutti gli EA pari a 500.

Fig.1 Il risultato della verifica degli indicatori 

I risultati peggiori nei nostri test vengono mostrati dall'indicatore che chiama gli indicatori personalizzati; pertanto, questa variante di scrittura di un codice può essere consigliata solo ai pigri! Naturalmente, un altro "leader" che arriva ultimo ma che si basa su chiamate di indicatori tecnici, ha risultati migliori, tuttavia, sono troppo lontani da un ideale.

Il vero leader dei test è l'indicatore che viene sviluppato utilizzando le classi!

L'ibrido che utilizza classi e indicatori tecnici ha preso il secondo posto, ma non succede sempre; se il tempo del test di un indicatore è importante allora è meglio controllare personalmente tali varianti per ogni situazione.

Panoramica delle Classi Implementate di Media

№  Algoritmo Nome della Classe Nome del File Spostamento dell'Inizio delle Barre Affidabili
Dopo Aver Applicato un Algoritmo
Possibilità di Dynamic
Modifica della Lunghezza del Parametro
   1  Media Classica  CMoving_Average  MASeries_Cls.mqh Lunghezza/0/Lunghezza/Lunghezza + 1 (SMA/EMA/SMMA/LWMA) no
   2  Deviazione Standard   CStdDeviation  StdDevSeries_Cls.mqh Lunghezza no
   3  JMA Smoothing  CJJMA  JJMASeries_Cls.mqh 30
   4  T3 Smoothing  CT3  T3Series_Cls.mqh 0
   5  Ultralinear Smoothing  CJurX  JurXSeries_Cls.mqh 0
   6  Smoothing di Tushar Chande   CCMO  CMOSeries_Cls.mqh Length + 1 no
   7  Smoothing di Kaufman  CAMA  AMASeries_Cls.mqh Length + 3 no
   8  Media Parabolica  CParMA  ParMASeries_Cls.mqh Lunghezza no
   9  Velocità del Cambiamento  CMomentum  MomSeries_Cls.mqh                                             Length + 1                               no
  10  Velocità di Modifica Normalizzata  CnMomentum  nMomSeries_Cls.mqh                                             Length + 1                               no
  11  Tasso di Variazione  CROC  ROCSeries_Cls.mqh                                             Length + 1                               no

La classe CMoving_Average precedentemente descritta include cinque algoritmi di media.

La classe CCMO contiene algoritmi di media e dell’oscillatore.

Le altre classi includono singoli algoritmi di media. L'ideologia dell'uso di una qualsiasi delle classi suggerite è assolutamente la stessa della procedura di utilizzo della classe CMoving_Average sopra descritta. Il codice di tutti gli algoritmi della media (ad eccezione di quello parabolico) è ottimizzato per la massima velocità di esecuzione. Il codice della media parabolica non è stato ottimizzato a causa della complessità di questo processo. Gli ultimi tre algoritmi non rappresentano una media. Li ho aggiunti a causa della loro alta popolarità e compatibilità con i lavori di analisti tecnici popolari.

Per una più facile comprensione delle informazioni, sarebbe meglio rappresentare gli algoritmi di media in file .mqh separati; e per un uso pratico, la variante migliore è averli in un unico file.

Per l'utilizzo negli indicatori, tutte le classi suggerite vengono impacchettate nel singolo file SmoothAlgorithms.mqh. Inoltre, il file è integrato con le funzioni del file iPriceSeries.mqh. Solo la funzione PriceSeries() viene utilizzata negli esempi di questo articolo:

double PriceSeries
 (
  uint applied_price,  // Price constant
  uint   bar,          // Index of shift for a specified number of periods back or forward
                          // relatively to a current bar.
  const double& Open [],
  const double& Low  [],
  const double& High [],
  const double& Close[]
 )

Questa funzione è destinata a lavorare con indicatori basati sull'utilizzo del secondo tipo di chiamata della funzione OnCalculate().

L'idea principale della creazione di questa funzione è quella di estendere l'insieme delle serie di tempi dei prezzi dell'enumerazione ENUM_APPLIED_PRICE con varianti personalizzate. La funzione restituisce il valore di una serie di timeserie di prezzo in base al suo numero che varia da 1 a 11.


4. Esempi Pratici di Implementazione di un Codice di Programma utilizzando le Classi della Media

Se è sufficiente mostrare un altro esempio di utilizzo delle altre classi, assicurarsi che tutto sia fatto allo stesso modo della media quadruplicata. Mostrerò una variante di implementazione della funzione OnCalculate() in un analogo dell'indicatore CCI utilizzando le classi CJJMA e CJurX (JCCX.mq5)

int OnCalculate(const int rates_total,       // amount of history in bars on a current tick
              const int prev_calculated,   // amount of history in bars on a previous tick
              const datetime& time[],
              const double& open[],
              const double& high[],
              const double& low[],
              const double& close[],
              const long& tick_volume[],
              const long& volume[],
              const int& spread[]
             )
  {
//----+   
   //---- Checking whether there are enough bars for calculation
   if (rates_total < 0) return(0);
    
   //---- Declaration of variables  with floating point  
   double price_, jma, up_cci, dn_cci, up_jccx, dn_jccx, jccx;
   //----+ Declaration of integer variables
   int first, bar;
   
   //---- calculation of start number 'first' for the cycle of recalculation of bars
   if (prev_calculated == 0) // checking for the first start of calculation of indicator
        first = 0;           // starting number for calculation of all bars
   else first = prev_calculated - 1; // starting number for calculation of new bars
   
   //---- declaration of variables of the class CJurX from the file SmoothAlgorithms.mqh
   static CJurX Jur1, Jur2;
   //---- declaration of variables of the class CJMA from the file SmoothAlgorithms.mqh
   static CJJMA JMA;
   
   //---- Main cycle of calculation of the indicator
   for(bar = first; bar < rates_total; bar++)
    {
     //----+ Calling the PriceSeries function to get the input price price_
     price_ = PriceSeries(IPC, bar, open, low, high, close); 

     //----+ One call of the JJMASeries function to get JMA
     jma = JMA.JJMASeries(0, prev_calculated, rates_total, 0, JMAPhase, JMALength, price_, bar, false); 

     //----+ Determine the deviation of price from the value of JMA
     up_cci = price_ - jma;         
     dn_cci = MathAbs(up_cci);

     //----+ Two calls of the JurXSeries function.  
     up_jccx = Jur1.JurXSeries(30, prev_calculated, rates_total, 0, JurXLength, up_cci, bar, false);
     dn_jccx = Jur2.JurXSeries(30, prev_calculated, rates_total, 0, JurXLength, dn_cci, bar, false); 

     //---- Preventing zero divide in empty values
     if (dn_jccx == 0) jccx = EMPTY_VALUE;
     else
      {
       jccx = up_jccx / dn_jccx;
       
       //---- Limitation of the indicator from the top and from the bottom
       if (jccx > +1)jccx = +1;
       if (jccx < -1)jccx = -1;
      }

     //---- Loading the obtained value to the indicator buffer
     JCCX[bar] = jccx;
    }
//----+     
   return(rates_total);
  }

Fig.2 L'indicatore JCCX 

Ma questa volta ho aggiunto le classi appropriate da un altro file sull'ambito globale nel codice dell'indicatore:

#include <SmoothAlgorithms.mqh>

Ora, vorrei avere la tua attenzione su un'altra cosa. Il problema è che un grande numero di indicatori può essere rappresentato come funzioni di una barra, che sono davvero comode da lavorare usando le classi.

Ad esempio, sarebbe interessante disegnare il canale di Bollinger sulla base della media mobile Vidya di Tushar Chande. In questo caso, vengono utilizzate due classi CCMO e CStdDeviation. Usando la prima classe, otteniamo il valore della media mobile VIDYA; e usando il secondo, calcoliamo il valore della deviazione standard della serie di prezzi per la media mobile.

Successivamente, usiamo questa deviazione per il calcolo del border superiore e inferiore del canale:

//+------------------------------------------------------------------+
// Description of the classes CStdDeviation{}; and CCMO{};           | 
//+------------------------------------------------------------------+ 
#include <SmoothAlgorithms.mqh> 
//+==================================================================+
//|  The algorithm of getting the Bollinger channel from             |
//|  the moving average VIDYA                                        |
//+==================================================================+
class CVidyaBands
{
public:
  double VidyaBandsSeries(uint begin,                // number of the start of reliable calculation of bars
                         uint prev_calculated,      // amount of history on a previous tick in bars
                         uint rates_total,          // amount of history on a current tick in bars
                         int CMO_period,            // the period of averaging of the oscillator CMO
                         double EMA_period,         // the period of averaging of EMA
                         ENUM_MA_METHOD MA_Method, // the type of averaging
                         int BBLength,             // the period of averaging of the Bollinger channel
                         double deviation,          // Deviation
                         double series,             // Value of the price series calculated for a bar with the number 'bar'
                         uint bar,                  // Bar index
                         bool set,                  // Direction of indexing of arrays
                         double& DnMovSeries,       // Value of the lower border of the channel for a current bar
                         double& MovSeries,         // Value of the middle line of the channel for a current bar
                         double& UpMovSeries        // Value of the upper border of the channel for a current bar 
                        ) 
   {
//----+
    //----+ Calculation of the middle line    
    MovSeries = m_VIDYA.VIDYASeries(begin, prev_calculated, rates_total, 
                                    CMO_period, EMA_period, series, bar, set); 
    //----+ Calculation of the Bollinger channel
    double StdDev = m_STD.StdDevSeries(begin+CMO_period+1, prev_calculated, rates_total, 
                                      BBLength, deviation, series, MovSeries, bar, set);
    DnMovSeries = MovSeries - StdDev;
    UpMovSeries = MovSeries + StdDev;
//----+
    return(StdDev); 
   }

  protected:
    //---- declaration of variables of the classes CCMO and CStdDeviation
    CCMO           m_VIDYA;
    CStdDeviation  m_STD;
};

Quindi, abbiamo una classe semplice e ridotta!

Gli ultimi tre parametri di input della funzione VidyaBandsSeries() passano i valori necessari del canale attraverso un collegamento.

Vorrei sottolineare che in questo caso, non è possibile dichiarare le variabili delle classi all'interno della funzione VidyaBandsSeries() e renderle statiche, perché le variabili statiche nelle classi hanno un significato molto diverso. Ecco perché questa dichiarazione deve essere effettuata sull'ambito globale della classe:

protected: 
  //---- declaration of variables of the classes CCMO and CStdDeviation 
  CCMO           m_VIDYA; 
  CStdDeviation  m_STD;

In un normale canale di Bollinger, il periodo di media della media mobile e il periodo di media del canale stesso sono sempre uguali.

In questa classe, ho separato questi parametri per darti più libertà (EMA_period e BBLength). L'indicatore stesso (VidyaBBands.mq5) realizzato sulla base di questa classe è così semplice nell'uso della classe CVidyaBands che non è necessario analizzare il suo codice nell'articolo.

Tali classi di funzioni dell’indicatore devono essere inserite in un file mqh separato. Ho inserito tali funzioni nel file IndicatorsAlgorithms.mqh.

Fig.3 L'indicatore VidyaBBands 


5. Confronto delle Prestazioni di un Indicatore che Utilizza Classi con Uno che Non lo Fa 

Prima di tutto, vorrei scoprire, come l'uso delle classi quando si scrive un codice di un indicatore diminuisce le sue prestazioni?

A tale scopo, il codice dell'indicatore JJMA.mq5 è stato scritto senza utilizzare le classi (JMA.mq5), quindi è stato testato nelle stesse condizioni del test precedente. I risultati finali dei test non hanno una grande differenza:

Fig.4 I risultati dei test degli indicatori JMA e JJMA 

Naturalmente, ci sono alcuni costi aggiuntivi per l'utilizzo delle classi, ma non sono significativi rispetto ai vantaggi che forniscono. 


6. Vantaggi dell'Utilizzo delle Classi della Media

Un vantaggio dell'utilizzo di questi algoritmi, che è davvero convincente, è che la sostituzione delle chiamate di indicatori tecnici e personalizzati porta ad un grande aumento delle prestazioni del codice sviluppato sopra descritto.

Un altro vantaggio pratico di tali classi è una grande comodità di usarle. Ad esempio, tutto ciò che è descritto nel popolare libro di William Blau "Momentum, Direction and Divergence " sembra essere un vero e proprio banco di prova per questo tipo di approccio alla scrittura di indicatori. Il codice degli indicatori risulta compresso al massimo, comprensibile e spesso costituito da un unico ciclo di ricalcolo delle barre.

Puoi facilmente sviluppare qualsiasi indicatore, classico o tecnico, utilizzando i metodi alternativi di media. Una varietà piuttosto ampia di algoritmi di media offre vaste possibilità per la creazione di sistemi di trading non tradizionali, spesso con un rilevamento precoce delle tendenze e un numero minore di falsi trigger.


7. Alcuni Consigli sull'Utilizzo degli Algoritmi di Media in un Codice Indicatore Specifico

Una rapida occhiata a qualsiasi indicatore sviluppato utilizzando diversi algoritmi di media descritti qui è sufficiente per capire quanto siano diversi quegli algoritmi.

 

 Fig. 5 Le medie mobili che utilizzano diversi algoritmi di media

Pertanto, sarebbe ragionevole supporre che non tutti gli algoritmi suggeriti siano ugualmente buoni in ogni situazione. Sebbene sarebbe difficile determinare un limite rigoroso di utilizzo dell'uno o dell'altro algoritmo, è possibile fornire alcuni consigli generali sul loro utilizzo.

Ad esempio, gli algoritmi di Tushar Chande e Kaufman sono destinati a determinare situazioni di tendenza e non sono adatti per un ulteriore smoothing allo scopo di filtrare il rumore. Pertanto, è meglio inserire serie di prezzi non elaborate o valori di indicatori senza fare la media di questi algoritmi. Ecco il risultato dell'elaborazione dei valori dell'indicatore Momentum utilizzando l'algoritmo di Kaufman (l'indicatore 4c_Momentum_AMA.mq5)

Fig.6 Il risultato dell'elaborazione dei valori dell'indicatore Momentum utilizzando l'algoritmo di Kaufman 

Penso che gli algoritmi della media classica non necessitino di raccomandazioni particolari. La loro area di applicazione è piuttosto ampia. Ovunque, dove vengono utilizzati questi algoritmi, è possibile utilizzare con successo i quattro algoritmi di sinistra (JMA, T3, ultra lineare e parabolico). Ecco un esempio dell'indicatore MACD in cui EMA e SMA sono sostituiti con la media JMA (l'indicatore JMACD.mq5):

 Fig.7 Il grafico MACD usando la media JMA

Ed ecco il risultato della levigatura dell'indicatore calcolato invece di cambiare il suo algoritmo di media per una migliore qualità nel determinare la tendenza corrente (l'indicatore JMomentum.mq5):

Fig.8 Il risultato dello smoothing JMA dell'indicatore Momentum

Non è una sorpresa che il comportamento dei mercati cambi costantemente; pertanto, sarebbe ingenuo pensare di poter trovare l'unico e l'unico algoritmo ideale per una certa parte del mercato finanziario ora e per sempre! Ahimè! Niente in questo mondo dura per sempre! Tuttavia, per quanto mi riguarda ad esempio, in questo mercato in continua evoluzione uso spesso gli indicatori di tendenze a medio e veloce termine come JFATL.mq5 e J2JMA.mq5. Sono abbastanza soddisfatto delle previsioni sulla loro base.

Un'altra cosa che voglio aggiungere. Gli algoritmi di media sono riutilizzabili. Buoni risultati possono essere ottenuti applicando la media ripetuta a valori già medi. È un dato di fatto, in questo articolo ho iniziato ad analizzare il processo di disegno dell'indicatore da esso (l'indicatore MAx4.mq5).


8. L'idea Generale di Comporre il Codice degli Algoritmi di Media

E ora, alla fine dell'articolo, vorrei prestare la tua attenzione al meccanismo delle funzioni di media di se stesse.

Prima di tutto, la maggior parte degli algoritmi di media include array dinamici di variabili del tipo m_SeriesArray[] per memorizzare i valori del parametro di input 'series'.

Non appena vengono visualizzate le informazioni significative per il calcolo, è necessario allocare la memoria per tale array per una volta. Viene eseguito utilizzando la funzione SeriesArrayResize() della classe CMovSeriesTools.

//----+ Changing the size of the array of variables
if(bar==begin && !SeriesArrayResize(__FUNCTION__, Length, m_SeriesArray, m_Size_))
   return(EMPTY_VALUE);

Quindi su ogni barra dovresti scrivere il valore corrente della serie di prezzi 'serie' al valore più vecchio dell'array e memorizzare il numero della sua posizione nella variabile m_count. Viene eseguito utilizzando la funzione Recount_ArrayZeroPos() della classe CMovSeriesTools.

//----+ transposition and initialization of cells of the array m_SeriesArray 
Recount_ArrayZeroPos(m_count, Length_, prev_calculated, series, bar, m_SeriesArray);

E ora, se abbiamo bisogno di trovare un elemento con uno spostamento relativo all'elemento corrente, dovremmo usare la funzione Recount_ArrayNumber() della classe CMovSeriesTools:

for(iii=1; iii<=Length; iii++, rrr--)
   {
    kkk = Recount_ArrayNumber(m_count, Length_, iii);
    m_sum += m_SeriesArray[kkk] * rrr;
    m_lsum += m_SeriesArray[kkk];
    m_weight += iii;
   }

Di solito in tali situazioni, l'elemento più recente è scritto in una posizione zero e gli altri (tranne quello più vecchio) sono preliminarmente sovrascritti nelle posizioni successive a turno; tuttavia, non sta risparmiando le risorse del computer e l'approccio più complesso descritto sopra sembra essere più razionale!

Oltre agli algoritmi di media, i corpi di tali funzioni contengono le chiamate di funzioni utilizzate per determinare le posizioni delle barre relativamente all'inizio del calcolo delle barre:

//----+ Checking the start of reliable calculation of bars
if(BarCheck1(begin, bar, set)) return(EMPTY_VALUE);

il momento in cui ci sono informazioni sufficienti per l'inizializzazione iniziale delle variabili:

//----+ Initialization of zero
if(BarCheck2(begin, bar, set, Length))

e situazioni in cui l'ultima barra è chiusa:

//----+ Saving values of the variables 
if(BarCheck4(rates_total, bar, set))

o non chiusa:

//----+ Restoring values of the variables
if(BarCheck5(rates_total, bar, set))

Il primo controllo determina una situazione in cui non ci sono abbastanza barre per far funzionare la funzione di media e restituisce un risultato vuoto. Una volta superato con successo il secondo controllo e ci sono dati sufficienti per il primo calcolo, l'inizializzazione delle variabili viene eseguita per una volta. Due ultimi controlli sono necessari per la corretta elaborazione multipla dei valori sulla barra corrente non chiusa. L'ho già descritto nel mio articolo dedicato all'ottimizzazione di un codice di programma.

E ora qualche parola sull'ottimizzazione del codice di programma di tali funzioni per le massime prestazioni. Ad esempio, l'algoritmo SMA implica la media dei valori selezionati di un periodo di una serie di prezzi su ogni barra. Questi valori sono letteralmente sommati e divisi per il punto su ogni barra.

Ma la differenza tra la somma sulla barra precedente e la somma sulla barra corrente è che la prima viene sommata con il valore della serie di prezzi con uno spostamento su un periodo relativamente al periodo corrente e la seconda con il valore corrente. Pertanto, sarebbe molto razionale calcolare tale somma solo una volta durante l'inizializzazione delle funzioni, e quindi su ogni barra aggiungere solo nuovi valori della serie di prezzi a questa somma e sottrarre i valori più vecchi da esso. Questo è esattamente fatto in una funzione tale.


Conclusione

Suggerite nell'articolo, le implementazioni degli algoritmi di media utilizzando le classi sono semplici, di tipo singolo e universali, quindi non avrai problemi a studiarle.

Gli archivi allegati all'articolo contengono molti esempi per una più facile comprensione di questo approccio alla scrittura di codice di indicatori. Nell'archivio Include__en.zip tutte le classi sono distribuite in file. L'archivio Include_en.zip contiene solo due file che sono sufficienti per compilare tutti gli indicatori nell'archivio Indicatori.zip. Gli Expert Advisor per i test sono nell'archivio Experts.zip.


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

File allegati |
experts-en.zip (3.88 KB)
include__en.zip (40.84 KB)
include-en.zip (17.82 KB)
indicators_en.zip (90.93 KB)
Costruire un Analizzatore di Spettro Costruire un Analizzatore di Spettro
Questo articolo ha lo scopo di far conoscere ai suoi lettori una possibile variante dell'utilizzo di oggetti grafici del linguaggio MQL5. Analizza un indicatore, che implementa un pannello di gestione di un semplice analizzatore di spettro utilizzando gli oggetti grafici. L'articolo è pensato per i lettori che hanno acquisito le basi di MQL5.
Crea il tuo Market Watch usando le Classi Standard della Libreria Crea il tuo Market Watch usando le Classi Standard della Libreria
Il nuovo terminale client MetaTrader 5 e il linguaggio MQL5 offrono nuove opportunità per presentare informazioni visive al trader. In questo articolo, proponiamo un insieme di classi universale ed estensibile, che gestisce tutto il lavoro di organizzazione della visualizzazione delle informazioni di testo arbitrarie sul grafico. Viene presentato l'esempio dell'indicatore Market Watch.
Indicatori e Sistemi di Trading di William Blau in MQL5. Parte 1: Indicatori Indicatori e Sistemi di Trading di William Blau in MQL5. Parte 1: Indicatori
L'articolo presenta gli indicatori, descritti nel libro di William Blau "Momentum, Direction, and Divergence". L'approccio di William Blau ci consente di approssimare tempestivamente e accuratamente le fluttuazioni della curva dei prezzi, di determinare l'andamento dei movimenti dei prezzi e dei punti di svolta ed eliminare il rumore dei prezzi. Nel frattempo, siamo anche in grado di rilevare gli stati di ipercomprato/ipervenduto del mercato e segnali, che indicano la fine di una tendenza e l'inversione del movimento dei prezzi.
Il Semplice Esempio di Creazione di un Indicatore Utilizzando la Logica Fuzzy Il Semplice Esempio di Creazione di un Indicatore Utilizzando la Logica Fuzzy
L'articolo è dedicato all'applicazione pratica del concetto di logica fuzzy per l'analisi dei mercati finanziari. Proponiamo l'esempio dell'indicatore che genera segnali basati su due regole fuzzy basate sull'indicatore Envelopes. L'indicatore sviluppato utilizza diversi buffer di indicatori: 7 buffer per i calcoli, 5 buffer per la visualizzazione dei grafici e 2 buffer colore.