English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Gestione degli Eventi in MQL5: Modifica del periodo MA al volo

Gestione degli Eventi in MQL5: Modifica del periodo MA al volo

MetaTrader 5Indicatori | 15 dicembre 2021, 17:10
121 0
Sceptic Philozoff
Sceptic Philozoff

Introduzione

Questo breve articolo è dedicato a una delle nuove funzionalità MQL5 della piattaforma MetaTrader 5, sviluppata da MetaQuotes Software Corp. Forse questo articolo è leggermente in ritardo (avrebbe dovuto essere pubblicato a settembre-ottobre 2009 - quindi sarebbe opportuno), ma non c'erano articoli simili su questo argomento. Inoltre, in quel momento non c'erano tali possibilità di gestire gli eventi negli indicatori.

Immagina di avere un semplice indicatore di prezzo applicato a un grafico (in questo caso è la media mobile, cioè MA), e di voler modificare il suo periodo di smoothing. Nella piattaforma MT4 avevamo le seguenti opzioni:

  • In MetaEditor puoi modificare il parametro di input dell'expert (extern), responsabile del periodo MA, e quindi compilare il file sorgente.
  • Senza passare a MetaEditor, direttamente nella finestra del terminale è possibile aprire la finestra di dialogo Proprietà dell'indicatore e lì modificare il parametro di input corrispondente.
  • È possibile aprire la libreria API Win32, trovare funzioni di acquisizione dei messaggi, quindi modificare il codice dell'indicatore in modo che risponda agli eventi dalla tastiera.

Come sappiamo, il desiderio del minimo sforzo è il più grande motore del progresso. Ora, grazie a una nuova piattaforma MT5, che consente la gestione degli eventi degli indicatori avviati dall'utente, possiamo saltare le possibilità di cui sopra e modificare i parametri dell'indicatore con la semplice pressione di un tasto. Questo articolo riguarda l'implementazione tecnica di questa soluzione del problema.

Assegnazione dei compiti e problemi

Il codice sorgente dell'indicatore, utilizzato nei nostri esperimenti, viene fornito con Terminale Client. Il file del codice sorgente invariato (Custom Moving Average.mq5) è allegato alla fine di questo articolo.

Per ora non analizzeremo il codice sorgente e soprattutto le modifiche rispetto al suo originale MQL4. Sì, in alcuni punti è cambiato in modo significativo e questo non è sempre ovvio. Spiegazioni corrispondenti, relative alla ristrutturazione della parte base del calcolo, sono disponibili sul forum e nella guida in linea.

Tuttavia, la parte principale dell'indicatore in MQL4 è rimasta invariata. Almeno l'80% di tutte le modifiche al codice, intese a risolvere il nostro problema, sono state fatte sulla base dell'idea di funzioni computazionali di indicatore come le "scatole nere".

Un esempio di ciò che vogliamo ottenere è simile a questo. Supponiamo di aver applicato questo indicatore a un grafico e che in un dato momento visualizzi un MA esponenziale (EMA) con spostamento zero e periodo di 10. Il nostro obiettivo è aumentare di 3 (fino a 13) il periodo di smoothing della MA semplice (SMA) e spostarlo di 5 barre a destra. La sequenza di azioni ipotizzata è la seguente:

  • Premendo alcune volte il tasto TAB si cambia la MA visualizzata da esponenziale a semplice (cambio tipo MA).
  • Premendo tre volte il tasto freccia SU sulla parte principale della tastiera si aumenta di 3 il periodo di MA semplice.
  • Premendo il tasto freccia SU (8) sul tastierino numerico 5 volte per spostare MA di 5 barre a destra.

La prima e più ovvia soluzione è inserire la funzione OnChartEvent() nel codice dell'indicatore e scrivere l’handler dell’evento keystroke. Secondo l'elenco delle modifiche nelle build del terminale client MetaTrader 4 245 e 246 https://www.mql5.com/en/forum/53/page1/#comment_2655,

Il terminale client MetaTrader 5 costruisce 245 e 246

MQL5: Aggiunta la possibilità di gestione degli eventi tramite indicatori personalizzati, simile a quella degli Expert Advisor.

Quindi, ora non abbiamo problemi con l'aggiunta di nuovi gestori di eventi nell'indicatore. Ma per questo dobbiamo ancora modificare leggermente il suo codice.

