English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Creazione di un Multi-Currency Multi-System Expert Advisor

Creazione di un Multi-Currency Multi-System Expert Advisor

MetaTrader 5Esempi | 11 gennaio 2022, 17:15
133 0
Maxim Khrolenko
Maxim Khrolenko

Introduzione

Credo che ci siano parecchi trader che scambiano più di un simbolo di trading e utilizzano più strategie. Questo approccio non solo ti consente di aumentare potenzialmente il tuo profitto, ma anche di ridurre al minimo il rischio di un sostanziale drawdown su una gestione efficiente del denaro. Quando si crea un Expert Advisor, il primo passo naturale per verificare l'efficienza della strategia del programma è l'ottimizzazione al fine di determinare i migliori parametri di input.

Con i valori dei parametri identificati, gli Expert Advisor sarebbero tecnicamente pronti per il trading. Tuttavia, ciò lascerebbe una domanda importante senza risposta. Come sarebbero i risultati dei test se un trader potesse mettere insieme tutte le sue strategie in un unico Expert Advisor? La consapevolezza che il drawdown su diversi simboli o strategie potrebbe a un certo punto sovrapporsi e risultare in un orribile drawdown totale o persino in una richiesta di margine può a volte essere una brutta sorpresa.

Questo articolo introduce un concetto di creazione di un Expert Advisor multi-sistema multi-valuta che ci permetterà di trovare una risposta a questa importante domanda.


1. Struttura dell'Expert Advisor

In termini generali, la struttura dell'Expert Advisor è la seguente:

Fig. 1. Struttura dell'Expert Advisor multi-sistema multi-valuta

Fig. 1. Struttura dell'Expert Advisor multi-sistema multi-valuta

Come puoi vedere, il programma si basa su un ciclo for. Ogni strategia è organizzata in un ciclo in cui ogni iterazione è responsabile del trading di ciascun simbolo separatamente. Qui, puoi organizzare in loop un numero illimitato di strategie. È importante che il tuo computer disponga di risorse sufficienti per "elaborare" un tale programma.

Dovresti tenere presente che potrebbe esserci solo una posizione per ogni simbolo scambiato in MetaTrader 5. Tale posizione rappresenta la somma di lotti di acquisti e vendite precedentemente eseguiti. Pertanto, il risultato del test multistrategia per un simbolo non sarà identico alla somma dei risultati dei test separati delle stesse strategie per lo stesso simbolo.

Per una considerazione più attenta della struttura dell'Expert Advisor adotteremo 2 strategie ognuna delle quali scambia due simboli:

Strategia A:

  • Acquista Il prezzo Ask raggiunge la banda inferiore dell'indicatore Bollinger Bands calcolato in base al prezzo basso.
    Chiusura: Il prezzo di offerta raggiunge la banda inferiore dell'indicatore Bollinger Bands calcolato in base al prezzo elevato.
  • Sell Il prezzo di offerta raggiunge la banda superiore dell'indicatore Bollinger Bands calcolato in base al prezzo elevato.
    Chiusura: Il prezzo Ask raggiunge la banda superiore dell'indicatore Bollinger Bands calcolato in base al prezzo basso.
  • Restrizione: solo un affare può essere eseguito su un determinato bar.

Strategia В:

  • Acquista: la barra precedente è ribassista (chiudi < apri) e il prezzo Ask raggiunge il massimo della barra precedente.
    Chiusura: tramite Stop Loss o Take Profit.
  • Vendi: la barra precedente è rialzista (chiudi > apri) e il prezzo bid raggiunge il minimo della barra precedente.
    Chiusura: tramite Stop Loss o Take Profit.
  • Restrizione: solo un affare può essere eseguito su un determinato bar.

Per essere indipendenti dai nuovi tick per un simbolo su cui verrà testato l'Expert Advisor o che scambierà, è consigliabile utilizzare la funzione OnTimer() per il trading in modalità multi-valuta.

