English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Creazione di un Expert Advisor, che fa Trading su una Serie di Strumenti

Creazione di un Expert Advisor, che fa Trading su una Serie di Strumenti

MetaTrader 5Esempi | 16 dicembre 2021, 10:34
208 0
Nikolay Kositsin
Nikolay Kositsin

Introduzione

Il lato tecnico dell'implementazione del codice di programma in modo che un singolo Expert Advisor, lanciato su un singolo grafico, sia in grado di negoziare con diverse attività finanziarie contemporaneamente. In generale, questo non era un problema nemmeno in MQL4. Ma solo con l'avvento del terminale client MetaTrader 5, i trader hanno finalmente avuto l'opportunità di eseguire un'analisi completa del lavoro di tali automatizzati, utilizzando strategy tester.

Quindi, ora gli automi multi-valuta diventeranno più popolari che mai e possiamo prevedere un'ondata di interesse nella costruzione di tali sistemi di trading. Ma il problema principale dell'implementazione di tali robot è nel fatto che le loro dimensioni nel codice del programma si espandono, nella migliore delle ipotesi, in una progressione aritmetica, e questo non è facile da comprendere per un tipico programmatore.

In questo articolo scriveremo un semplice Expert Advisor multi-valuta, in cui i difetti della struttura sono, se non assenti, almeno ridotti al minimo.


1. Implementazione di un semplice sistema trend-following

In effetti, potremmo iniziare con un sistema di trading massimamente semplice, seguendo l'andamento sulla base di un terminale integrato di un indicatore tecnico Triple Exponential Moving Average. Questo è un algoritmo molto semplice, che non richiede commenti speciali e che ora introdurremo nel codice del programma.

Ma prima di tutto, vorrei trarre le conclusioni più generali sull'Expert Advisor. Ha senso iniziare con il blocco dei parametri di Expert Advisor in arrivo, dichiarati a livello globale.

Quindi, prima di tutto dobbiamo scegliere le attività finanziarie con cui lavoreremo. Ciò può essere fatto utilizzando variabili di input di linea, in cui è possibile memorizzare i simboli delle risorse. Ora sarebbe bello avere un interruttore di divieto commerciale per ogni attività finanziaria, che consentirebbe di disabilitare le operazioni di trading da parte dell'asset.

Naturalmente, ogni asset dovrebbe essere associato ai propri parametri di trading individuali di Stop Loss, Take Profit, volume della posizione aperta e slippage. E per ovvie ragioni, i parametri di input dell'indicatore Triple Exponential Moving Average per ogni chip di trading dovrebbero essere individuali.

Ecco un ultimo blocco di variabili di input per un solo chip, eseguito in conformità con questi argomenti. I blocchi rimanenti differiscono solo per i numeri nei nomi dei parametri di input dell'Expert Advisor. Per questo esempio mi sono limitato a sole dodici asset finanziari, anche se idealmente non ci sono limitazioni software per il numero di tali blocchi.

Abbiamo solo bisogno di qualcosa su cui fare trading! E, soprattutto, il nostro PC deve avere risorse sufficienti per risolvere questo problema.

input string                Symb0 = "EURUSD";
input  bool                Trade0 = true; 
input int                    Per0 = 15; 
input ENUM_APPLIED_PRICE ApPrice0 = PRICE_CLOSE;
input int                 StLoss0 = 1000;
input int               TkProfit0 = 2000;
input double                Lots0 = 0.1;
input int               Slippage0 = 30;

Ora che abbiamo capito le variabili a livello globale, possiamo procedere alla costruzione del codice all'interno della funzione OnTick(). L'opzione più razionale qui sarebbe la divisione dell'algoritmo per la ricezione dei segnali di trading e la parte di trading effettiva dell'Expert Advisor in due funzioni personalizzate.

E poiché l'Expert Advisor lavora con dodici asset finanziari contemporaneamente, ci devono essere anche dodici chiamate di queste funzioni all'interno del blocco OnTick(). 

Naturalmente, il primo parametro di input di queste funzioni dovrebbe essere un numero univoco, sotto il quale verranno elencate queste attività di trading. Il secondo parametro di input, per ovvi motivi, sarà il nome della linea dell'asset finanziario di trading.