Innanzitutto, in MQL5 lo stato dei parametri esterni dell'indicatore è cambiato: non è possibile modificarli nel codice. L'unico modo per modificarli è tramite la finestra di dialogo Proprietà nel Terminale Client. Generalmente, nell'urgente necessità di modificarli, questa restrizione viene facilmente aggirata: basta copiare i valori dei parametri esterni nelle nuove variabili globali dell'indicatore e tutti i calcoli vengono eseguiti come se queste nuove variabili fossero effettivamente i parametri esterni dell'indicatore. D'altra parte, in questo caso viene meno la fattibilità di parametri esterni, i cui valori possono solo trarre in inganno gli utenti. Ora questi parametri semplicemente non sono necessari.

Pertanto, non ci sono parametri esterni (input) nell'indicatore. Le variabili che svolgono il ruolo di parametri esterni, ora saranno le Variabili Globali Terminali o TGV in breve. Se vuoi vedere il TGV, responsabile dei precedenti parametri esterni dell'indicatore, puoi semplicemente premere il tasto F3 nel terminale. Non riesco a trovare un altro modo semplice per controllare i parametri dell'indicatore.

In secondo luogo (e questo è importante), su qualsiasi modifica dei parametri esterni dell'indicatore dobbiamo ricalcolare tutti i suoi valori nel corso della storia, di nuovo e da zero. In altre parole, dovremo eseguire calcoli che di solito vengono effettuati solo al primo avvio dell'indicatore. L'ottimizzazione dei calcoli dell'indicatore rimane, ma ora diventa più sottile.

Di seguito sono riportate alcune parti del codice della prima versione dell'indicatore modificato. Il codice completo è allegato alla fine di questo articolo.

 

Versione "Standard": la descrizione delle modifiche nel codice sorgente dell'indicatore standard

I parametri esterni non sono più esterni, ma semplicemente variabili globali

Tutti i parametri esterni dell'indicatore hanno perso il modificatore di input. In genere non riuscivo nemmeno a renderli globali, ma ho deciso di farlo per tradizione:

int              MA_Period   = 13;
int              MA_Shift    =  0;
ENUM_MA_METHOD   MA_Method   =  0;
int              Updated     =  0;     /// Indicates whether the indicator has updated after changing it's values

Le prime tre opzioni - sono il periodo, l'offset e il tipo di MA, e la quarta - Updated - è responsabile dell'ottimizzazione dei calcoli, quando si modificano i parametri MA. Le spiegazioni sono poche righe sotto. 

Codici chiavi virtuali

Inserisci i codici per le chiavi virtuali:

#define KEY_UP             38
#define KEY_DOWN           40
#define KEY_NUMLOCK_DOWN   98
#define KEY_NUMLOCK_UP    104
#define KEY_TAB             9

Questi sono i codici per i tasti "freccia su" e "freccia giù", frecce simili sulla tastiera numerica (tasto "8" e "2"), nonché il tasto TAB. Gli stessi codici (con altri nomi di costanti VK_XXX) esistono effettivamente nel file <MT5dir>\MQL5\Include\VirtualKeys.mqh, ma in questo caso ho deciso di lasciarlo così com'è.


Piccola correzione del codice in funzione, calcolo della media mobile ponderata lineare (LWMA)

Ho apportato una piccola modifica alla funzione CalculateLWMA(): nella versione originale la variabile weightsum era dichiarata utilizzando il modificatore statico. Apparentemente, l'unico motivo per cui gli sviluppatori lo hanno fatto è stata la necessità di pre-calcolarlo alla prima chiamata di questa funzione. Inoltre nel codice questa variabile rimane invariata. Ecco il codice originale di questa funzione, in cui le parti relative al calcolo e all'utilizzo di weightsum sono contrassegnate con dei commenti:

void CalculateLWMA(int rates_total,int prev_calculated,int begin,const double &price[])
  {
   int              i,limit;
   static int     weightsum;                       // <-- using weightsum
   double               sum;
//--- first calculation or number of bars was changed
   if(prev_calculated==0)                          // <-- using weightsum
     {
      weightsum=0;                                 // <-- using  weightsum
      limit=InpMAPeriod+begin;                     // <-- using weightsum
      //--- set empty value for first limit bars
      for(i=0;i<limit;i++) ExtLineBuffer[i]=0.0;
      //--- calculate first visible value
      double firstValue=0;
      for(i=begin;i<limit;i++)                     // <-- using weightsum
        {
         int k=i-begin+1;                          // <-- using weightsum
         weightsum+=k;                             // <-- using weightsum
         firstValue+=k*price[i];
        }
      firstValue/=(double)weightsum;
      ExtLineBuffer[limit-1]=firstValue;
     }
   else limit=prev_calculated-1;
//--- main loop
   for(i=limit;i<rates_total;i++)
     {
      sum=0;
      for(int j=0;j<InpMAPeriod;j++) sum+=(InpMAPeriod-j)*price[i-j];
      ExtLineBuffer[i]=sum/weightsum;              // <-- using weightsum
      }
//---
  }