A tale scopo, quando inizializzamo Expert Advisor specifichiamo la frequenza di generazione di un evento per la chiamata di calcolo del programma utilizzando la funzione EventSetTimer() e, al momento della deistizializzazione, utilizziamo la funzione EventKillTimer() per dire al terminale di interrompere la generazione di eventi:

// Include standard libraries
// Create external parameters
// Create arrays, variables, indicator handles, etc.

//--- Initialization of the Expert Advisor
int OnInit()
  {
   //--- Set event generation frequency
   EventSetTimer(1); // 1 second
   // ...
   return(0);
  }
void OnTimer()
  {
   // ...
  }
//--- Deinitialization of the Expert Advisor
void OnDeinit(const int reason)
  {
   //--- Stop event generation
   EventKillTimer();
   // ...
  }

Invece di EventSetTimer(), è anche possibile utilizzare EventSetMillisecondTimer(), dove la frequenza è impostata con precisione al millisecondo, ma non si deve utilizzarla in modo improprio con chiamate di calcolo del programma troppo frequenti.

Per accedere alle impostazioni di account, posizione e simbolo, nonché alle funzioni di trading, utilizzeremo rispettivamente le classi, CAccountInfo, CPositionInfo, CSymbolInfo e CTrade. Includiamoli nell'Expert Advisor:

//--- Include standard libraries
#include <Trade\AccountInfo.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Trade\Trade.mqh>

Poiché Expert Advisor si basa su cicli for, dovremo creare matrici per i suoi parametri esterni. Creiamo innanzitutto costanti uguali al numero di simboli per ogni strategia:

//--- Number of traded symbols for each strategy
#define Strategy_A 2
#define Strategy_B 2

Creiamo quindi parametri esterni. Utilizzando le costanti, determiniamo le dimensioni delle matrici in cui verranno copiate. Inoltre, creiamo maniglie degli indicatori e altre variabili globali.

Un esempio per un simbolo di strategia А è fornito di seguito:

//------------------- External parameters of strategy A
input string          Data_for_Strategy_A="Strategy A -----------------------";
//--- Symbol 0
input string          Symbol_A0      = "EURUSD";   // Symbol
input bool            IsTrade_A0     = true;       // Permission for trading
//--- Bollinger Bands (BB) parameters
input ENUM_TIMEFRAMES Period_A0      = PERIOD_H1;  // ВВ period
input uint            BBPeriod_A0    = 20;         // Period for calculation of the moving average of BB
input int             BBShift_A0     = 0;          // Horizontal shift of ВВ
input double          BBDeviation_A0 = 2.0;        // Number of standard deviations of BB
//...
//--- General parameters of strategy A
input double          DealOfFreeMargin_A = 1.0;    // Percent of free margin for a deal
input uint            MagicNumber_A      = 555;    // Magic number
input uint            Slippage_A         = 100;    // Permissible slippage for a deal
//...
//------------- Set variables of strategy A -----
//--- Arrays for external parameters
string          Symbol_A[Strategy_A];
bool            IsTrade_A[Strategy_A];
ENUM_TIMEFRAMES Period_A[Strategy_A];
int             BBPeriod_A[Strategy_A];
int             BBShift_A[Strategy_A];
double          BBDeviation_A[Strategy_A];
//--- Arrays for global variables
double          MinLot_A[Strategy_A],MaxLot_A[Strategy_A];
double          Point_A[Strategy_A],ContractSize_A[Strategy_A];
uint            DealNumber_A[Strategy_A];
datetime        Locked_bar_time_A[Strategy_A],time_arr_A[];
//--- Indicator handles
int             BB_handle_high_A[Strategy_A];
int             BB_handle_low_A[Strategy_A];
//--- Arrays for indicator values
double          BB_upper_band_high[],BB_lower_band_high[];
double          BB_upper_band_low[],BB_lower_band_low[];
//--- Class
CTrade          Trade_A;
//...
//--- Set global variables for all strategies
long            Leverage;
//--- Classes
CAccountInfo    AccountInfo;
CPositionInfo   PositionInfo;
CSymbolInfo     SymbolInfo;