Per il ruolo del terzo parametro, impostiamo una variabile logica per risolvere il trade. Successivamente, per l'algoritmo che determina i segnali di trading, segui i segnali dell'indicatore di input e per una funzione di trading - la distanza dagli ordini in sospeso, il volume di posizione e lo slippage (slittamento consentito del prezzo della posizione aperta).

Per trasferire i segnali di trading da una funzione all'altra, gli array statici devono essere impostati come parametri della funzione, che derivano i loro valori attraverso un riferimento. Questa è la versione finale del codice proposto per la funzione OnTick().

void OnTick()
  {
//--- declare variables arrays for trade signals 
   static bool UpSignal[12], DnSignal[12], UpStop[12], DnStop[12];
  
//--- get trade signals
   TradeSignalCounter( 0, Symb0,  Trade0,  Per0,  ApPrice0,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 1, Symb1,  Trade1,  Per1,  ApPrice1,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 2, Symb2,  Trade2,  Per2,  ApPrice2,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 3, Symb3,  Trade3,  Per3,  ApPrice3,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 4, Symb4,  Trade4,  Per4,  ApPrice4,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 5, Symb5,  Trade5,  Per5,  ApPrice5,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 6, Symb6,  Trade6,  Per6,  ApPrice6,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 7, Symb7,  Trade7,  Per7,  ApPrice7,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 8, Symb8,  Trade8,  Per8,  ApPrice8,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 9, Symb9,  Trade9,  Per9,  ApPrice9,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter(10, Symb10, Trade10, Per10, ApPrice10, UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter(11, Symb11, Trade11, Per11, ApPrice11, UpSignal, DnSignal, UpStop, DnStop);
  
//--- perform trade operations
   TradePerformer( 0, Symb0,  Trade0,  StLoss0,  TkProfit0,  Lots0,  Slippage0,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 1, Symb1,  Trade1,  StLoss1,  TkProfit1,  Lots1,  Slippage1,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 2, Symb2,  Trade2,  StLoss2,  TkProfit2,  Lots2,  Slippage2,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 3, Symb3,  Trade3,  StLoss3,  TkProfit3,  Lots3,  Slippage3,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 4, Symb4,  Trade4,  StLoss4,  TkProfit4,  Lots4,  Slippage4,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 5, Symb5,  Trade5,  StLoss5,  TkProfit5,  Lots5,  Slippage5,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 6, Symb6,  Trade6,  StLoss6,  TkProfit6,  Lots6,  Slippage6,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 7, Symb7,  Trade7,  StLoss7,  TkProfit7,  Lots7,  Slippage7,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 8, Symb8,  Trade8,  StLoss8,  TkProfit8,  Lots8,  Slippage8,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 9, Symb9,  Trade9,  StLoss9,  TkProfit9,  Lots9,  Slippage9,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer(10, Symb10, Trade10, StLoss10, TkProfit10, Lots10, Slippage10, UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer(11, Symb11, Trade11, StLoss11, TkProfit11, Lots11, Slippage11, UpSignal, DnSignal, UpStop, DnStop); 
//---
  }

All'interno della funzione TradeSignalCounter(), è necessario ottenere l’handle dell'indicatore tecnico Triple Exponential Moving Average una volta all'inizio di ogni chip, e poi ad ogni cambio della barra per calcolare i segnali di trading.

Questo schema relativamente semplice con l'implementazione nel codice sta iniziando ad essere pieno di piccoli dettagli.

bool TradeSignalCounter(int Number,
                        string Symbol_,
                        bool Trade,
                        int period,
                        ENUM_APPLIED_PRICE ApPrice,
                        bool &UpSignal[],
                        bool &DnSignal[],
                        bool &UpStop[],
                        bool &DnStop[])
  {
//--- check if trade is prohibited
   if(!Trade)return(true);

//--- declare variable to store final size of variables arrays
   static int Size_=0;

//--- declare array to store handles of indicators as static variable
   static int Handle[];

   static int Recount[],MinBars[];
   double TEMA[4],dtema1,dtema2;

//--- initialization
   if(Number+1>Size_) // Entering the initialization block only on first start
     {
      Size_=Number+1; // For this number entering the block is prohibited

      //--- change size of variables arrays
      ArrayResize(Handle,Size_);
      ArrayResize(Recount,Size_);
      ArrayResize(MinBars,Size_);

      //--- determine minimum number of bars, sufficient for calculation 
      MinBars[Number]=3*period;

      //--- setting array elements to 0
      DnSignal[Number] = false;
      UpSignal[Number] = false;
      DnStop  [Number] = false;
      UpStop  [Number] = false;

      //--- use array as timeseries
      ArraySetAsSeries(TEMA,true);

      //--- get indicator's handle
      Handle[Number]=iTEMA(Symbol_,0,period,0,ApPrice);
     }

//--- check if number of bars is sufficient for calculation 
   if(Bars(Symbol_,0)<MinBars[Number])return(true);
//--- get trade signals 
   if(IsNewBar(Number,Symbol_,0) || Recount[Number]) // Entering the block on bar change or on failed copying of data
     {
      DnSignal[Number] = false;
      UpSignal[Number] = false;
      DnStop  [Number] = false;
      UpStop  [Number] = false;

      //--- using indicator's handles, copy values of indicator's
      //--- buffers into static array, specially prepared for this purpose
      if(CopyBuffer(Handle[Number],0,0,4,TEMA)<0)
        {
         Recount[Number]=true; // As data were not received, we should return 
                               // into this block (where trade signals are received) on next tick!
         return(false);        // Exiting the TradeSignalCounter() function without receiving trade signals
        }

      //--- all copy operations from indicator buffer are successfully completed
      Recount[Number]=false; // We may not return to this block until next change of bar

      int Digits_ = int(SymbolInfoInteger(Symbol_,SYMBOL_DIGITS)+4);
      dtema2 = NormalizeDouble(TEMA[2] - TEMA[3], Digits_);
      dtema1 = NormalizeDouble(TEMA[1] - TEMA[2], Digits_);

      //---- determining the input signals
      if(dtema2 > 0 && dtema1 < 0) DnSignal[Number] = true;
      if(dtema2 < 0 && dtema1 > 0) UpSignal[Number] = true;

      //---- determining the output signals
      if(dtema1 > 0) DnStop[Number] = true;
      if(dtema1 < 0) UpStop[Number] = true;
     }
//----+
   return(true);
  }

A questo proposito, il codice della funzione TradePerformer() risulta essere silenzioso e semplice:

bool TradePerformer(int    Number,
                    string Symbol_,
                    bool   Trade,
                    int    StLoss,
                    int    TkProfit,
                    double Lots,
                    int    Slippage,
                    bool  &UpSignal[],
                    bool  &DnSignal[],
                    bool  &UpStop[],
                    bool  &DnStop[])
  {
//--- check if trade is prohibited
   if(!Trade)return(true);

//--- close opened positions 
   if(UpStop[Number])BuyPositionClose(Symbol_,Slippage);
   if(DnStop[Number])SellPositionClose(Symbol_,Slippage);

//--- open new positions
   if(UpSignal[Number])
      if(BuyPositionOpen(Symbol_,Slippage,Lots,StLoss,TkProfit))
         UpSignal[Number]=false; //This trade signal will be no more on this bar!
//---
   if(DnSignal[Number])
      if(SellPositionOpen(Symbol_,Slippage,Lots,StLoss,TkProfit))
         DnSignal[Number]=false; //This trade signal will be no more on this bar!
//---
   return(true);
  }
Ma questo è solo perché i comandi effettivi per l'esecuzione delle operazioni di trading sono racchiusi in quattro funzioni aggiuntive:
BuyPositionClose();
SellPositionClose();
BuyPositionOpen();
SellPositionOpen();

Tutte e quattro le funzioni funzionano in modo del tutto analogo, quindi possiamo limitarci all'esame di una sola di esse:

bool BuyPositionClose(const string symbol,ulong deviation)
  {
//--- declare structures of trade request and result of trade request
   MqlTradeRequest request;
   MqlTradeResult result;
   ZeroMemory(request);
   ZeroMemory(result);

//--- check if there is BUY position
   if(PositionSelect(symbol))
     {
      if(PositionGetInteger(POSITION_TYPE)!=POSITION_TYPE_BUY) return(false);
     }
   else  return(false);

//--- initializing structure of the MqlTradeRequest to close BUY position
   request.type   = ORDER_TYPE_SELL;
   request.price  = SymbolInfoDouble(symbol, SYMBOL_BID);
   request.action = TRADE_ACTION_DEAL;
   request.symbol = symbol;
   request.volume = PositionGetDouble(POSITION_VOLUME);
   request.sl = 0.0;
   request.tp = 0.0;
   request.deviation=(deviation==ULONG_MAX) ? deviation : deviation;
   request.type_filling=ORDER_FILLING_FOK;
//---
   string word="";
   StringConcatenate(word,
                     "<<< ============ BuyPositionClose():   Close Buy position at ",
                     symbol," ============ >>>");
   Print(word);

//--- send order to close position to trade server
   if(!OrderSend(request,result))
     {
      Print(ResultRetcodeDescription(result.retcode));
      return(false);
     }
//----+
   return(true);
  }

Fondamentalmente, questo è praticamente l'intero Expert Advisor multi-valuta (Exp_TEMA.mq5)!

Oltre alle funzioni considerate, contiene due funzioni utente aggiuntive:

bool IsNewBar(int Number, string symbol, ENUM_TIMEFRAMES timeframe);
string ResultRetcodeDescription(int retcode);

La prima di queste funzioni restituisce il valore reale al momento della modifica della barra, in base al simbolo e all'intervallo di tempo selezionati, e la seconda, restituisce la riga dal codice risultato della transazione di trading, derivato dal campo retcode della struttura della richiesta di trading MqlTradeResult

L'Expert Advisor è pronto, è tempo di iniziare con i test! Non ci sono differenze visibili e serie nei test dell'Expert Advisor multi-valuta rispetto al suo collega Expert Advisor a moneta unica.

Determinare le configurazioni nel tab "Parametri" dello Strategy Tester:

Figura 1. Tab "Impostazioni" dello Strategy tester

Figura 1. Tab "Impostazioni" dello Strategy tester

Se necessario, regolare i valori dei parametri di input nella scheda "Parametri di input:

Figura 2. Tab "Parametri" dello Strategy Tester

Figura 2. Tab "Parametri" dello Strategy tester

e quindi fare click sul pulsante "Start" nello Strategy Tester nel tab "Impostazioni":

Figura 3. Esecuzione del test di Expert Advisor

Figura 3. Esecuzione del test di Expert Advisor

Il tempo di passaggio della prima prova dell'Expert Advisor può rivelarsi molto significativo, a causa del caricamento della cronologia per tutti e dodici i simboli. Dopo aver completato il test nello strategy tester, apri il tab "Risultati":

Figura 4. Risultati dei test

Figura 4. Risultati dei test

e fare un'analisi dei dati, utilizzando il contenuto del tab "Chart":

Figura 5. Grafico delle dinamiche del saldo e del capitale

Figura 5. Grafico delle dinamiche del saldo e del capitale

e il "Journal":

Figura 6. Journal dello Strategy tester

Figura 6. Journal dello Strategy tester

Naturalmente, l'essenza stessa degli ingressi e delle uscite dell'algoritmo dal market di questo Expert Advisor è troppo semplice, e sarebbe ingenuo aspettarsi risultati molto significativi, quando si utilizzano i primi parametri casuali. Ma il nostro obiettivo qui è dimostrare l'idea fondamentale di costruire un Expert Advisor multi-valuta nel modo più semplice possibile.

Con l'ottimizzazione di questo Expert Advisor possono sorgere alcuni inconvenienti dovuti a troppi parametri di input. L'algoritmo genetico di ottimizzazione richiede una quantità molto minore di questi parametri, quindi l'Expert Advisor dovrebbe essere ottimizzato su ciascun chip individualmente, disabilitando i restanti chip dei parametri di input TradeN.

Ora, quando l'essenza stessa dell'approccio è stata delineata, puoi iniziare a lavorare con l'algoritmo più interessante del processo decisionale per il robot multi-valuta.


2. Risonanze sui mercati finanziari e loro applicazione nei sistemi di trading

L'idea di tenere conto delle correlazioni tra i diversi asset finanziari, in generale, non è nuova, e sarebbe interessante implementare l'algoritmo, che si baserebbe proprio sull'analisi di tali tendenze. In questo articolo implementerò un'automazione multi-valuta, basata sull'articolo di Vasily Yakimkin "Resonances - a New Class of Technical Indicators" pubblicato sulla rivista "Currency Speculator" (in russo) 04, 05, 2001.

L'essenza stessa di questo approccio in poche parole sembra la seguente. Ad esempio, per la ricerca su EUR / USD, utilizziamo non solo i risultati di alcuni indicatori sull'attività finanziaria, ma anche i risultati dello stesso indicatore relativi alle attività EUR / USD - EUR / JPY e USD / JPY. È meglio usare l'indicatore, i cui valori sono normalizzati nello stesso intervallo di modifiche per la semplicità e la facilità delle misurazioni e dei calcoli.

Considerando questi requisiti, l'indicatore stocastico si presta bene per questo classico. Anche se, in realtà, non vi è alcuna differenza nell'uso di altri indicatori. Come direzione di tendenza considereremo il segno di differenza tra il valore dello Stoh stocastico e il suo segno della linea Sign .

Figura 7. Determinare la direzione della tendenza

Figura 7. Determinare la direzione della tendenza

Per il simbolo variabile dStoh esiste un'intera tabella delle possibili combinazioni e delle loro interpretazioni per la direzione del trend attuale:

Figura 8. Combinazioni del simbolo variabile dStoh e della direzione di tendenza

Figura 8. Combinazioni del simbolo variabile dStoh e della direzione di tendenza

Nel caso in cui due segnali degli asset EUR / JPY e USD / JPY hanno valori opposti, dovremmo determinare la loro somma e, se questa somma è maggiore di zero, considerare entrambi i segnali come positivi, altrimenti - come negativi.

Pertanto, per l'apertura di Longs, utilizzare la situazione in cui il trend è in crescita, e per uscire, utilizzare una tendenza al ribasso, o una tendenza quando i segnali dell'indicatore dell'asset principale EUR / USD sono negativi. Inoltre, esci dal lungo se l'asset principale non ha segnali e se la somma della variabile dStoh per le attività rimanenti è inferiore a zero. Per i pantaloncini, tutto è assolutamente analogo, solo la situazione è opposta.

La soluzione più razionale sarebbe quella di posizionare l'intera parte analitica dell'Expert Advisor nell'indicatore multi-valuta, e per l'Expert Advisor dai buffer degli indicatori, prendere solo i segnali pronti per il controllo dei trade. La versione di questo tipo di indicatore è presentata dall'indicatore MultiStochastic.mq5, che fornisce un'analisi visiva delle condizioni di mercato.

Figura 9. Indicatore MultiStochastic

Figura 9. Indicatore MultiStochastic

La barra verde segnala l'apertura e il mantenimento dei longs e le barre rosse - degli shorts, rispettivamente. I punti rosa e verde chiaro sul bordo superiore del grafico rappresentano i segnali di uscita dalle posizioni lunghe e corte.

Questo indicatore può essere utilizzato direttamente per ricevere segnali nell'Expert Advisor, ma sarebbe comunque meglio facilitare il suo lavoro e rimuovere tutti i buffer e gli elementi di visualizzazione non necessari, lasciando solo ciò che è direttamente coinvolto nella fornitura di segnali di trading. Questo è esattamente ciò che è stato fatto nell'indicatore MultiStochastic_Exp.mq5.

In questo Expert Advisor, ho scambiato solo tre chip, quindi il codice della funzione OnTick() è diventato estremamente semplice:

void OnTick()
  {
//--- declare variables arrays for trade signals
  static bool UpSignal[], DnSignal[], UpStop[], DnStop[];
  
//--- get trade signals
  TradeSignalCounter(0, Trade0, Kperiod0, Dperiod0, slowing0, ma_method0, price_0, SymbolA0, SymbolB0, SymbolC0, UpSignal, DnSignal, UpStop, DnStop);
  TradeSignalCounter(1, Trade1, Kperiod1, Dperiod1, slowing1, ma_method1, price_1, SymbolA1, SymbolB1, SymbolC1, UpSignal, DnSignal, UpStop, DnStop);
  TradeSignalCounter(2, Trade2, Kperiod2, Dperiod2, slowing2, ma_method2, price_2, SymbolA2, SymbolB2, SymbolC2, UpSignal, DnSignal, UpStop, DnStop);
                             
//--- perform trade operations
   TradePerformer( 0, SymbolA0,  Trade0,  StopLoss0,  0,  Lots0,  Slippage0,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 1, SymbolA1,  Trade1,  StopLoss1,  0,  Lots1,  Slippage1,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 2, SymbolA2,  Trade2,  StopLoss2,  0,  Lots2,  Slippage2,  UpSignal, DnSignal, UpStop, DnStop);
//---
  }

Tuttavia, il codice della funzione TradeSignalCounter() è un po' più complesso: Il fatto è che un indicatore multi-valuta funziona direttamente con tre timeserie di diversi asset finanziari e, pertanto, implementiamo una verifica più sottile delle barre per l'adeguatezza del numero minimo di esse in una delle tre timeserie, utilizzando la funzione Rates_Total ().

Inoltre, viene effettuata un'ulteriore verifica sulla sincronizzazione delle timeserie, utilizzando la funzione SynchroCheck(), per garantire l'accuratezza nel determinare il momento in cui si verifica un cambio di barra in tutte le timeserie contemporaneamente.

bool TradeSignalCounter(int Number,
                        bool Trade,
                        int Kperiod,
                        int Dperiod,
                        int slowing,
                        ENUM_MA_METHOD ma_method,
                        ENUM_STO_PRICE price_,
                        string SymbolA,
                        string SymbolB,
                        string SymbolC,
                        bool &UpSignal[],
                        bool &DnSignal[],
                        bool &UpStop[],
                        bool &DnStop[])
  {
//--- check if trade is prohibited
   if(!Trade)return(true);
//--- declare variable to store sizes of variables arrays
   static int Size_=0;
//--- declare arrays to store handles of indicators as static variables
   static int Handle[];
   static int Recount[],MinBars[];
//---
   double dUpSignal_[1],dDnSignal_[1],dUpStop_[1],dDnStop_[1];
//--- change size of variables arrays
   if(Number+1>Size_)
     {
      uint size=Number+1;
      //----
      if(ArrayResize(Handle,size)==-1
         || ArrayResize(Recount,size)==-1
         || ArrayResize(UpSignal, size) == -1
         || ArrayResize(DnSignal, size) == -1
         || ArrayResize(UpStop, size) == -1
         || ArrayResize(DnStop, size) == -1
         || ArrayResize(MinBars,size) == -1)
        {
         string word="";
         StringConcatenate(word,"TradeSignalCounter( ",Number,
                           " ): Error!!! Unable to change sizes of variables arrays!!!");
         int error=GetLastError();
         ResetLastError();
         //---
         if(error>4000)
           {
            StringConcatenate(word,"TradeSignalCounter( ",Number," ): Error code ",error);
            Print(word);
           }
         Size_=-2;
         return(false);
        }

      Size_=int(size);
      Recount[Number] = false;
      MinBars[Number] = Kperiod + Dperiod + slowing;

      //--- get indicator's handle
      Handle[Number]=iCustom(SymbolA,0,"MultiStochastic_Exp",
                             Kperiod,Dperiod,slowing,ma_method,price_,
                             SymbolA,SymbolB,SymbolC);
     }
//--- check if number of bars is sufficient for calculation 
   if(Rates_Total(SymbolA,SymbolB,SymbolC)<MinBars[Number])return(true);
//--- check timeseries synchronization
   if(!SynchroCheck(SymbolA,SymbolB,SymbolC))return(true);
//--- get trade signals 
   if(IsNewBar(Number,SymbolA,0) || Recount[Number])
     {
      DnSignal[Number] = false;
      UpSignal[Number] = false;
      DnStop  [Number] = false;
      UpStop  [Number] = false;

      //--- using indicators' handles, copy values of indicator's 
      //--- buffers into static arrays, specially prepared for this purpose
      if(CopyBuffer(Handle[Number], 1, 1, 1, dDnSignal_) < 0){Recount[Number] = true; return(false);}
      if(CopyBuffer(Handle[Number], 2, 1, 1, dUpSignal_) < 0){Recount[Number] = true; return(false);}
      if(CopyBuffer(Handle[Number], 3, 1, 1, dDnStop_  ) < 0){Recount[Number] = true; return(false);}
      if(CopyBuffer(Handle[Number], 4, 1, 1, dUpStop_  ) < 0){Recount[Number] = true; return(false);}

      //--- convert obtained values into values of logic variables of trade commands
      if(dDnSignal_[0] == 300)DnSignal[Number] = true;
      if(dUpSignal_[0] == 300)UpSignal[Number] = true;
      if(dDnStop_  [0] == 300)DnStop  [Number] = true;
      if(dUpStop_  [0] == 300)UpStop  [Number] = true;

      //--- all copy operations from indicator's buffers completed successfully
      //--- unnecessary to return into this block until next bar change
      Recount[Number]=false;
     }
//----+
   return(true);
  }

Non ci sono altre differenze ideologiche radicali del codice di questo Expert Advisor (Exp_ResonanceHunter.mq5) dovute al fatto che è compilato sulla base delle stesse componenti funzionali. Quindi non credo che sarà necessario dedicare altro tempo alla sua struttura interna.


Conclusione

A mio parere, il codice dell'Expert Advisor multi-valuta in MQL5 è assolutamente analogo al codice di un normale Expert Advisor.


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

File allegati |
multistochastic.mq5 (17.47 KB)
exp_tema.mq5 (25.17 KB)
Test delle Prestazioni del Calcolo delle Medie Mobili in MQL5 Test delle Prestazioni del Calcolo delle Medie Mobili in MQL5
Dal momento della creazione del primo indicatore della media mobile, sono comparsi numerosi indicatori. Molti di loro utilizzano metodi di smoothing simili, ma non sono state studiate le prestazioni di diversi algoritmi di medie mobili. In questo articolo, prenderemo in considerazione i possibili modi d’utilizzo delle medie mobili in MQL5 e confronteremo le loro prestazioni.
Analizzare i Modelli di Candele Analizzare i Modelli di Candele
La costruzione del grafico a candele giapponesi e l'analisi dei modelli di candele costituiscono un'area straordinaria dell’analisi tecnica. Il vantaggio dei modelli di candele è che rappresentano i dati in modo tale da poter tenere traccia delle dinamiche all'interno dei dati. In questo articolo analizziamo i tipi di candele, la classificazione dei modelli di candele e presentiamo un indicatore in grado di determinare queste ultime.
I Principi del Calcolo Economico degli Indicatori I Principi del Calcolo Economico degli Indicatori
Le chiamate all'utente e gli indicatori tecnici occupano pochissimo spazio nel codice del programma dei sistemi di trading automatizzati. Spesso si tratta semplicemente di poche righe di codice. Ma capita spesso che siano queste poche righe di codice a impiegare la maggior parte del tempo, che deve essere speso per testare l'Expert Advisor. Pertanto, tutto ciò che è correlato ai calcoli dei dati all'interno di un indicatore, deve essere considerato molto attentamente di quanto sembrerebbe a prima vista. In questo articolo si parlerà proprio di questo.
Guida alla scrittura di una DLL per MQL5 in Delphi Guida alla scrittura di una DLL per MQL5 in Delphi
L'articolo descrive il meccanismo per creare un modulo DLL, utilizzando il popolare linguaggio di programmazione ObjectPascal, all'interno di un ambiente di programmazione Delphi. I materiali, forniti in questo articolo, sono progettati principalmente per i programmatori principianti che stanno affrontando dei problemi, che violano i confini del linguaggio di programmazione integrato di MQL5, collegando i moduli DLL esterni.