In precedenza, questa variante funzionava abbastanza bene, ma quando ho eseguito il tandem "indicatore + advisor" (questo viene menzionato alla fine di questo articolo) in questo stesso tipo di MA sono usciti problemi. La principale era causata dalle circostanze sopra descritte, cioè weightsum era la variabile statica: questa variabile era in costante aumento poiché ad ogni modifica del parametro MA al volo era necessario ricalcolarla da zero.

Il modo più semplice per calcolare direttamente e immediatamente il valore di weightsum (è uguale alla somma di numeri interi da 1 a periodo MA - a questo scopo esiste una semplice formula per la somma della progressione aritmetica) e allo stesso tempo negare il suo stato come una statica, cosa che ho fatto. Ora, invece della precedente dichiarazione di weightsum usando il modificatore static, lo dichiariamo senza di lui, semplicemente inizializziamo con il valore "corretto" e quindi rimuoviamo il ciclo iniziale di "accumulo di variabili".

int weightsum = MA_Period *( MA_Period + 1 ) / 2;

Ora funziona tutto correttamente.


Funzione OnCalculate() come un handler

Ho dovuto apportare molte modifiche alla funzione OnCalculate(), e quindi cito qui il suo codice completamente.

int OnCalculate(const int rates_total,
                const int prev_calculated,            /// Mathemat: full recalculation!
                const int begin,                      /// Mathemat: full recalculation!
                const double &price[])
  {
//--- check for bars count
   if(rates_total<MA_Period-1+begin)
      return(0);// not enough bars for calculation
//--- first calculation or number of bars was changed
   if(prev_calculated==0)
      ArrayInitialize(LineBuffer,0);
//--- sets first bar from what index will be draw
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,MA_Period-1+begin);

//--- calculation (Mthmt - optimized by Mathemat)

   if( GlobalVariableGet( "Updated" ) == 1 )
   {
      if(MA_Method==MODE_EMA)  CalculateEMA(       rates_total,prev_calculated,begin,price);
      if(MA_Method==MODE_LWMA) CalculateLWMA_Mthmt(rates_total,prev_calculated,begin,price);
      if(MA_Method==MODE_SMMA) CalculateSmoothedMA(rates_total,prev_calculated,begin,price);
      if(MA_Method==MODE_SMA)  CalculateSimpleMA(  rates_total,prev_calculated,begin,price);
   }
   else
   {
      OnInit( );                 /// Mthmt
      if(MA_Method==MODE_EMA)  CalculateEMA(       rates_total,0,0,price);
      if(MA_Method==MODE_LWMA) CalculateLWMA_Mthmt(rates_total,0,0,price);
      if(MA_Method==MODE_SMMA) CalculateSmoothedMA(rates_total,0,0,price);
      if(MA_Method==MODE_SMA)  CalculateSimpleMA(  rates_total,0,0,price);
      GlobalVariableSet( "Updated", 1 );
      Updated = 1;
   }
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

Il cambiamento principale riguarda la necessità percepita di un calcolo completo dell'indicatore "da zero": è ovvio che se la manipolazione della tastiera di un utente ha cambiato il periodo MA da 13 a 14, tutte le precedenti ottimizzazioni dei suoi calcoli sono già inutili e dobbiamo calcolare di nuovo MA. Ciò si verifica quando la variabile Updated ha valore 0 (TGV è cambiato dopo aver premuto il tasto di scelta rapida, ma il tick, che ridisegna l'indicatore, non è ancora arrivato).

Tuttavia, in aggiunta, in precedenza dovevamo chiamare esplicitamente la funzione OnInit(), perché avevamo bisogno di cambiare il nome breve dell'indicatore, che verrà visualizzato quando un cursore passa sopra la riga. Dopo il calcolo dell'MA iniziale, il TGV Updated è impostato su 1, il che apre la strada al calcolo dell'indicatore ottimizzato, fino a quando non si è nuovamente disposti a modificare al volo i parametri di alcuni indicatori.