Per avere la possibilità di disabilitare il trading per un determinato simbolo, abbiamo creato una variabile booleana IsTrade_A0 che verrà posizionata all'inizio dei loop for.


2. Inizializzazione dell'Expert Advisor

Per prima cosa, otteniamo i valori richiesti per tutte le strategie, ad esempio la leva finanziaria. Poiché la leva viene applicata al conto di trading e non ha nulla a che fare con una strategia o un simbolo, non è necessario copiare il suo valore negli array:

//--- Get the leverage for the account
   Leverage=AccountInfo.Leverage();

Quindi copiamo le variabili esterne in matrici.

//--- Copy external variables to arrays
   Symbol_A[0]     =Symbol_A0;
   IsTrade_A[0]    =IsTrade_A0;
   Period_A[0]     =Period_A0;
   BBPeriod_A[0]   =(int)BBPeriod_A0;
   BBShift_A[0]    =BBShift_A0;
   BBDeviation_A[0]=BBDeviation_A0;

Se un parametro esterno è definito dal tipo che richiederà la conversione in un altro, questo può essere fatto in un modo più conveniente durante la copia in matrici.

In questo caso, possiamo vedere che BBPeriod_A0 è stato creato come uint per impedire all'utente di impostare un valore negativo. Qui, lo convertiamo in int e lo copiamo nell'array che è stato anche creato come int. In caso contrario, il compilatore darà un avviso se si tenta di inserire il parametro di tipo uint nell'handle dell'indicatore.

Vediamo ulteriormente se il simbolo negoziato è disponibile nel Market Watch e se è stato utilizzato più di una volta all'interno di una strategia:

//--- Check for the symbol in the Market Watch
   for(int i=0; i<Strategy_A; i++)
     {
      if(IsTrade_A[i]==false) continue;
      if(IsSymbolInMarketWatch(Symbol_A[i])==false)
        {
         Print(Symbol_A[i]," could not be found on the server!");
         ExpertRemove();
        }
     }

//--- Check whether the symbol is used more than once
   if(Strategy_A>1)
     {
      for(int i=0; i<Strategy_A-1; i++)
        {
         if(IsTrade_A[i]==false) continue;
         for(int j=i+1; j<Strategy_A; j++)
           {
            if(IsTrade_A[j]==false) continue;
            if(Symbol_A[i]==Symbol_A[j])
              {
               Print(Symbol_A[i]," is used more than once!");
               ExpertRemove();
              }
           }
        }
     }
//--- The IsSymbolInMarketWatch() function
bool IsSymbolInMarketWatch(string f_Symbol)
  {
   for(int s=0; s<SymbolsTotal(false); s++)
     {
      if(f_Symbol==SymbolName(s,false))
         return(true);
     }
   return(false);
  }

Se i simboli sono stati selezionati correttamente, verificare la presenza di errori nei parametri di input per ciascuno di essi, creare maniglie degli indicatori, ottenere i dati necessari per il calcolo del lotto e, se necessario, fare altre cose come definito dalla strategia data.

Implementeremo le azioni sopra menzionate all'interno di un ciclo for.

//--- General actions
   for(int i=0; i<Strategy_A; i++)
     {
      if(IsTrade_A[i]==false) continue;
      //--- Check for errors in input parameters
      //...
      //--- Set indicator handles
      BB_handle_high_A[i]=iBands(Symbol_A[i],Period_A[i],BBPeriod_A[i],BBShift_A[i],BBDeviation_A[i],
                                 PRICE_HIGH);
      if(BB_handle_high_A[i]<0)
        {
         Print("Failed to create a handle for Bollinger Bands based on High prices for ",Symbol_A[i]," . Handle=",INVALID_HANDLE,
               "\n Error=",GetLastError());
         ExpertRemove();
        }
      //...
      //--- Calculate data for the Lot
      //--- set the name of the symbol for which the information will be obtained
      SymbolInfo.Name(Symbol_A[i]);
      //--- minimum and maximum volume size in trading operations
      MinLot_A[i]=SymbolInfo.LotsMin();
      MaxLot_A[i]=SymbolInfo.LotsMax();
      //--- point value
      Point_A[i]=SymbolInfo.Point();
      //--- contract size
      ContractSize_A[i]=SymbolInfo.ContractSize();

      //--- Set some additional parameters
     }

