English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Guida Step-By-Step alla scrittura di un Expert Advisor in MQL5 per Principianti

Guida Step-By-Step alla scrittura di un Expert Advisor in MQL5 per Principianti

MetaTrader 5Sistemi di trading | 9 dicembre 2021, 13:35
4 595 0
Samuel Olowoyo
Samuel Olowoyo

Introduzione

Questo articolo è rivolto ai principianti che desiderano imparare a scrivere semplici Expert Advisor nel nuovo linguaggio MQL5. In primo luogo, inizieremo prima stabilendo cosa vogliamo che faccia il nostro EA (Expert advisor), per poi passare a come vogliamo che l'EA lo faccia.


1. Strategia di Trading

Cosa farà il nostro EA:

  • Monitorerà un particolare indicatore e, quando una certa condizione viene soddisfatta (o determinate condizioni sono soddisfatte), piazzerà uno scambio (Short/Sell Long/Buy), a seconda della condizione attuale che è stata soddisfatta.

Ciò che abbiamo descritto sopra viene chiamato strategia di trading. Prima di poter scrivere un EA, è necessario innanzitutto sviluppare la strategia che desideri da automatizzare nell'EA. Quindi, in questo caso, modifichiamo l'affermazione di cui sopra in modo che rifletta la strategia che vogliamo sviluppare in un EA.

  • Useremo un indicatore chiamato Media Mobile con un periodo di 8 (puoi scegliere qualsiasi periodo, ma ai fini della nostra strategia, useremo 8)

  • Vogliamo che il nostro EA effettui un trade Long (Buy) quando la Media Mobile-8 (ai fini della nostra discussione, mi riferirò ad essa come MA-8) sta aumentando verso l'alto e il prezzo è poco al di sopra di questa e posizionerà uno Short (Sell) quando MA-8 sta diminuendo verso il basso e il prezzo è poco al di sotto di essa.
  • Useremo anche un altro indicatore chiamato Movimento direzionale medio (ADX) con il periodo 8 anche per aiutarci a determinare se il mercato è crescita oppure no. Stiamo facendo questo perché vogliamo aprire una posizione solo quando il mercato segue un trend e rilassarci quando il mercato si muove all’interno di un range definito (cioè, non in crescita). Per raggiungere questo obiettivo, piazzeremo il nostro trade (Buy o Sell) solo quando le condizioni di cui sopra sono soddisfatte e il valore ADX è maggiore di 22. Se ADX è maggiore di 22 ma decrescente, o ADX è inferiore a 22, non effettueremo operazioni di trading, anche se la condizione B è stata soddisfatta.
  • Inoltre, vogliamo proteggerci impostando uno Stop loss di 30 pip e per il nostro obiettivo di Profitto; punteremo a un profitto di 100 pip.
  • Vogliamo anche che il nostro EA cerchi opportunità di Acquisto/Vendita solo quando è stata formata una nuova barra e ci assicureremo anche di aprire una posizione di Acquisto se le condizioni di Acquisto sono soddisfatte e non ne abbiamo già una, nonché aprire una posizione di Vendita quando le condizioni di Vendita sono soddisfatte e non ne abbiamo già una aperta.

Ora, abbiamo sviluppato la nostra strategia; adesso è il momento di iniziare a scrivere il nostro codice.


2. Scrivere un Expert Advisor

2.1 MQL5 Wizard

Inizia avviando MetaQuotes Language Editor 5. Quindi premere Ctrl+No cliccare sul pulsante Nuovo nella barra del Menu

Figura 1. Avvio di un nuovo documento MQL5

Figura 1. Avvio di un nuovo documento MQL5

 Nella finestra di MQL5 Wizard, selezionare Expert Advisor e cliccare su "Avanti" come mostrato in Fig. 2:

Figura 2. Selezione del tipo di documento

Figura 2. Selezione del tipo di programma

Nella finestra successiva, digita il Nome che vuoi dare al tuo EA nella casella Nome. In questo caso, ho digitato My_First_EA. Quindi, puoi digitare il tuo nome nella casella Autore e anche l'indirizzo del sito Web o indirizzo e-mail nella casella Link (se ne possiedi uno).

Figura 3. Proprietà generali dell’Expert Advisor

Figura 3. Proprietà generali dell'Expert Advisor

Dal momento che vogliamo essere in grado di cambiare alcuni dei parametri per il nostro EA per vedere quale valore può darci il miglior risultato, li aggiungeremo cliccando sul pulsante "Aggiungi".

Figura 4. Impostazione dei parametri di input EA

Figura 4. Impostazione dei parametri di Input dell’EA

Nel nostro EA, vogliamo essere in grado di sperimentare con i nostri Stop Loss, Take Profit, ADX Period e Impostazioni del Periodo della Media Mobile, quindi le definiremo a questo punto.

Fare doppio click sotto la sezione Nome e digitare il nome del parametro, quindi fare doppio click su Tipo per Selezionare il tipo di dati per il parametro, fare doppio click nella sezione Valore iniziale e digitare il valore iniziale per il parametro.

Una volta fatto, dovresti vedere qualcosa di simile:

Figura 5. Tipi di dati dei parametri di input dell’EA

Figura 5. Tipi di dati dell’ EA parametri di Input dell’EA

Come puoi vedere sopra, ho selezionato il tipo di dati integer (int) per tutti i parametri. Parliamo un po' di tipi di dati.

  • char: Il Il tipochar occupa 1 byte di memoria (8 bit) e consente di esprimere nella notazione binaria 2^8=256 valori. Il tipo di carattere può contenere entrambi i valori positivi e negativi. L'intervallo di valori va da -128 a 127.
  • uchar: L’uchar il tipo integer occupa anche 1 byte di memoria, così come il tipo char, ma a differenza sua uchar è inteso solo per valori positivi. Il valore minimo è zero, il valore massimo è 255. La prima lettera u nel nome del tipouchar è l'abbreviazione diunsigned.
  • short: La dimensione del tiposhort è di 2 byte (16 bit) e, di conseguenza, consente di esprimere l'intervallo di valori pari a 2 alla potenza 16: 2^16 = 65 536. Poiché il tipo short è un segno uno, e contiene sia valori positivi che negativi, l'intervallo di valori è compreso tra -32 768 e 32 767.
  • ushort: Il tipo unsigned short è il tipo ushortche ha anche una dimensione di 2 byte. Il valore minimo è 0, il valore massimo è 65 535.
  • int: La dimensione del tipoint è di 4 byte (32 bit). Il valore minimo è di -2 147 483 648, quello massimo è 2 147 483 647.
  • uint:  Il tipo unsigned integer è uint. Richiede 4 byte di memoria e consente esprimere numeri interi da 0 a 4 294 967 295.
  • long: La dimensione del tipo long è di 8 byte (64 bit). Il valore minimo è -9 223 372 036 854 775 808, il valore massimo è 9 223 372 036 854 775 807.
  • ulong: Il tipoulong occupa anche 8 byte e può memorizzare valori da 0 a 18 446 744 073 709 551 615.

Dalla descrizione precedente dei vari tipi di dati, i tipi integer senza segno non sono progettati per memorizzare valori negativi, qualsiasi tentativo di impostare un valore negativo può portare a conseguenze inaspettate. Ad esempio, se si desidera memorizzare valori negativi, non è possibile memorizzarli all'interno dei tipi unsigned (ad es. uchar, uint, ushort, ulong).

Torniamo al nostro EA. Esaminando i tipi di dati, sarai d'accordo con me sul fatto che supponiamo di utilizzare i tipi di dati char o uchar poiché i dati che intendiamo archiviare in questi parametri sono rispettivamente inferiori a 127   o 255. Per una buona gestione della memoria, questa è la cosa migliore da fare. Tuttavia, ai fini della nostra discussione, ci atterremo ancora d attenerci al tipo int.

Una volta che hai finito di configurare tutti i parametri necessari, cliccare sul pulsante Finito e l'Editor MetaQuotes creerà per te lo scheletro del codice come mostrato nella figura successiva.


Spezziamo il codice nelle varie sezioni per una migliore comprensione.

La parte superiore (Intestazione) del codice è dove viene definita la proprietà dell'EA. Puoi vedere che qui ci sono i valori compilati in MQL5 Wizard nella figura 3. 