Handler OnChartEvent.

Di seguito è riportato un semplice codice dell’handler OnChartEvent():

void OnChartEvent( const int          id,
                   const long    &lparam,
                   const double  &dparam,
                   const string  &sparam )
{
   if( id == CHARTEVENT_KEYDOWN )
      switch( lparam )
      {
         case( KEY_TAB          ):  changeTerminalGlobalVar( "MA_Method",  1 ); 
                                    GlobalVariableSet( "Updated",  0 );
                                    Updated = 0;
                                    break;
         
         case( KEY_UP           ):  changeTerminalGlobalVar( "MA_Period",  1 ); 
                                    GlobalVariableSet( "Updated",  0 );
                                    Updated = 0;
                                    break;
         case( KEY_DOWN         ):  changeTerminalGlobalVar( "MA_Period", -1 ); 
                                    GlobalVariableSet( "Updated",  0 );
                                    Updated = 0;
                                    break;
         
         case( KEY_NUMLOCK_UP   ):  changeTerminalGlobalVar( "MA_Shift",   1 ); 
                                    GlobalVariableSet( "Updated",  0 );
                                    Updated = 0;
                                    break;
         case( KEY_NUMLOCK_DOWN ):  changeTerminalGlobalVar( "MA_Shift",  -1 ); 
                                    GlobalVariableSet( "Updated",  0 );
                                    Updated = 0;
                                    break;
      }
      
      return;
}//+------------------------------------------------------------------+      

Il gestore funziona come segue: si preme il tasto di scelta rapida, il suo codice virtuale viene definito, quindi viene avviata la funzione ausiliaria changeTerminalGlobalVar() e sta modificando correttamente il TGV desiderato. Dopodiché il flag Updatedviene azzerato, in attesa del tick, che avvierà OnCalculate() e ridisegna l'indicatore "da zero".


Funzione ausiliaria che cambia "correttamente" il TGV

E, infine, il codice della funzione changeTerminalGlobalVar(), utilizzata nell’handler OnChartEvent():

void changeTerminalGlobalVar( string name, int dir = 0 )
{
   int var = GlobalVariableGet( name );
   int newparam = var + dir;
   if( name == "MA_Period" )
   {
      if( newparam > 0 )       /// Possible period is valid for MA
      {
         GlobalVariableSet( name, newparam ); 
         MA_Period = newparam;     /// Don't forget to change the global variable    
      }   
      else                       /// we do not change the period, because MA period is equal to 1 minimum
      {   
         GlobalVariableSet( name, 1 );     
         MA_Period = 1;     /// Don't forget to change the global variable 
      }   
   }   
      
   if( name == "MA_Method" )    /// Here when you call the 'dir' it is always equal to 1, the dir value is not important    
   {
      newparam = ( var + 1 ) % 4;
      GlobalVariableSet( name, newparam );  
      MA_Method = newparam;
   }      

   if( name == "MA_Shift" )
   {
      GlobalVariableSet( name, newparam );     
      MA_Shift = newparam;
   }      

   ChartRedraw( );
   return;
}//+------------------------------------------------------------------+

Lo scopo principale di questa funzione - il calcolo corretto dei nuovi parametri MA tenendo conto dei "limiti fisici". Ovviamente, non possiamo rendere il periodo MA minore di 1, lo spostamento MA può essere casuale, ma il tipo MA è il numero da 0 a 3, corrispondente a un numero membro condizionale nell'enumerazione ENUM_MA_METHOD.

 

Controllo. Funziona, ma "al grado C". Cosa possiamo fare?

OK, applichiamo il nostro indicatore al grafico e iniziamo a premere sporadicamente i tasti di scelta rapida, che modificano i parametri MA. Sì, tutto funziona correttamente, ma c'è un fatto spiacevole: i TGV cambiano subito (si può verificare chiamando il TGV con il tasto F3), ma le MA non sempre ridisegnano subito ma solo all'arrivo del nuovo tick. Se abbiamo una sessione americana con il flusso di tick attivo, difficilmente possiamo notare il ritardo. Ma se succede di notte, durante la calma, possiamo aspettare il ridisegno per diversi minuti. Che cosa succede?

Ebbene, come si dice, ciò che scrivi, avrai. Prima di costruire 245 negli indicatori c'era solo un "punto di ingresso" - la funzione OnCalculate(). Ovviamente, non sto parlando delle funzioni OnInit() e OnDeinit(), che forniscono i calcoli iniziali, l'inizializzazione e il completamento dell'indicatore. Ora ci sono diversi punti di ingresso e sono collegati ai nuovi eventi Timer e ChartEvent.