Quindi, impostiamo i parametri per le operazioni di trading della strategia A utilizzando l'oggetto Trade_A della classe CTrade.

//--- Set parameters for trading operations
//--- set the magic number
   Trade_A.SetExpertMagicNumber(MagicNumber_A);
//--- set the permissible slippage in points upon deal execution
   Trade_A.SetDeviationInPoints(Slippage_A);
//--- order filling mode, use the mode that is allowed by the server
   Trade_A.SetTypeFilling(ORDER_FILLING_RETURN);
//--- logging mode, it is advisable not to call this method as the class will set the optimal mode by itself
   Trade_A.LogLevel(1);
//--- the function to be used for trading: true - OrderSendAsync(), false - OrderSend().
   Trade_A.SetAsyncMode(true);

La stessa procedura viene ripetuta per ogni strategia, vale a.

  1. Copiare variabili esterne in matrici;
  2. Verificare se i simboli sono selezionati correttamente;
  3. Controllare gli errori, impostare le maniglie degli indicatori, calcolare i dati per il lotto e per tutto ciò che è necessario per una determinata strategia;
  4. Imposta i parametri per le operazioni di trading.

Infine, sarebbe bene verificare se uno stesso simbolo viene utilizzato in più strategie (un esempio per due strategie è fornito di seguito):

//--- Check whether one and the same symbol is used in several strategies
   for(int i=0; i<Strategy_A; i++)
     {
      if(IsTrade_A[i]==false) continue;
      for(int j=0; j<Strategy_B; j++)
        {
         if(IsTrade_B[j]==false) continue;
         if(Symbol_A[i]==Symbol_B[j])
           {
            Print(Symbol_A[i]," is used in several strategies!");
            ExpertRemove();
           }
        }
     }

3. Trading "For" Loop

Il framework di for loop all'interno della funzione OnTimer() è il seguente:

void OnTimer()
  {
//--- Check if the terminal is connected to the trade server
   if(TerminalInfoInteger(TERMINAL_CONNECTED)==false) return;

//--- Section A: Main loop of the FOR operator for strategy A -----------
   for(int A=0; A<Strategy_A; A++)
     {
      //--- A.1: Check whether the symbol is allowed to be traded
      if(IsTrade_A[A]==false)
         continue; // terminate the current FOR iteration

     }

//--- Section В: Main loop of the FOR operator for strategy В -----------
   for(int B=0; B<Strategy_B; B++)
     {
      //--- B.1: Check whether the symbol is allowed to be traded
      if(IsTrade_B[B]==false)
         continue; // terminate the current FOR iteration

     }
  }

Se un Expert Advisor a simbolo singolo basato su una singola strategia ha una condizione in base alla quale tutti i calcoli successivi devono essere interrotti, utilizziamo l'operatore ritorno. Nel nostro caso, dobbiamo solo terminare l'iterazione corrente e procedere all'iterazione successiva del simbolo. A tale scopo, è meglio utilizzare l'operatore continua.

Se si desidera migliorare Expert Advisor multistrate strategico aggiungendo una strategia con un ciclo for che contiene una condizione per la terminazione di tutti i calcoli successivi, è possibile utilizzare il modello seguente:

//--- Section N: Main loop of the FOR operator for strategy N -----------
for(int N=0; N<Strategy_N; N++)
  {

   //...
   bool IsInterrupt=false;
   for(int i=0; i<Number; i++)
     {
      if(...) // terminate all calculations
        {
         IsInterrupt=true;
         break;
        }
     }
   if(IsInterrupt=true)
      continue; // terminate the current FOR iteration
   //...

  }