In questa sezione del codice, puoi definire parametri aggiuntivi come ladescrizione(breve descrizione testuale dell'EA), dichiarare costanti, includere file aggiuntivi o funzioni di importazione. 


Quando una dichiarazione inizia con un simbolo #, si chiama direttiva del preprocessore e non termina con un punto e virgola ';' un altro esempio di direttive preprocessore include:

#define : 

La direttiva#define viene utilizzata per una dichiarazione delle costanti. È scritto nella forma

#define identificatore token_string

Ciò che questo fa è sostituire ogni occorrenza di identificatore nel codice con il valore token_string.

Esempio:

#define  ABC 100
#define  COMPANY_NAME      "MetaQuotes Software Corp."

Sostituirà ogni occorrenza di COMPANY_NAME con la stringa  "MetaQuotes Software Corp." o sostituirà ogni occorrenza di ABC con il carattere (o intero) 100 nel codice.

Puoi leggere di più sulle direttive del preprocessore nel Manuale MQL5. Continuiamo ora con discussione.

La seconda parte dell'intestazione del nostro codice è la sezione dei parametri di input:

 

Specifichiamo tutti i parametri, che verranno utilizzati nel nostro EA in questa sezione. Questi includono tutte le variabili che verranno utilizzate da tutte le funzioni che scriveremo nel nostro EA.

Le variabili dichiarate a questo livello sono chiamate Variabili Globalipoiché sono accessibili da tutte le funzioni del nostro EA che potrebbero averne bisogno. I parametri di Input sono parametri che possono essere modificati solo al di fuori del nostro EA. Possiamo anche dichiarare altre variabili che gestiremo nel corso del nostro EA ma non saranno disponibili al di fuori del nostro EA in questa sezione. 

La prossima è la funzione di inizializzazione dell’EA. Questa è la prima funzione che viene chiamata quando l'EA viene avviato o associato a un grafico e viene chiamato solo una volta. 


Questa sezione è il luogo migliore per eseguire alcuni controlli importanti per assicurarsi che il nostro EA funzioni alla perfezione.

Possiamo decidere di sapere se il grafico ha abbastanza barre per far funzionare il nostro EA, ecc.

È anche il posto migliore per ottenere gli handle che utilizzeremo per i nostri indicatori (ADX e Indicatori della Media Mobile).

 
 Lafunzione OnDeinitviene chiamata quando l’ EA viene rimosso dal grafico.

Per il nostro EA, rilasceremo gli handle creati per i nostri Indicatori durante l'inizializzazione in questa sezione.


Questa funzione elabora l'evento NewTick, generato quando si riceve una nuova offerta per un simbolo. 

Si noti che l’Expert Advisor non può eseguire operazioni di trading l'uso dell’Expert Advisor nel client terminal non è consentito (Pulsante "Auto Trading").

Figura 6. L’Autotrading è abilitato

Figura 6. L’Autotrading è abilitato

La maggior parte dei nostri codici che implementeranno la nostra la strategia di trading, sviluppata in precedenza, sarà scritta all'interno di questa sezione.

Ora che abbiamo esaminato le varie sezioni del codice per il nostro EA, iniziamo ad aggiungere “carne” allo scheletro.

2.2 SEZIONE PARAMETRI DI INPUT

//--- input parameters
input int      StopLoss=30;      // Stop Loss
input int      TakeProfit=100;   // Take Profit
input int      ADX_Period=8;     // ADX Period
input int      MA_Period=8;      // Moving Average Period
input int      EA_Magic=12345;   // EA Magic Number
input double   Adx_Min=22.0;     // Minimum ADX Value
input double   Lot=0.1;          // Lots to Trade
//--- Other parameters
int adxHandle; // handle for our ADX indicator
int maHandle;  // handle for our Moving Average indicator
double plsDI[],minDI[],adxVal[]; // Dynamic arrays to hold the values of +DI, -DI and ADX values for each bars
double maVal[]; // Dynamic array to hold the values of Moving Average for each bars
double p_close; // Variable to store the close value of a bar
int STP, TKP;   // To be used for Stop Loss & Take Profit values

Come puoi vedere, abbiamo aggiunto più parametri. Prima di continuare a parlare dei nuovi parametri, trattiamo qualcosa che puoi vedere ora. I due forward slash '//' ci permettono di inserire commenti nei nostri codici. Con i commenti, siamo in grado di sapere cosa rappresentano le nostre variabili o cosa stiamo facendo in quel momento nel nostro codice. Esso offre anche una migliore comprensione del nostro codice. Esistono due modi fondamentali per scrivere i commenti:

// Altri parametri ...

Questo è un commento di una sola riga

/*

  Questo è un commento su più righe

*/

Questo è un commento su più righe. I commenti multi-riga iniziano con la coppia di simboli /* e termina con quella */ .

Il compilatore ignora tutti i commenti mentre compila il tuo codice.

Utilizzo di commenti a riga singola per i parametri di input è un buon modo per far capire ai nostri utenti EA cosa rappresentano questi parametri. Nelle proprietà di Input EA, i nostri utenti non vedranno il parametro stesso, bensì i commenti come mostrato di seguito:

Figura 7. Parametri di input di Expert AdvisorAdvisor

Figura 7. Parametri di input di Expert Advisor

Ora, torniamo al nostro codice...

Abbiamo deciso di aggiungere ulteriori parametri per il nostro EA. L’ EA_Magic è il numero magico per tutti gli ordini del nostro EA.  Il valore ADX minimo (Adx_Min) è dichiarato come undoppio tipo di dati. Un tipodoppio viene utilizzato per memorizzare i floating point costanti che contengono una parte intera, un punto decimale e una parte frazione.

Esempio:

doppio mysum = 123,5678;

doppio b7 = 0,09876;

Il Lotto da per fare trading (Lotto) rappresenta il volume dello strumento finanziario con cui vogliamo operare. Quindi abbiamo dichiarato altri parametri che utilizzeremo:

L’ adxHandle deve essere utilizzato per memorizzare l'handle dell'indicatore ADX, mentre maHandle memorizzerà l'handle per il Indicatore della Media Mobile. I plsDI[], minDI[], adxVal[] sono array dinamici che conterranno i valori di +DI, -DI e ADX principale (dell'Indicatore ADX ) per ogni barra del grafico. Il maVal[] è un array dinamico che contiene i valori dell’Indicatore della Media mobile per ogni barra del grafico.

A proposito, cosa sono gli array dinamici? Un array dinamico è una array dichiarata senza una dimensione. In altre parole, nessun valore è specificato nella coppia di parentesi quadre. Un array statico statica, invece, ha le sue dimensioni definite nel punto di dichiarazione.

Esempio:

doppio allbars[20]; Ci vorranno 20 elementi

p_close è una variabile che useremo per memorizzare il Prezzo di chiusura per la barra che monitoreremo per il controllo dei nostri trade Buy/Sell.

STPe TKP verranno utilizzati per memorizzare i valori Stop Loss e Take Profit nel nostro EA.

2.3. SEZIONE INIZIALIZZAZIONE EA