Tuttavia, i nuovi gestori eseguono solo ciò che includono e non sono formalmente associati all’handler OnCalculate(). Quindi, cosa possiamo fare con il nostro handler "alieno" OnChartEvent() per farlo funzionare "bene", cioè consentirebbe di ridisegnare immediatamente il MA?

In generale, ci sono diversi modi per implementare questo requisito:

  • "Matryoshka" (chiamata OnCalculate() all'interno di OnChartEvent()): inserisce la chiamata alla funzione OnCalculate() in questo handler, precompilando tutti i suoi parametri. Poiché l’handler OnChartEvent() implica la modifica di almeno un parametro MA, influirà su tutta la sua cronologia, ovvero dobbiamo ricalcolarlo di nuovo "da zero", senza l'ottimizzazione dei calcoli.
  • "Tick artificiale" che trasferisce il controllo all'inizio della funzione OnCalculate(), che modifica il buffer grafico. Apparentemente, non ci sono metodi "legittimi", come si evince dalla documentazione MT5 (anche se forse ho cercato non così a fondo). Se sei interessato puoi cercare qualcosa come «API», «PostMessageA», ecc. Pertanto, non prenderemo in considerazione questa variante qui, perché non garantisce che le funzionalità non documentate un giorno non cambieranno. Non ho dubbi che si possa realizzare.

 

"Matryoshka" funziona!

Si scopre che abbiamo già fatto la cosa più importante. Di seguito è riportato un codice di funzione molto semplice. Puoi semplicemente inserire la sua chiamata direttamente davanti all'operatore di ritorno dell’handler OnChartEvent().

int OnCalculate_Void()
{
   const int rates_total = Bars( _Symbol, PERIOD_CURRENT );
   CopyClose( _Symbol, PERIOD_CURRENT, 0, rates_total, _price );
   OnCalculate( rates_total, 0, 0, _price );
   return( 1 );
}//+------------------------------------------------------------------+

Dopo aver compilato l'indicatore e averlo applicato al grafico, vediamo che in generale il codice funziona velocemente e indipendentemente dall'arrivo dei tick.

Lo svantaggio di questa implementazione è che esattamente i prezzi Close vengono copiati nell'array price[]. Se lo si desidera, la funzione CopyClose() può essere sostituita con ciò che si desidera impostando il campo "Applica a" nella scheda "Impostazioni" della finestra di dialogo delle proprietà dell'indicatore. Se il prezzo corrente sarà di base (Open, High, Low, Close), allora abbiamo già la funzione CopyXXXX() corrispondente. Nel caso di prezzi più complessi (Mediana, Tipica o Ponderata) dobbiamo calcolare l'array in modo diverso.

Non sono sicuro se non abbiamo bisogno della funzione CopyClose(), che copia l'intera cronologia dell'array. D'altra parte, questa funzione è abbastanza veloce quando la cronologia non è caricata troppo a fondo. Il controllo dell'indicatore su EURUSD H1 con la cronologia prima del 1999 (circa 700 mila barre) ha mostrato che l'indicatore si occupa di calcoli e non mostra alcun rallentamento. Su tale cronologia i possibili rallentamenti possono essere causati non dalla funzione CopyXXXX(), ma dalla necessità di un più complicato ricalcolo dell'indicatore dall'inizio della cronologia (obbligatorio).


Diversi risultati e conclusioni

Cosa c'è di meglio: un file indicatore o un tandem "indicatore + advisor"?

In realtà, questa domanda non è così semplice. Da un lato, è bene avere un file indicatore, perché tutte le funzioni, inclusi i gestori di eventi, sono concentrate in un unico posto.

D'altra parte, immaginiamo che ci siano 3 o 4 indicatori applicati al grafico insieme a un Expert Advisor: questa situazione non è rara. Inoltre, supponiamo che ogni indicatore sia dotato di un proprio gestore di eventi, oltre allo standard OnCalculate(). Per evitare confusione con l'elaborazione degli eventi in questa "crue eterogenea" è più ragionevole concentrare tutti i gestori di eventi, ora consentiti negli indicatori, in un unico posto - nell’Expert Advisor.

Da tempo gli sviluppatori di software decidono di darci la possibilità di elaborare gli eventi nell'indicatore: dalla versione beta non pubblica del 09.09.09 (quando l'indicatore è considerato come "puro calcolo & entità matematica" e non deve essere contaminato da eventuali caratteristiche che ostacolano la velocità di calcolo) sono trascorsi esattamente 5 mesi. Probabilmente, la "purezza dell'idea" deve soffrire - e ora si scatenerà un vero caos di fantasie dei programmatori. Ma l'equilibrio è sempre da qualche parte nel mezzo tra un'idea pura, ma limitata, e una capacità non così pulita, ma più potente.