Dopo aver creato il framework dei for loop, inseriamo semplicemente in esso codici da altri EA e quindi sostituiamo alcune variabili con elementi array.

Ad esempio, cambiamo la variabile predefinita _Symbol in Symbol_A[i] o _Point in Point_A[i]. I valori di queste variabili sono tipici del simbolo dato e sono stati quindi copiati in matrici al momento dell'inizializzazione.

Ad esempio, troviamo il valore dell'indicatore:

 //--- A.3: Lower band of BB calculated based on High prices
 if(CopyBuffer(BB_handle_high_A[A],LOWER_BAND,BBShift_A[A],1,BB_lower_band_high)<=0)
    continue; // terminate the current FOR iteration
 ArraySetAsSeries(BB_lower_band_high,true);

Per implementare la chiusura di una posizione di acquisto, scriveremo il seguente codice:

 //--- A.7.1: Calculate the current Ask and Bid prices
 SymbolInfo.Name(Symbol_A[A]);
 SymbolInfo.RefreshRates();
 double Ask_price=SymbolInfo.Ask();
 double Bid_price=SymbolInfo.Bid();

 if(PositionSelect(Symbol_A[A]))
   {
    //--- A.7.2: Closing a BUY position
    if(PositionInfo.PositionType()==POSITION_TYPE_BUY)
      {
       if(Bid_price>=BB_lower_band_high[0] || DealNumber_A[A]==0)
         {
          if(!Trade_A.PositionClose(Symbol_A[A]))
            {
             Print("Failed to close the Buy ",Symbol_A[A]," position. Code=",Trade_A.ResultRetcode(),
                   " (",Trade_A.ResultRetcodeDescription(),")");
             continue; // terminate the current FOR iteration
            }
          else
            {
             Print("The Buy ",Symbol_A[A]," position closed successfully. Code=",Trade_A.ResultRetcode(),
                   " (",Trade_A.ResultRetcodeDescription(),")");
             continue; // terminate the current FOR iteration
            }
         }
      }

    //...
   }

Apertura di una posizione di acquisto:

 //--- A.9.1: for a Buy
 if(Ask_price<=BB_lower_band_low[0])
   {
    //...

    //--- A.9.1.3: Execute a deal
    if(!Trade_A.Buy(OrderLot,Symbol_A[A]))
      {
       Print("The Buy ",Symbol_A[A]," has been unsuccessful. Code=",Trade_A.ResultRetcode(),
             " (",Trade_A.ResultRetcodeDescription(),")");
       continue; // terminate the current FOR iteration
      }
    else
      {
       Print("The Buy ",Symbol_A[A]," has been successful. Code=",Trade_A.ResultRetcode(),
             " (",Trade_A.ResultRetcodeDescription(),")");
       continue; // terminate the current FOR iteration
      }
   }

Ricordarsi di terminare la generazione di eventi timer ed eliminare le maniglie degli indicatori alla deinitializzazione.


4. Risultati del test

Quando l'Expert Advisor è pronto, testiamo ogni strategia e ogni simbolo separatamente e confrontiamo i risultati del test con quelli ottenuti in modalità test quando negoziamo tutte le strategie e i simboli contemporaneamente.

Si presume che l'utente abbia già identificato i valori ottimali dei parametri di input.


Di seguito sono riportate le impostazioni del tester strategico:

Fig. 2. Impostazioni del tester strategico

Fig. 2. Impostazioni di Strategy Tester

Risultati per la strategia A, EURUSD:

Fig. 3. Risultati dei test per la strategia A, EURUSD

Fig. 3. Risultati dei test per la strategia A, EURUSD

Risultati per la strategia A, GBPUSD:

Fig. 4. Risultati dei test per la strategia A, GBPUSD

Fig. 4. Risultati dei test per la strategia A, GBPUSD