int OnInit()
  {
//--- Get handle for ADX indicator
   adxHandle=iADX(NULL,0,ADX_Period);
//--- Get the handle for Moving Average indicator
   maHandle=iMA(_Symbol,_Period,MA_Period,0,MODE_EMA,PRICE_CLOSE);
//--- What if handle returns Invalid Handle
   if(adxHandle<0 || maHandle<0)
     {
      Alert("Error Creating Handles for indicators - error: ",GetLastError(),"!!");
     }

Qui otteniamo gli handle del nostro indicatore utilizzando le rispettive funzioni dell’ indicatore.

L’ handle dell’indicatore ADX viene ottenuto utilizzando la funzione iADX. Prende Il simbolo del grafico (NULL indica anche il simbolo corrente sul grafico corrente), il grafico periodo/timeframe (0 indica anche il timeframe corrente sul grafico corrente), il periodo di media ADX per calcolare l’indice (che abbiamo definito in precedenza con nella sezione parametri di input) come parametri o argomenti.  

int  iADX(
   string           symbol,         // symbol name
   ENUM_TIMEFRAMES  period,         // period
   int              adx_period      // averaging period
   );

L'handle dell'indicatore della Media Mobile viene ottenuto utilizzando la funzione iMA. Ha i seguenti argomenti:

  • il simbolo del grafico (che può essere ottenuto utilizzando _symbol, symbol() o NULL per il simbolo corrente sul grafico corrente),
  • ilperiod/timeframe del grafico (che può essere ottenuto utilizzando _period, period(), o 0 per l’attuale timeframe del grafico corrente),
  • ilperiodo di media mobile (che abbiamo definito in precedenza nella sezione parametri di input),
  • lo spostamento dell'indicatore relativo al grafico dei prezzi (lo spostamento qui è 0),
  • il tipo di adattamento della media mobile (potrebbe essere uno dei seguenti tipi di media: MODE_SMA media semplice, media esponenziale MODE_EMA, MODE_SMMA media adattiva o media ponderata lineare-MODE_LWMA), e
  • il prezzo utilizzato per la media (qui usiamo il prezzo di chiusura).

int  iMA(
   string               symbol,            // symbol name
   ENUM_TIMEFRAMES      period,            // period
   int                  ma_period,         // averaging period
   int                  ma_shift,          // horizontal shift
   ENUM_MA_METHOD       ma_method,         // smoothing type
   ENUM_APPLIED_PRICE   applied_price      // type of price or handle
   );

Ti invitiamo a leggere il manuale MQL5 per ottenere ulteriori dettagli su queste funzioni dell’indicatore. Ciò ti offrirà una migliore comprensione sull’utilizzo di ciascun indicatore.

Proviamo nuovamente a controllare eventuali errori; nel caso in cui la funzione non abbia restituito l’handle con successo, otterremo un errore INVALID_HANDLE. Usiamo la funzione di avviso per visualizzare l'errore utilizzando la funzione GetlastError.

//--- Let us handle currency pairs with 5 or 3 digit prices instead of 4
   STP = StopLoss;
   TKP = TakeProfit;
   if(_Digits==5 || _Digits==3)
     {
      STP = STP*10;
      TKP = TKP*10;
     }

Decidiamo di memorizzare i valori Stop Loss e i Profit nelle variabili STP e TKP che abbiamo dichiarato in precedenza. Perché stiamo facendo questo?

Perché i valori memorizzati nei parametri INPUT sono di sola lettura, non possono essere modificati. Quindi, qui vogliamo assicurarci che il nostro EA funzioni bene con tutti i broker. Digits o Digits() restituisce il numero di cifre decimali determinando l'accuratezza del prezzo del simbolo del grafico corrente. Per un grafico dei prezzi a 5 o 3 cifre, moltiplichiamo sia lo Stop Loss che il Take Profit per 10.

2.4. SEZIONE REINIZIALIZZAZIONE EA

 

Poiché questa funzione viene chiamata ogni volta che l'EA viene disabilitato o rimosso da un grafico, rilasceremo qui tutti gli indicatori handle creati durante il processo di inizializzazione. Abbiamo creato due handle, uno per l'indicatore ADX e un altro handle per l’indicatore della Media Mobile.

Useremo la funzione IndicatorRelease() per eseguire questa operazione. Ci vuole un solo argomento (l’handle dell'indicatore)

bool  IndicatorRelease(
   int       indicator_handle,     // indicator handle
   );

La funzione rimuove un handle dell’indicatore e rilascia il blocco di calcolo dell'indicatore, se non è stato utilizzato.

2.5 LA SEZIONE EA ONTICK

La prima cosa che dobbiamo fare qui è verificare se abbiamo abbastanza barre sul grafico corrente. Possiamo ottenere le barre totali nella cronologia di qualsiasi grafico che utilizza la funzione Barre. Ci vogliono due parametri, il simbolo (può essere ottenuto utilizzando _Symbol o Symbol(). Questi due restituiscono il simbolo corrente per il grafico corrente a cui è associato il nostro EA) e il periodo o timeframe del grafico presente (può essere ottenuto utilizzando Period o Period(). Questi due restituiranno il timeframe del grafico corrente a cui è associato l'EA).

Se il totale delle barre disponibili è inferiore a 60, vogliamo che il nostro EA si “rilassi” fino a quando non avremo abbastanza barre disponibili sul grafico.  La funzione Alert mostra un messaggio in una finestra separata. Prende qualsiasi valore separato da virgole come parametri/argomenti. In questo caso, abbiamo un solo valore della stringa. Il ritorno esce dall'inizializzazione del nostro EA.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
// Do we have enough bars to work with
   if(Bars(_Symbol,_Period)<60) // if total bars is less than 60 bars
     {
      Alert("We have less than 60 bars, EA will now exit!!");
      return;
     }
// We will use the static Old_Time variable to serve the bar time.
// At each OnTick execution we will check the current bar time with the saved one.
// If the bar time isn't equal to the saved time, it indicates that we have a new tick.
   static datetime Old_Time;
   datetime New_Time[1];
   bool IsNewBar=false;

// copying the last bar time to the element New_Time[0]
   int copied=CopyTime(_Symbol,_Period,0,1,New_Time);
   if(copied>0) // ok, the data has been copied successfully
     {
      if(Old_Time!=New_Time[0]) // if old time isn't equal to new bar time
        {
         IsNewBar=true;   // if it isn't a first call, the new bar has appeared
         if(MQL5InfoInteger(MQL5_DEBUGGING)) Print("We have new bar here ",New_Time[0]," old time was ",Old_Time);
         Old_Time=New_Time[0];            // saving bar time
        }
     }
   else
     {
      Alert("Error in copying historical times data, error =",GetLastError());
      ResetLastError();
      return;
     }

//--- EA should only check for new trade if we have a new bar
   if(IsNewBar==false)
     {
      return;
     }
 
//--- Do we have enough bars to work with
   int Mybars=Bars(_Symbol,_Period);
   if(Mybars<60) // if total bars is less than 60 bars
     {
      Alert("We have less than 60 bars, EA will now exit!!");
      return;
     }

//--- Define some MQL5 Structures we will use for our trade
   MqlTick latest_price;     // To be used for getting recent/latest price quotes
   MqlTradeRequest mrequest;  // To be used for sending our trade requests
   MqlTradeResult mresult;    // To be used to get our trade results
   MqlRates mrate[];         // To be used to store the prices, volumes and spread of each bar
   ZeroMemory(mrequest);     // Initialization of mrequest structure

L'Expert Advisor eseguirà operazioni di trading all'inizio di una nuova barra, quindi è necessario risolvere il problema con la nuova identificazione della barra. In altre parole, vogliamo essere sicuri che il nostro EA non controlli le impostazioni Long/Short su ogni tick, vogliamo solo che il nostro EA controlli le posizioni Long/Short quando c'è una nuova barra. 

Iniziamo dichiarando una variabile datetime staticaOld_Time, che memorizzerà il Bar time. La abbiamo definita statica poiché vogliamo che il valore venga mantenuto in memoria fino alla chiamata successiva della funzione OnTick. Quindi saremo in grado di confrontare il suo valore con la variabile New_Time (anche del tipo di dati datetime), che è un array di un elemento che contiene il nuovo (corrente) bar time. Abbiamo anche dichiarato una variabile di dati di tipo bool IsNewBar e ne abbiamo impostato il valore su false. Ciò, perché vogliamo che il suo valore sia VERO solo quando abbiamo una nuova barra.

Usiamo la funzione CopyTime per ottenere l'ora della barra corrente. Copia il bar time nell’array  New_Time con un elemento; se ha esito positivo, confrontiamo l'ora di una nuova barra con l'ora della barra precedente. Se i tempi non coincidono, significa che abbiamo una nuova barra e impostiamo la variabile IsNewBar su TRUE e salviamo il valore della bar time corrente sulla variabile Old_Time.

La variabile IsNewBar indica che abbiamo una nuova barra. Se è FALSO, terminiamo l'esecuzione della funzione OnTick.  

Dai un'occhiata al codice

if(MQL5InfoInteger(MQL5_DEBUGGING)) Print("We have new bar here ",New_Time[0]," old time was ",Old_Time);

esso controlla l'esecuzione della modalità di debug, stamperà il messaggio sul bar time nella modalità di debug, lo considereremo in seguito.

La prossima cosa che vogliamo fare qui è verificare se abbiamo abbastanza barre con cui lavorare. Perché ripeterlo? Vogliamo solo essere sicuri che il nostro EA funzioni correttamente. Va notato che mentre la funzione OnInit viene chiamata solo una volta quando l'EA è associato ad un grafico, la funzione OnTick viene chiamata ogni volta che c'è un nuovo tick (quotazione del prezzo).

Sicuramente, hai notato che lo abbiamo fatto di nuovo in modo diverso qui. Decidiamo di memorizzare i bar totali nella cronologia che abbiamo ottenuto dall'espressione

int Mybars=Bars(_Symbol,_Period);

in una nuova variabile, Mybars, dichiarata all'interno della funzione OnTick. Questo tipo di variabile è una variabile locale, a differenza della variabile che abbiamo dichiarato nella sezione PARAMETRI DI INPUT del nostro codice. Mentre le variabili, dichiarate nella sezione Parametri di input del nostro codice, sono disponibili per tutte le funzioni, all'interno del nostro codice che potrebbe averne bisogno, le variabili dichiarate all'interno di un  la singola funzione sono limitate e disponibili solo per quella funzione. Non può essere utilizzato al di fuori di questa funzione.

Successivamente, abbiamo dichiarato alcune variabili tipi struttura MQL5 che verranno utilizzati in questa sezione del nostro EA. MQL5 ha un certo numero di Strutture integrate che rende le cose abbastanza facili per gli sviluppatori EA. Prendiamo le Strutture una dopo l'altra.

MqlTick

Questa è una struttura utilizzata per memorizzare gli ultimi prezzi dei simboli.

struct MqlTick
  {
   datetime     time ; //Time of the last prices update
   double       bid;          //Current Bid price
   double       ask;           //Current Ask price
   double       last;) // Price of the last deal (Last)
   ulong        volume;        // Volume for the current Last price
  };

Qualsiasi variabile dichiarata di tipo MqlTick può essere facilmente utilizzata per ottenere i valori correnti di Ask, Bid, Last e Volume una volta chiamata la funzione SymbolInfoTick().

Così abbiamo dichiarato latest_price come tipo MqlTick in modo da poterlo utilizzare per ottenere i prezzi Ask e Bid

MqlTradeRequest

Questa struttura viene utilizzata per eseguire tutte le richieste di trading per un'operazione di trading. Contiene, nella sua struttura, tutti i campi necessari per l'esecuzione di una transazione di trading.

struct MqlTradeRequest
  {
   ENUM_TRADE_REQUEST_ACTIONS    action;       // Trade operation type
   ulong                         magic;        // Expert Advisor ID (magic number)
   ulong                         order;        // Order ticket
   string                        symbol;       // Trade symbol
   double                        volume;       // Requested volume for a deal in lots
   double                        price;        // Price
   double                        stoplimit;    // StopLimit level of the order
   double                        sl;           // Stop Loss level of the order
   double                        tp;           // Take Profit level of the order
   ulong                         deviation;    // Maximal possible deviation from the requested price
   ENUM_ORDER_TYPE               type;          // Order type
   ENUM_ORDER_TYPE_FILLING       type_filling;  // Order execution type
   ENUM_ORDER_TYPE_TIME          type_time;     // Order execution time
   datetime                      expiration;    // Order expiration time (for the orders of ORDER_TIME_SPECIFIED type)
   string                        comment;       // Order comment
  };

Qualsiasi variabile dichiarata di tipo MqlTradeRequest può essere utilizzata per inviare ordini per le nostre operazioni di trading. Qui abbiamo dichiarato mrequest come un tipo MqlTradeRequest.

MqlTradeResult

Il risultato di qualsiasi operazione di trading viene restituito come una speciale struttura predefinita di tipo MqlTradeResult. Qualsiasi variabile dichiarata di tipo MqlTradeResult sarà in grado di accedere ai risultati della richiesta di trading.

struct MqlTradeResult
  {
   uint     retcode;          // Operation return code
   ulong    deal;             // Deal ticket, if it is performed
   ulong    order;            // Order ticket, if it is placed
   double   volume;           // Deal volume, confirmed by broker
   double   price;            // Deal price, confirmed by broker
   double   bid;              // Current Bid price
   double   ask;              // Current Ask price
   string   comment;          // Broker comment to operation (by default it is filled by the operation description)
  };

Qui abbiamo dichiarato mresult come un tipo MqlTradeResult.

MqlRates

Il Prezzo (di Apertura, di Chiusura, Alto, Basso), il Tempo, i Volumi di ogni barra e lo spread per un simbolo viene memorizzato in questa struttura. Qualsiasi array dichiarato di tipo MqlRates può essere utilizzato per memorizzare la cronologia del prezzo, dei volumi dello spread per un simbolo.

struct MqlRates
  {
   datetime time;         // Period start time
   double   open;         // Open price
   double   high;         // The highest price of the period
   double   low;          // The lowest price of the period
   double   close;        // Close price
   long     tick_volume;  // Tick volume
   int      spread;       // Spread
   long     real_volume;  // Trade volume
  };

Qui abbiamo dichiarato un array mrate[] che verrà utilizzato per memorizzare queste informazioni.

/*
     Let's make sure our arrays values for the Rates, ADX Values and MA values 
     is store serially similar to the timeseries array
*/
// the rates arrays
   ArraySetAsSeries(mrate,true);
// the ADX DI+values array
   ArraySetAsSeries(plsDI,true);
// the ADX DI-values array
   ArraySetAsSeries(minDI,true);
// the ADX values arrays
   ArraySetAsSeries(adxVal,true);
// the MA-8 values arrays
   ArraySetAsSeries(maVal,true);

Successivamente, decidiamo di impostare tutti gli array che utilizzeremo per memorizzare i dettagli delle Barre come serie. Questo è per garantire che i valori che verranno copiati negli array vengano indicizzati come la timeserie, cioè 0, 1, 2, 3, (per corrispondere all'indice delle barre. Quindi, noi utilizziamo la funzione ArraySetAsSeries().

bool  ArraySetAsSeries(
   
void  array[],     // array by reference
   bool  set          // true denotes reverse order of indexing
   );

Si dovrebbe notare che ciò può essere fatto anche una volta nella sezione inizializzazione del nostro codice. Tuttavia, ho deciso di mostrarlo a questo punto ai fini della nostra spiegazione.

//--- Get the last price quote using the MQL5 MqlTick Structure
   if(!SymbolInfoTick(_Symbol,latest_price))
     {
      Alert("Error getting the latest price quote - error:",GetLastError(),"!!");
      return;
     }

Ora utilizziamo la funzione SymbolInfoTick per ottenere l'ultima quotazione del prezzo. Questa la funzione accetta due argomenti: il simbolodel grafico e lavariabile di struttura MqlTick (latest_price). Ancora una volta, se c'è un errore, lo segnaliamo.

//--- Get the details of the latest 3 bars
   if(CopyRates(_Symbol,_Period,0,3,mrate)<0)
     {
      Alert("Error copying rates/history data - error:",GetLastError(),"!!");
      return;
     }

Successivamente, abbiamo copiato le informazioni sulle ultime tre barre nel nostro array di tipi Mqlrates utilizzando la funzione CopyRates. La funzione CopyRates viene utilizzata per ottenere la cronologia dati della struttura MqlRates di un Simbolo-Periodo specificato in quantità specificata in un array di tipo MqlRates. 

int  CopyRates(
   string           symbol_name,       // symbol name
   ENUM_TIMEFRAMES  timeframe,         // period
   int              start_pos,         // start position
   int              count,             // data count to copy
   MqlRates         rates_array[]      // target array to copy
   );

Il nome del simbolo si ottiene utilizzando ‘_symbol’, the current period/timeframe is obtained by using ‘_period’. Per la posizione di partenza, partiremo dalla barra corrente, Barra 0 e conteremo solo tre Barre, Barre 0, 1 e 2. Il risultato sarà memorizzato nel nostro array, mrate[].

L’array mrate[] ora contiene tutte le informazioni su prezzo, tempo, volumi e spread per le barre 0, 1 e 2.  Pertanto, per ottenere i dettagli di qualsiasi barra, utilizzeremo quanto segue:

mrate[bar_number].bar_property

Ad esempio, possiamo avere le seguenti informazioni su ogni barra:

mrate[1].time   // Bar 1 Start time
mrate[1].open   // Bar 1 Open price
mrate[0].high   // Bar 0 (current bar) high price, etc

Successivamente, abbiamo copiato tutti i valori dell'indicatore negli array dinamici che abbiamo dichiarato utilizzando la funzione CopyBuffer.

int  CopyBuffer(
   int       indicator_handle,     // indicator handle
   int       buffer_num,           // indicator buffer number
   int       start_pos,            // start position
   int       count,                // amount to copy
   double    buffer[]              // target array to copy
   );

L’handle dell’indicatore è l’handle che abbiamo creato nella sezione OnInit. Riguardo ai numeri di buffer, l'indicatore ADX ha tre (3) buffer:

  • 0 - MAIN_LINE,
  • 1 - PLUSDI_LINE,
  • 2 - MINUSDI_LINE.

L’ indicatore della Media Mobile ha un solo (1) buffer:

  • 0 – MAIN_LINE.

Copiamo dalla barra presente (0) alle ultime due barre. Quindi, la quantità di record da copiare è 3 (barre 0, 1 e 2). Il buffer[] è l'array dinamico di destinazione che avevamo precedentemente dichiarato – adxVal, plsDI, minDI and maVal.

Come puoi vedere, anche in questo caso, proviamo a rilevare qualsiasi errore che possa verificarsi nel processo di copiatura. Se c'è un errore, non c'è bisogno di andare oltre.

È importante notare che la funzione CopyBuffer() e la funzione CopyRates() restituiscono il numero totale di record copiati in caso di esito positivo mentre restituiscono -1 in caso di errore. Ecco perché stiamo controllando qui un valore inferiore a 0 (zero) nelle funzioni di controllo dell’errore.

//--- Copy the new values of our indicators to buffers (arrays) using the handle
   if(CopyBuffer(adxHandle,0,0,3,adxVal)<0 || CopyBuffer(adxHandle,1,0,3,plsDI)<0
      || CopyBuffer(adxHandle,2,0,3,minDI)<0)
     {
      Alert("Error copying ADX indicator Buffers - error:",GetLastError(),"!!");
      return;
     }
   if(CopyBuffer(maHandle,0,0,3,maVal)<0)
     {
      Alert("Error copying Moving Average indicator buffer - error:",GetLastError());
      return;
     }

A questo punto vogliamo verificare se abbiamo già una posizione Buy or Sell aperta, in altre parole, vogliamo assicurarci di avere solo UN trade Sell o Buy aperto alla volta. Non vogliamo aprire un nuovo Buy se ne abbiamo già uno e non vogliamo aprire un nuovo Sell se ne abbiamo già uno aperto.

Per raggiungere questo obiettivo dichiareremo prima di tutto due variabili di tipo di dati bool (Buy_opened e Sell_opened) che conterranno un un valore TRUE se abbiamo già una posizione aperta per Buy o Sell.

//--- we have no errors, so continue
//--- Do we have positions opened already?
    bool Buy_opened=false;  // variable to hold the result of Buy opened position
    bool Sell_opened=false; // variable to hold the result of Sell opened position
    
    if (PositionSelect(_Symbol) ==true)  // we have an opened position
    {
         if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
         {
            Buy_opened = true;  //It is a Buy
         }
         else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
         {
            Sell_opened = true; // It is a Sell
         }
    }

Usiamo la funzione di trading PositionSelect per sapere se abbiamo una posizione aperta. Questa funzione restituisce TRUE se abbiamo già una posizione aperta e FALSE se non ne abbiamo nessuna.

bool  PositionSelect(
   string  symbol      // Symbol name 
 );

Prende, come argomento/parametro principale, il simbolo (coppia di valute) che vogliamo controllare. Qui, usiamo _symbol perché stiamo controllando il simbolo corrente (coppia di valute).

Se questa espressione restituisce TRUE, allora vogliamo verificare se la posizione aperta è un Buy o un Sell. Usiamo la funzione PositionGetInteger proprio a tale scopo. Essa ci dà il tipo di posizione aperta quando la usiamo con il modificatore POSITION_TYPE. Restituisce l'identificatore del tipo di Posizione che può essere  POSITION_TYPE_BUY o POSITION_TYPE_SELL

long  PositionGetInteger(
   ENUM_POSITION_PROPERTY  property_id      // Property identifier
   );

Nel nostro caso, l'abbiamo utilizzato per determinare quale delle posizioni abbiamo già aperto. Se si tratta di un Sell, memorizziamo un valore TRUE in Sell_opened e se si tratta di un Buy, memorizziamo un valore TRUE in Buy_opened. Saremo in grado di utilizzare queste due variabili in un secondo momento, quando controlleremo le condizioni per Sell o Buy più avanti nel nostro codice.

Ora è il momento di memorizzare il prezzo di chiusura per la barra che utilizzeremo per la nostra configurazione Buy/Sell. Ricorda che abbiamo dichiarato una variabile per quello precedente

// Copy the bar close price for the previous bar prior to the current bar, that is Bar 1

   p_close=mrate[1].close;  // bar 1 close price

Fatto questo, procederemo ora alla fase successiva.

/*
    1. Check for a long/Buy Setup : MA-8 increasing upwards, 
    previous price close above it, ADX > 22, +DI > -DI
*/
//--- Declare bool type variables to hold our Buy Conditions
   bool Buy_Condition_1 = (maVal[0]>maVal[1]) && (maVal[1]>maVal[2]); // MA-8 Increasing upwards
   bool Buy_Condition_2 = (p_close > maVal[1]);         // previuos price closed above MA-8
   bool Buy_Condition_3 = (adxVal[0]>Adx_Min);          // Current ADX value greater than minimum value (22)
   bool Buy_Condition_4 = (plsDI[0]>minDI[0]);          // +DI greater than -DI

//--- Putting all together   
   if(Buy_Condition_1 && Buy_Condition_2)
     {
      if(Buy_Condition_3 && Buy_Condition_4)
        {
         // any opened Buy position?
         if (Buy_opened) 
         {
            Alert("We already have a Buy Position!!!"); 
            return;    // Don't open a new Buy Position
         }
         mrequest.action = TRADE_ACTION_DEAL;                                // immediate order execution
         mrequest.price = NormalizeDouble(latest_price.ask,_Digits);          // latest ask price
         mrequest.sl = NormalizeDouble(latest_price.ask - STP*_Point,_Digits); // Stop Loss
         mrequest.tp = NormalizeDouble(latest_price.ask + TKP*_Point,_Digits); // Take Profit
         mrequest.symbol = _Symbol;                                         // currency pair
         mrequest.volume = Lot;                                            // number of lots to trade
         mrequest.magic = EA_Magic;                                        // Order Magic Number
         mrequest.type = ORDER_TYPE_BUY;                                     // Buy Order
         mrequest.type_filling = ORDER_FILLING_FOK;                          // Order execution type
         mrequest.deviation=100;                                            // Deviation from current price
         //--- send order
         OrderSend(mrequest,mresult);

Ora è il momento di iniziare a controllare un’ opportunità di Acquisto.

Analizziamo l'espressione sopra in quanto rappresenta la strategia che abbiamo progettato in precedenza. Stiamo dichiarando una variabile di tipo bool per ciascuna delle nostre condizioni che deve essere soddisfatta prima che un ordine possa essere effettuato. Una variabile di tipo bool può contenere solo TRUE o FALSE. Quindi, la nostra strategia di Acquisto è stata suddivisa in quattro condizioni.  Se una qualsiasi delle condizioni viene rispettata o soddisfatta, un valore TRUE viene memorizzato nella nostra variabile di tipo bool, altrimenti verrà memorizzato un valore FALSE. Analizziamoli uno per uno.

bool Buy_Condition_1 = (maVal[0]>maVal[1]) && (maVal[1]>maVal[2]);

Qui, stiamo considerando i valori MA-8 sulle Barre 0, 1 e 2. Se il valore di MA-8 sulla barra corrente è maggiore del suo valore sulla Barra 1 precedente e anche il valore MA-8 sulla Barra 1 è maggiore del suo valore sulla Barra 2, significa che MA-8 sta aumentando verso l'alto. Ciò soddisfa una delle nostre condizioni per una configurazione Buy.

bool Buy_Condition_2 = (p_close > maVal[1]); 

Questa espressione sta verificando se il prezzo di Chiusura Barra 1 è superiore al valore di MA-8 nello stesso periodo (periodo Barra 1). Se il prezzo è più alto, allora anche la nostra seconda condizione è stata soddisfatta; quindi possiamo controllare altre condizioni. Tuttavia, se le due condizioni che abbiamo appena analizzato non fossero state soddisfatte, allora non sarebbe stato necessario verificare altre condizioni. Ecco perché decidiamo di includere la prossima espressione all'interno di queste due condizioni iniziali (espressioni).

bool Buy_Condition_3 = (adxVal[0]>Adx_Min);

Ora vogliamo verificare se il valore corrente di ADX (valore ADX sulla Barra 0) è maggiore del valore ADX Minimo dichiarato nei Parametri di input Se questa espressione è vera, cioè, il valore corrente di ADX è maggiore del valore Minimo richiesto; vogliamo anche essere sicuri che il valore plusDI sia è maggiore del valore minusDI . Questo è ciò che abbiamo ottenuto nella successiva espressione

bool Buy_Condition_4 = (plsDI[0]>minDI[0]);

Se tutte queste condizioni sono soddisfatte, cioè se risultano vere, allora vogliamo essere sicuri di non aprire una nuova posizione Buy se ne abbiamo già una. Ora è il momento di controllare il valore della variabile Buy_opened che abbiamo dichiarato in precedenza nel nostro codice.

// any opened Buy position?
if (Buy_opened) 
   {
      Alert("We already have a Buy Position!!!"); 
      return;    // Don't open a new Buy Position
   }

Se Buy_opened risulta vera, non vogliamo aprire un'altra posizione Buy.Quindi, mostriamo un avviso per informarci e, dunque, in modo che ora il nostro EA attenda il prossimo Tick. Tuttavia, se Buy_opened è FALSE, prepariamo i nostri record utilizzando la variabile di tipo MqlTradeRequest (mrequest) che abbiamo dichiarato in precedenza per inviare il nostro ordine.

  • L’ azione  qui, che è il tipo di operazione di trading, è TRADE_ACTION_DEAL perché stiamo effettuando un ordine di trading per la sua esecuzione immediata. Se stiamo modificando un ordine, allora utilizzeremo TRADE_ACTION_MODIFY. Per eliminare un ordine useremo TRADE_ACTION_REMOVE.  Abbiamo usato il nostro tipo MqlTick latest_price per ottenere l’ ultimo prezzoAsk .  Il prezzo di Stop loss dell’ordine si ottiene sottraendo il nostro StopLoss in punti dal prezzo Ask mentre il prezzo take profit dell'ordine si ottiene aggiungendo il nostro TakeProfit in punti al prezzo Ask. Noterai anche che abbiamo utilizzato la funzione NormalizeDouble per il prezzo Ask, i valori StopLoss e TakeProfit; è buona norma normalizzare sempre questi prezzi al numero di cifre della coppia di valute prima di inviarlo al server di trading.
  • Il simbolo  è il simbolo corrente (_Symbol o Symbol()). Il tipo di ordine è il tipo di ordine che stiamo effettuando; qui stiamo effettuando un ordine di acquisto ORDER_TYPE_BUY. Per un ordine Sell, ci sarà ORDER_TYPE_SELL.
  • Iltype_filling dell'ordine è il tipo di esecuzione dell'ordine; ORDER_FILLING_FOK significa che la transazione può essere effettuate esclusivamente con un volume specificato a parità di prezzo o a un prezzo migliore del prezzo specificato dall'ordine. Se non c'è abbastanza volume di offerte sul simbolo dell'ordine, l'ordine non verrà eseguito.

La funzione OrderSend() accetta due argomenti, il tipo MqlTradeRequest e la variabile di tipo MqlTradeResult.

bool  OrderSend(
   MqlTradeRequest&  request      // query structure
   MqlTradeResult&   result       // structure of the answer
   );

Come puoi vedere, abbiamo usato la nostra variabile di tipo MqlTradeRequest e la variabile di tipo MqlTradeResult nell'effettuare il nostro ordine utilizzando OrderSend.

         // get the result code
         if(mresult.retcode==10009 || mresult.retcode==10008) //Request is completed or order placed
           {
            Alert("A Buy order has been successfully placed with Ticket#:",mresult.order,"!!");
           }
         else
           {
            Alert("The Buy order request could not be completed -error:",GetLastError());
            ResetLastError();           
            return;
           }

Dopo aver inviato il nostro ordine, ora useremo la variabile di tipo MqlTradeResult per controllare il risultato del nostro ordine. Se il nostro ordine viene effettuato con successo, vogliamo essere informati e se non lo è, vogliamo saperlo ugualmente. Con la variabile di tipo MqlTradeResult 'mresult' possiamo accedere al codice di ritorno dell'Operazione e anche il numero di ticket dell’ordine se l'ordine viene effettuato.

Il codice di ritorno 10009 mostra che la richiesta OrderSend è stata completata con successo, mentre 10008 mostra che il nostro ordine è stato effettuato. Questo è il motivo per cui abbiamo controllato per uno qualsiasi dei questi due codici restituiti. Se ne abbiamo uno, siamo sicuri che il nostro ordine è stato completato o è stato effettuato.

Per controllare un'Opportunità di Vendita, controlliamo l'opposto di quello che abbiamo fatto per l'Opportunità Acquisto, ad eccezione del nostro ADX che deve essere maggiore del valore Minimo specificato.

/*
    2. Check for a Short/Sell Setup : MA-8 decreasing downwards, 
    previous price close below it, ADX > 22, -DI > +DI
*/
//--- Declare bool type variables to hold our Sell Conditions
   bool Sell_Condition_1 = (maVal[0]<maVal[1]) && (maVal[1]<maVal[2]);  // MA-8 decreasing downwards
   bool Sell_Condition_2 = (p_close <maVal[1]);                         // Previous price closed below MA-8
   bool Sell_Condition_3 = (adxVal[0]>Adx_Min);                         // Current ADX value greater than minimum (22)
   bool Sell_Condition_4 = (plsDI[0]<minDI[0]);                         // -DI greater than +DI
   
 //--- Putting all together
   if(Sell_Condition_1 && Sell_Condition_2)
       {
         if(Sell_Condition_3 && Sell_Condition_4)
           {
            // any opened Sell position?
            if (Sell_opened) 
            {
                Alert("We already have a Sell position!!!"); 
                return;    // Don't open a new Sell Position
            }
            mrequest.action = TRADE_ACTION_DEAL;                                 // immediate order execution
            mrequest.price = NormalizeDouble(latest_price.bid,_Digits);          // latest Bid price
            mrequest.sl = NormalizeDouble(latest_price.bid + STP*_Point,_Digits); // Stop Loss
            mrequest.tp = NormalizeDouble(latest_price.bid - TKP*_Point,_Digits); // Take Profit
            mrequest.symbol = _Symbol;                                         // currency pair
            mrequest.volume = Lot;                                            // number of lots to trade
            mrequest.magic = EA_Magic;                                        // Order Magic Number
            mrequest.type= ORDER_TYPE_SELL;                                     // Sell Order
            mrequest.type_filling = ORDER_FILLING_FOK;                          // Order execution type
            mrequest.deviation=100;                                           // Deviation from current price
            //--- send order
            OrderSend(mrequest,mresult);

Proprio come abbiamo fatto nella sezione di acquisto, stiamo dichiarando una variabile di tipo bool per ciascuna delle nostre condizioni che deve essere soddisfatta prima che un ordine possa essere effettuato. Una variabile di tipo bool può contenere solo TRUE o FALSE. Quindi, la nostra strategia di Vendita è stata suddivisa in quattro condizioni.  Se una qualsiasi delle condizioni viene rispettata o soddisfatta, un valore TRUE viene memorizzato nella nostra variabile di tipo bool, altrimenti verrà memorizzato un valore FALSE. Analizziamoli uno per uno come abbiamo nella sezione Buy

   bool Sell_Condition_1 = (maVal[0]<maVal[1]) && (maVal[1]<maVal[2]);

Qui, stiamo considerando i valori MA-8 sulle Barre 0, 1 e 2. Se il valore di MA-8 sulla barra corrente è inferiore al valore sulla Barra 1 precedente e anche il valore MA-8 sulla Barra 1 è inferiore al suo valore sulla Barra 2, significa che MA-8 sta diminuendo verso il basso. Ciò soddisfa una delle nostre condizioni per una configurazione di Sell.

   bool Sell_Condition_2 = (p_close <maVal[1]); 

Questa espressione sta controllando se la Barra 1 Il prezzo di chiusura è inferiore al valore di MA-8 nello stesso periodo (periodo Barra 1). Se il prezzo è più basso, allora anche la nostra seconda condizione è stata soddisfatta; quindi, possiamo controllare altre condizioni. Tuttavia, se le due condizioni che abbiamo appena considerato non sono state soddisfatte, allora non sarà necessario controllare altre condizioni. Ecco perché decidiamo di includere le prossime espressioni all'interno di queste due condizioni iniziali (espressioni).

   bool Sell_Condition_3 = (adxVal[0]>Adx_Min); 

Ora vogliamo verificare se il valore corrente di ADX (valore ADX sulla Barra 0) è maggiore del valore ADX Minimo dichiarato nei Parametri di input Se questa espressione è vera, cioè, il valore corrente di ADX è maggiore del valore Minimo richiesto; vogliamo anche essere sicuri che il valoreMinusDI sia maggiore del valoreplusDI . Questo è ciò che abbiamo ottenuto nella successiva espressione

bool Sell_Condition_4 = (plsDI[0]<minDI[0]);

Se queste condizioni sono soddisfatte,cioè se tornano vere, allora vogliamo essere sicuri di non aprire una nuova posizione di acquisto se ne abbiamo già una. Ora è il momento di controllare il valore della variabile Buy_opened che abbiamo dichiarato in precedenza nel nostro codice.

// any opened Sell position?
            if (Sell_opened) 
            {
                Alert("We already have a Sell position!!!"); 
                return;    // Don't open a new Sell Position
            }

Se Sell_opened è vero, non vogliamo aprire un'altra posizione di vendita, quindi mostriamo un avviso per informarci e poi tornare in modo che il nostro EA attenda ora il prossimo Tick. Tuttavia, se Sell_opened è FALSO, allora impostiamo la nostra richiesta di Sell trade come abbiamo fatto per l'ordine di Acquisto.

La principale differenza qui è il modo in cui noi calcoliamo il nostro prezzo stop loss e il prezzo take profit. Anche quando stiamo vendendo, vendiamo al prezzo Bid; ecco perché abbiamo usato la nostra variabile di tipo MqlTick latest_price per ottenere l'ultimo prezzo bid. L'altro tipo qui, come spiegato in precedenza, è ORDER_TYPE_SELL.

Anche qui,abbiamo utilizzato la funzione NormalizeDouble per il prezzo Bid, i valori StopLoss e TakeProfit; è buona norma normalizzare sempre questi prezzi al numero di cifre della coppia di valute prima di inviarlo al server di trading.

Proprio come abbiamo fatto per il nostro ordine di Acquisto, dobbiamo controllare anche se il nostro ordine di Vendita è andato a buon fine o no. Quindi abbiamo usato la stessa espressione come nel nostro ordine di Acquisto.

         if(mresult.retcode==10009 || mresult.retcode==10008) //Request is completed or order placed
           {
            Alert("A Sell order has been successfully placed with Ticket#:",mresult.order,"!!");
           }
         else
           {
            Alert("The Sell order request could not be completed -error:",GetLastError());
            ResetLastError();
            return;
           }
        }


3. Debug e test del nostro Expert Advisor

A questo punto, dobbiamo testare il nostro EA per sapere se la nostra strategia funziona o no. Inoltre, è possibile che ci siano uno o due errori nel nostro codice EA. Questo lo scopriremo nel passaggio successivo.

3.1 IL DEBUG

Il debug del nostro codice ci aiuta a capire come il nostro codice esegue riga per riga (se impostiamo dei breakpoint) e quindi poi possiamo notare qualsiasi errore o bug nel nostro codice ed effettuare rapidamente le correzioni necessarie prima di utilizzare il nostro codice nel real trade.

Qui, passeremo attraverso il processo graduale step by step di debug del nostro Expert Advisor impostando, in primo luogo, con breakpoint e, in secondo luogo, senza breakpoint. Per fare questo, assicurati di non aver chiuso l'Editor. Prima di tutto, selezioniamo il grafico che vogliamo utilizzare per testare il nostro EA. Nella barra dei Menu dell'Editor, clicca su Strumenti e clicca su Opzioni come mostrato di seguito:

Figura 8. Configurazione delle opzioni di Debug

Figura 8. Configurazione delle opzioni di Debug 

Una volta comparsa la finestra Opzioni, selezionare la coppia di valute e il periodo/intervallo di tempo da utilizzare e cliccare sul pulsante OK:

Figura 9. Finestra delle opzioni del Debugger

Prima di avviare il debugger, impostiamo i breakpoint. I breakpoint ci permettono di monitorare il comportamento/le prestazioni del nostro codice in determinate posizioni o linee selezionate. Piuttosto che eseguire tutto il codice in una sola volta, il debugger si fermerà ogni volta che vede un breakpoint, in attesa della tua azione netta. Con questo, saremo in grado di analizzare il nostro codice e monitorare il suo comportamento quando raggiunge ogni punto di rottura configurato. Saremo anche in grado di valutare i valori di alcune delle nostre variabili per vedere se le cose vanno effettivamente come abbiamo previsto.

Per inserire unbreakpoint, passare alla riga nel tuo codice quando vuoi impostare il breakpoint. Sul lato sinistro, nel campo grigio vicino al bordo della riga del codice, fare doppio click e verrà visualizzato un piccolo bottone blu rotondo con un quadrato bianco al suo interno. O in alternativa, posizionare il cursore del tuo mouse in un punto qualsiasi della riga del codice in cui si desidera che il breakpoint per visualizzare e premere F9. Per rimuovere il breakpoint, premere di nuovo F9 o fare doppio click su di esso.

Figura 10. Configurazione di un breakpoint

Figura10. Impostazione di un breakpoint

Per il nostro codice, stabiliremo un breakpoint su cinque righe diverse. 

Li etichetterò anche da 1 a 5 ai fini della spiegazione.

Per continuare, impostare un breakpoint nelle sette righe di codice, come illustrato nella figura seguente. Il Breakpoint1  è quello che abbiamo creato sopra.

Figura 11. Configurazione di breakpoint aggiuntivi

Figura 11. Configurazione di breakpoint aggiuntivi

Una volta che abbiamo finito di configurare i nostri breakpoint, ora siamo pronti per iniziare il debug del nostro codice.

Per avviare il debugger, premere F5 o cliccare sul pulsante verde sulla Barra degli Strumenti del MetaEditor:

  Figura 12. Avvio del Debugger

Figura 12. Avvio del Debugger

La prima cosa che l'editor fa è compilare il codice; se c'è qualche errore in un determinato punto, lo visualizzerà e se non c’è nessun errore, ti comunicherà che il codice è stato compilato correttamente.

Figura 13. Report di Compilazione

Figura 13. Report di Compilazione

Si prega di notare che il fatto che il codice sia compilato correttamente non significa che esso non contenga errori. A seconda di come viene scritto il codice, potrebbero esserci errori di runtime. Ad esempio, se una qualsiasi delle nostre espressioni non viene valutata correttamente a causa di una piccola svista, il codice verrà compilato correttamente ma potrebbe non essere eseguito correttamente. Troppe chiacchiere, vediamolo in azione...

Una volta che il debugger ha terminato la compilazione del codice, ti porta al terminale di trading e associa l'EA al grafico che hai specificato nelle impostazioni delle Opzioni di MetaEditor. Allo stesso tempo, mostra la sezione parametri di input dell'EA. Dal momento che non stiamo sistemando ancora nulla, basta fare clic sul pulsante OK.

Figura 14. Parametri di Input dell’Expert Advisor per il Debug

Figura 14. Parametri di Input dell’Expert Advisor per il Debug

Ora vedrai chiaramente l'EA nell’ angolo in alto a destra del grafico.

Una volta avviato l’ OnTick(), si fermerà non appena arriva al nostro breakpoint 1.

Figura 15. Il Debugger si ferma al primo breakpoint

Figura 15. Il Debugger si ferma al primo breakpoint

Noterai una freccia verde in quella riga di codice. Ciò indica che la riga di codice precedente era stata eseguita; ora siamo pronti per eseguire la riga corrente.

Permettetemi di spiegare alcune cose prima di procedere. Se guardi la Barra degli Strumenti dell'Editor, noterai che i tre pulsanti con frecce curve che in precedenza erano disattivate, ora sono attivate. Questo perché ora stiamo eseguendo il debugger. Questi pulsanti/comandi vengono utilizzato per esaminare il nostro codice (Step into, Step over o Step out)

Figura 16. Comando Step into

Figura 16. Comando Step into

Lo Step Into viene utilizzato per andare da un passaggio dell'esecuzione del programma al passaggio successivo, entrando in ogni funzione chiamata all'interno di quella riga di codice. Cliccare sul pulsante o premere F11 per richiamare il comando. (Useremo questo comando nel nostro debug Step by Step del nostro codice.)

Figura 17. Comando Step over

Figura 17. Comando Step over

LoStep over invece non entra in qualsiasi funzione chiamata all'interno di quella riga di codice. Cliccare sul pulsante o premere F10 per richiamare il comando

Figura 18. Comando Step out

Figura 18. Comando Step out

Per eseguire un passaggio del programma che è a un livello superiore, cliccare su questo pulsante o premere Shift+F11.

Inoltre, nella parte inferiore dell'Editor, vedrai la finestra Toolbox. Il tab Debug in questa finestra ha le seguenti voci:

  • File: mostra il nome del file chiamato
  • Funzione. Questo mostra la funzione corrente dal file chiamato
  • Riga: Mostra il numero della riga di codice nel file da cui viene chiamata la funzione.
  • Espressione: Qui è dove puoi digitare il nome di qualsiasi espressione/variabile che sei interessato a monitorare dal nostro codice. 
  • Valore Verrà visualizzato il valore dell’ espressione/variabile digitata nell'area dell’Espressione.
  • Tipo: Mostra il tipo di dati dell’ espressione/variabile monitorata.

Torniamo al nostro processo di debug...

La prossima cosa che vogliamo fare ora è digitare le variabili/espressioni del nostro codice che ci interessa monitorare. Assicurati di monitorare solo le variabili/ espressioni che contano davvero nel tuo codice. Per il nostro esempio, monitoreremo quanto segue:

  • Old_Time (bar time vecchia)
  • New_Time[0] (bar time corrente)
  • IsNewBar (flag che indica la nuova barra)
  • Mybars (Barre totali nella Cronologia) – Il nostro EA dipende da questo

Puoi aggiungere altri come i valori ADX, i valori MA-8, ecc.

Per aggiungere l'espressione/variabile, fare doppio click nell'area delle Espressioni oppure cliccare con il pulsante destro del mouse nell’area delle Espressioni e selezionare Aggiungi come mostratonella figura qui sopra.

Digitare l'espressione/variabile da monitorare o da osservare.

Figura 19. La finestra di osservazione delle espressioni

Figura 19. La finestra di osservazione delle espressioni

Digita tutte le variabili/espressioni necessarie...

Figura 20. Aggiunta di espressioni o variabili da osservare

Figura 20. Aggiunta di espressioni o variabili da osservare

Se la variabile non è stata ancora dichiarata, il suo tipo è "Identificatore sconosciuto" (ad eccezione delle variabili statiche).

Ora, passiamo oltre ...

Figura 21. Comando step into in azione

Figura 21. Comando step into in azione

Cliccare il pulsanteStep into o premere F11  e osserva cosa succede. Continua, premendo questo pulsante o F11 fino ad arrivare al breakpoint n. 2, continuare fino ad arrivare al breakpoint n. 4 come mostrato di seguito e si osservare la finestra di osservazione delle espressioni.


Figura 22. Osservare le espressioni o le variabili

Figura 22. Osservare le espressioni o le variabili

Figura 23. Osservazione delle espressioni o variabili

Figura 23. Osservare le espressioni o le variabili

Figura 24. Osservazione delle espressioni ovariabili

Figura 24. Osservare le espressioni o le variabili

Una volta che c'è un nuovo tick, tornerà alla prima riga di codice della funzioneOnTick(). Tutti i valori delle nostre variabili/espressioni saranno resettati poiché si tratta di un nuovo tick, eccetto il caso in cui uno di essi viene dichiarato una variabile statica. Nel nostro caso, abbiamo una variabile statica Old_Time.

Figura 25. Valori delle variabili sull'evento NewTick

Figura 25. Valori delle variabili sull'evento NewTick

Per ripetere il processo, continua premendo il tasto F11e continua a monitorare le variabili nella finestra di osservazione delle espressioni. È possibile arrestare il debugger e quindi rimuovere tutti i breakpoints.

Come possiamo vedere, in modalità Debug stampa il messaggio "Abbiamo una nuova barra qui ...".

Figura 26. L’Expert Advisor stampa il messaggio in modalità Debug

Figura 26. L’ Expert Advisor stampa il messaggio in modalità Debug

Avviare nuovamente il processo di debug; ma questa volta senza breakpoint. Continua a guardare ogni tick e se una qualsiasi delle nostre condizioni di Acquisto/Vendita è soddisfatta, effettuerà un trade. Dal momento che abbiamo scritto il nostro codice, per comunicarci se un ordine è andato a buon fine o meno, visualizzare un avviso.

Figura 27. L'Expert Advisor esegue un trade durante il debug

Figura 27. L’Expert Advisor esegue un trade durante il debug

Penso che tu possa lasciare l'EA a lavorare per qualche minuto in più mentre prendi un caffè. Una volta che sei tornato e hai guadagnato un po 'di soldi (sto scherzando),clicca sul pulsante (rosso) STOP sul MetaEditor per interrompere il debug.

Figura 28. Interrompere il debugger

Figura 28. Interruzione del debugger

Quello che abbiamo effettivamente fatto qui è stato controllare che il nostro EA controlli solo un trade all'apertura di una nuova Barra e che il nostro EA funzioni correttamente. C'è ancora molto margine per le modifiche al nostro codice EA.

Permettetemi di chiarire, a questo punto, che il terminale di Trading deve essere connesso a Internet, altrimenti il debug non funzionerà perché il terminale non sarà in grado di fare trading.

3.2 TESTARE LA NOSTRA STRATEGIA EA

A questo punto, ora vogliamo testare il nostro EA utilizzando lo Strategy Tester integrato nel Terminale di Trading.  Per avviare Strategy Tester, premere CTRL+R oppure cliccare sul menu Visualizza sulla Barra dei Menu del Terminale e fare click su Strategy Tester come mostrato di seguito

Figura 26. Avvio dello Strategy Testing

Figura 26. Avvio dello Strategy Testing

Il Tester (Strategy Tester) è mostrato nella la parte inferiore del terminale. Per poter vedere tutte le impostazioni del Tester, c’è bisogno di espanderlo / ridimensionarlo. Per fare questo, sposta il puntatore del mouse sul punto indicato dalla freccia rossa (come mostrato di seguito)

Figura 27. La finestra dello Strategy Tester

Figura 27. La finestra dello Strategy Tester.

Il puntatore del mouse si trasforma in una freccia a doppia estremità, tieni premuto il mouse e trascina la linea verso l'alto. Fermati quando scopri che puoi vedere tutto nel tab delle impostazioni. 

Figura 28. Tab delle Impostazioni dello Strategy Tester

Figura 28. Tab delle Impostazioni dello Strategy Tester

  1. Seleziona l'EA che vuoi testare
  2. Seleziona la coppia di Valute da utilizzare per il test
  3. Selezionare il Periodo/Intervallo di Tempo da utilizzare per il test
  4. Seleziona Periodo Personalizzato e imposta le date su 5
  5. Impostare le date per il periodo personalizzato da utilizzare per il test
  6. L'Esecuzione è Normale
  7. Seleziona l'importo del deposito in dollari USA da utilizzare per il test
  8. Imposta l'Ottimizzazione su Disabilita (ora non stiamo ottimizzando, vogliamo solo testare)
  9. Clicca su questo pulsante quando sei pronto per iniziare il test.

Prima di cliccare sul pulsante Start, analizziamo gli altri tab sul Tester

Tab Agents

Il processore utilizzato dal Tester per effettuare il Test. Dipende dal tipo di processore del tuo Computer. Il mio è solo un (1) processore core.

Figura 29. Tab Agent dello Strategy Tester

Figura 29. Tab Agents dello Strategy Tester

Una volta che l'agente, vedrai qualcosa di simile alla figura seguente

Figura 30. Tab Agents dello Strategy Tester durante un test

Figura 30. Tab Agents dello Strategy Testert durante un test

Tab Journal

Qui vengono visualizzati tutti gli eventi in corso durante il periodo di prova

Figura 31. Tab Journal dello Strategy Tester che mostra le attività di trading

Figura 31. Tab Journal dello Strategy Tester che mostra le attività di trading

Tab Inputs

Qui è possibile specificare i parametri di input per l'EA.

Figura 32. Tab Inputs dello Strategy Tester

Figura 32. Tab Inputs dello Strategy Tester

Se stiamo ottimizzando il nostro EA, allora dovremo impostare i valori nell'area cerchiata.

  • LoStart sono i valori con cui vuoi che il Tester cominci.
  • Lo Step è il tasso di incremento per il valore selezionato e
  • LoStop è il valore al quale il Tester smetterà di incrementare il valore per quel parametro.

Tuttavia, nel nostro caso non stiamo ottimizzando il nostro EA, quindi non avremo bisogno di toccarlo per ora. 

Una volta che tutto è impostato, torniamo ora al tabSettings e cliccare sul pulsante Start. Quindi, il Tester inizia il suo lavoro. Tutto ciò che devi fare ora è andare a bere un’altra tazza di caffè se vuoi o, se sei come me, potresti voler monitorare ogni evento, quindi consulti il tab Journal .

Tab Graph

Una volta che inizi a visualizzare i messaggi sugli ordini inviati nel Tab Journal, potresti quindi voler passare a una NUOVO tab chiamato Graph che è stato appena creato. Una volta passato al tab Graph, vedrai il grafico continuare ad aumentare o diminuire in base ai casi a seconda dell'esito delle tue operazioni.

Figura 33. Il risultato del grafico per il test dell’Expert Advisor

Figura 33. Il risultato del grafico per il Test dell’Expert Advisor

Tab Results

Una volta completato il test, vedrai un altro tab chiamatoResults. Passare al tab Results e vedrai il riepilogo del test che abbiamo appena effettuato.

Figura 34. II tab Strategy Tester Results mostra il riepilogo dei risultati dei test

Figura 34. II tab Strategy Tester Results mostra il riepilogo dei risultati dei test

Puoi vedere il Profitto Lordo totale, l'Utile Netto, il totale delle transazioni, il totale delle perdite delle transazioni e molto altro ancora. È davvero interessante vedere che abbiamo circa 1.450 dollari USA all’interno del periodo che abbiamo selezionato per il nostro test. Almeno abbiamo qualche profitto.

A questo punto, permettetemi di dirvi una cosa molto chiara. Scoprirai che le impostazioni per i parametri EA che vedi nello Strategy tester sono diverse dalle impostazioni iniziali dei parametri di input dell'EA. Ti ho appena dimostrato che puoi modificare uno qualsiasi di questi parametri di input per ottenere il meglio dal tuo EA. Invece di usare un periodo di 8 ciascuno per la Media Mobile e l’ADX, l'ho modificato in 10 per la Media Mobile e 14 per l’ADX. Cambio anche lo Stop Loss, passando da 30 a 35. Ultima cosa ma non meno importante, ho deciso di utilizzare un intervallo di tempo di 2 Ore. Ricorda, questo è lo Strategy Tester.

Se vuoi visualizzare un report completo del test, allora clicca con il pulsante destro del mouse su qualsiasi punto del tab Results, vedrai un menu. Da questo menu, seleziona ‘Salva con Report’.

Figura 35. Salvare il risultato del test

Figura 35. Salvataggio del risultato del test

Apparirà la finestra di dialogo salva; digita un nome per il tuo report (se vuoi, altrimenti puoi lasciare il nome predefinito) e cliccare sul pulsante Salva. L'intero report verrà salvato per te in formato HTML.

Per visualizzare il grafico per il test che è stato eseguito, clicca su Open Chart e vedrai il grafico mostrato

Figura 36. Il grafico mostra il test 

Figura 36. Il grafico mostra il test

Questo è tutto.Abbiamo scritto e testato con successo il nostro EA e ora abbiamo un risultato con cui lavorare. Ora puoi tornare al tab delle Impostazioni dello Strategy Tester ed effettuare il test per un altro Intervalli di Tempo/Periodo.

Assegnazione

Vorrei che tu eseguissi il test usando diverse coppie di valute, diversi intervalli di tempo, diversi Stop Loss, diversi Take profit e vedere come si comporta l'EA. Puoi anche provare nuovi valori di Media Mobile e ADX. Come ho detto prima, questa è l'essenza dello Strategy Tester. Mi piacerebbe anche che tu condividessi i tuoi risultati con me.

Conclusione

In questa guida step by step, siamo stati in grado di esaminare i passaggi fondamentali richiesti per scrivere un semplice Expert Advisor basato su una strategia di trading sviluppata. Abbiamo anche analizzato il modo in cui controlliamo il nostro EA per gli errori utilizzando il debugger. Abbiamo, inoltre, parlato di come testare le prestazioni del nostro EA utilizzando lo Strategy Tester. Con questo, siamo stati in grado di vedere la potenza e la solidità del nuovo linguaggio MQL5. Il nostro EA non è ancora perfetto o completo in quanto molte altre modifiche devono ancora essere effettuate per poterlo utilizzare per il trading reale.

C'è ancora molto da imparare: voglio che tu legga di nuovo l'articolo insieme al manuale MQL5 e provi tutto ciò che hai imparato in questo articolo. Posso assicurarti che sarai un grande sviluppatore EA in un futuro non molto lontano.

Buona codifica!


Tradotto dall’inglese da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/en/articles/100

File allegati |
my_first_ea.mq5 (11.86 KB)
Creazione di una Information Board utilizzando le Standard Library Classes e Google Chart API Creazione di una Information Board utilizzando le Standard Library Classes e Google Chart API
Il linguaggio di programmazione MQL5 è destinato principalmente alla creazione di sistemi di trading automatizzati e strumenti complessi di analisi tecniche. Tuttavia, a parte questo, ci consente di creare interessanti sistemi informativi per il monitoraggio delle situazioni del mercato e fornisce una connessione di ritorno con il trader. L'articolo descrive i componenti della Standard Library MQL5 e mostra esempi del loro utilizzo nella pratica per raggiungere questi obiettivi. Viene, inoltre, illustrato un esempio di come utilizzare Google Chart API per la creazione di grafici.
Nuove Opportunità con MetaTrader 5 Nuove Opportunità con MetaTrader 5
MetaTrader 4 ha guadagnato la sua popolarità tra i trader di tutto il mondo e sembrava che non si potesse desiderare di più. Con la sua elevata velocità di elaborazione, stabilità, ampia gamma di possibilità per la scrittura di indicatori, Expert Advisor e sistemi di trading informativo, e la possibilità di scegliere tra oltre un centinaio di broker diversi, - il terminale si è notevolmente distinto dal resto. Tuttavia, il tempo non si ferma e ci troviamo di fronte a una scelta da compiere tra MetaTrade 4 e MetaTrade 5. In questo articolo, descriveremo le principali differenze del terminale di 5a generazione dal nostro attuale favore.
Funzioni di Money Management in un Expert Advisor Funzioni di Money Management in un Expert Advisor
Lo sviluppo delle strategie di trading si focalizza principalmente sulla ricerca di modelli per entrare ed uscire dal mercato, oltre a mantenere delle posizioni. Se siamo in grado di formalizzare alcuni modelli in regole per il trading automatizzato, il trader affronta la questione del calcolo del volume delle posizioni, della grandezza dei margini e del mantenimento di un livello sicuro di fondi ipotecari per assicurare le posizioni aperte in una modalità automatizzata . In questo articolo, utilizzeremo il linguaggio MQL5 per costruire semplici esempi di eseguire questi calcoli.
Creazione di Indicatori di Tick in MQL5 Creazione di Indicatori di Tick in MQL5
In questo articolo, analizzeremo la creazione di due indicatori: l'indicatore tick, che traccia il grafico tick del prezzo e l'indicatore tick candle, che traccia le candele con il numero di tick specificato. Ciascuno degli indicatori scrive i prezzi in entrata in un file e utilizza i dati salvati dopo il riavvio dell'indicatore (questi dati possono essere utilizzati anche dagli altri programmi)