A settembre-Ottobre 2009, quando il numero di build della versione beta di MT5 non ha nemmeno raggiunto 200, ho scritto e fatto il debug del codice del tandem "Expert Advisor + Indicator", che consentiva di gestire i parametri MA al volo, ma " al grado C": è stato aggiornato solo dopo l'arrivo del tick, ma non immediatamente. A quel tempo questo tandem era l'unica soluzione possibile, ed ora difficilmente interessa a chiunque.

Non potevo quindi pensare a come portare la funzionalità dell'indicatore a "grado B", ovvero come viene presentato nell'ultima versione. Ora sono lieto di fornire una soluzione più conveniente a tutti coloro che potrebbero essere interessanti.


In allegato il mio breve video, che mostra il lavoro della nostra creazione. Il cambiamento graduale della curva MA (solo il periodo sta cambiando - all'inizio aumenta, poi diminuisce) è persino abbagliante in qualche modo. Questa è Matryoshka (simile al famoso set russo di bambole nidificanti).


Naturalmente, tali trucchi sono utili solo quando il calcolo dell'indicatore stesso da zero non richiede troppo tempo. Le MA semplici, contenute in questo indicatore, soddisfano questo requisito.


Un aspetto scivoloso

Ricorda che i precedenti parametri esterni dell'indicatore sono ora le variabili globali del terminale (TGV), che puoi vedere premendo il tasto F3. Supponiamo di aver aperto la finestra di dialogo Variabili Globali e di aver modificato uno dei TGV (ad esempio, il periodo MA). Ti aspetti che questo cambiamento si rifletta immediatamente nell'indicatore sul grafico.

Attualmente nel terminale non è presente alcun evento, corrispondente alla modifica del TGV effettuata dall'utente (ad esempio, CHARTEVENT_GLOBALVAR_ENDEDIT). Inoltre, penso che non possiamo disabilitare la modifica del TGV nella finestra di dialogo Variabili Globali. Pertanto, qui non possiamo contare su nessun evento tranne il tick. Cosa accadrà in realtà?

Se non si tocca la tastiera, allora anche al tick successivo l'aggiornamento sarà "sbagliato": la variabile Updated non è stata azzerata, quindi verrà realizzato solo il calcolo "ottimizzato" dell'indicatore (corrispondente al precedente valore di TGV). In questo caso, per ristabilire la giustizia, possiamo consigliare solo una cosa: dopo aver modificato il TGV è necessario premere almeno una volta il tasto di scelta rapida, che modifica il TGV, imposta Updated= 0 e provoca il ricalcolo completo dell'indicatore.

Tutti i possibili utenti e sviluppatori dovrebbero tenere a mente questo fatto.


File allegati di codice sorgente e video

Infine, allego i file del codice sorgente. Spiegazione:

  1. Custom Moving Average.mq5 - File di codice sorgente MA, fornito con MT5.
  2. MyMA_ind_with_ChartEvent.mq5 - implementazione iniziale ("grado C"): l'indicatore si aggiorna solo dopo l'arrivo del segno di spunta.
  3. MyMA_ind_with_ChartEvent_Matryoshka.mq5 - la seconda (forse, "grado B") variante: l'indicatore si aggiorna immediatamente, senza attendere l'arrivo del tick.

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

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.
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.
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.
Implementazione Pratica di Filtri Digitali in MQL5 per Principianti Implementazione Pratica di Filtri Digitali in MQL5 per Principianti
L'idea di filtrare il segnale digitale è stata ampiamente discussa negli argomenti del forum sulla costruzione di sistemi di trading. E sarebbe imprudente non creare un codice standard di filtri digitali in MQL5. In questo articolo l'autore descrive la trasformazione del semplice codice dell'indicatore SMA dal suo articolo "Indicatori personalizzati in MQL5 per principianti" in codice di filtro digitale più complicato e universale. Questo articolo è un seguito logico all'articolo precedente. Indica anche come sostituire il testo nel codice e come correggere gli errori di programmazione.