Risultati per la strategia B, AUDUSD:

Fig. 5. Risultati dei test per la strategia В, AUDUSD

Fig. 5. Risultati dei test per la strategia В, AUDUSD

Risultati della strategia B, EURJPY:

Fig. 6. Risultati dei test per la strategia В, EURJPY

Fig. 6. Risultati dei test per la strategia В, EURJPY

Risultati dei test per tutte le strategie e i simboli:

Fig. 7. Risultati dei test per tutte le strategie e i simboli

Fig. 7. Risultati dei test per tutte le strategie e i simboli


Conclusione

Di conseguenza, abbiamo una struttura comoda e semplice di Expert Advisor multi-sistema multi-valuta in cui puoi posizionare praticamente qualsiasi tua strategia.

Tale Expert Advisor ti consente di valutare meglio l'efficienza del trading utilizzando tutte le tue strategie. Può anche rivelarsi utile nel caso in cui un solo Expert Advisor sia autorizzato a lavorare su un determinato account. Il codice sorgente dell'Expert Advisor è allegato all'articolo per facilitare lo studio delle informazioni di cui sopra.


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

File allegati |
2multi_en.mq5 (30.27 KB)
Indicatore per Kagi Charting Indicatore per Kagi Charting
L'articolo presenta l'indicatore grafico Kagi con varie opzioni per la creazione di grafici e funzioni aggiuntive. Inoltre, vengono considerati il principio del grafico dell'indicatore e le sue funzionalità di implementazione MQL5. Vengono visualizzati i casi più popolari della sua implementazione nel trading: strategia di scambio Yin / Yang, allontanandosi dalla linea di tendenza e aumentando costantemente le "spalle" / diminuendo la "vita".
MQL5 Cookbook: Sviluppo di un indicatore di volatilità multi-simbolo in MQL5 MQL5 Cookbook: Sviluppo di un indicatore di volatilità multi-simbolo in MQL5
In questo articolo, considereremo lo sviluppo di un indicatore di volatilità multi-simbolo. Lo sviluppo di indicatori multi-simbolo può presentare alcune difficoltà per gli sviluppatori MQL5 alle prime armi che questo articolo aiuta a chiarire. Le principali questioni che sorgono nel corso dello sviluppo di un indicatore multi-simbolo hanno a che fare con la sincronizzazione dei dati di altri simboli rispetto al simbolo corrente, con la mancanza di alcuni dati indicatori e con l'identificazione dell'inizio di barre "vere" di un determinato intervallo di tempo. Tutti questi problemi saranno attentamente considerati nell'articolo.
Econometrics Previsioni EURUSD One-Step-Ahead Econometrics Previsioni EURUSD One-Step-Ahead
L'articolo si concentra sulla previsione anticipata per EURUSD utilizzando il software EViews e un'ulteriore valutazione dei risultati delle previsioni utilizzando i programmi in EViews. La previsione prevede modelli di regressione e viene valutata tramite un Expert Advisor sviluppato per MetaTrader 4.
Manuale MQL5: Controlli della finestra secondaria degli indicatori - Barra di scorrimento Manuale MQL5: Controlli della finestra secondaria degli indicatori - Barra di scorrimento
Continuiamo ad esplorare i vari controlli e questa volta rivolgiamo la nostra attenzione alla barra di scorrimento. Proprio come nel precedente articolo intitolato "Manuale MQL5: Controlli della finestra secondaria dell'indicatore - Pulsanti", tutte le operazioni verranno eseguite nella finestra secondaria dell'indicatore. Prenditi un momento per leggere l'articolo sopra menzionato in quanto fornisce una descrizione dettagliata dell'utilizzo degli eventi nella funzione OnChartEvent(). Questo argomento verrà solo menzionato in questo articolo. A scopo illustrativo, questa volta creeremo una barra di scorrimento verticale per un ampio elenco di tutte le proprietà degli strumenti finanziari che possono essere ottenute utilizzando le risorse MQL5.