English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Manuale MQL5: Utilizzo degli indicatori per impostare le condizioni di trading in Expert Advisor

Manuale MQL5: Utilizzo degli indicatori per impostare le condizioni di trading in Expert Advisor

MetaTrader 5Esempi | 11 gennaio 2022, 16:44
466 0
Anatoli Kazharski
Anatoli Kazharski

Introduzione

In questo articolo, l'Expert Advisor sarà arricchito con indicatori i cui valori saranno utilizzati per verificare le condizioni di apertura della posizione. Per ravvivarlo, creeremo un elenco a discesa nei parametri esterni per poter selezionare uno su tre indicatori di trading.

Si prega di ricordare, per ogni evenienza: continuiamo a modificare l'Expert Advisor su cui abbiamo lavorato in tutti gli articoli precedenti della serie Manuale MQL5. L'ultima versione dell'Expert Advisor può essere scaricata dall'articolo intitolato "Manuale MQL5: La cronologia delle offerte e della libreria di funzioni per ottenere proprietà di posizione".

Inoltre, questo articolo presenterà una funzione che creeremo per verificare se le operazioni di trading possono o non possono essere eseguite. La funzione di apertura della posizione verrà modificata in modo da consentire all'Expert Advisor di determinare la modalità di negoziazione (Instant Execution e Market Execution).

Poiché il codice dell'Expert Advisor, seguendo tutti i miglioramenti e i miglioramenti apportati negli articoli precedenti, supera già le 1.500 righe, diventerà sempre meno conveniente con ogni nuova funzionalità aggiunta. Quindi, la soluzione logica è dividerlo in diverse categorie come file di libreria separati. Ora che gli obiettivi sono stati fissati, iniziamo.

 

Sviluppo di Expert Advisor

Inseriamo il codice sorgente di Expert Advisor (*.mq5) dall'articolo precedente in una cartella separata, TestIndicatorConditions, in cui dobbiamo creare la sottocartella Include. Questa è la cartella in cui creeremo i file include (*.mqh). Possono essere generati utilizzando la procedura guidata MQL5 (Ctrl+N) o creati manualmente nella directory richiesta come file di testo standard (*.txt) e ulteriormente rinominati in *.mqh.

Di seguito sono riportati i nomi e i commenti a tutti i file di include creati:

  • Enums.mqh conterrà tutte le enumerazioni;
  • InfoPanel.mqh sarà dotato di funzioni per l'impostazione del pannello informativo, la creazione e l'eliminazione di oggetti grafici;
  • Errors.mqh coprirà tutte le funzioni che restituiscono codici di errore e motivi di deinitializzazione;
  • TradeSignals.mqh sarà caratterizzato da funzioni che riempiono gli array con prezzi e valori di indicatori, nonché blocchi di segnale;
  • TradeFunctions.mqh conterrà funzioni di trading;
  • ToString.mqh coprirà le funzioni che convertono i valori numerici in valori stringa;
  • Auxiliary.mqh verrà utilizzato per altre funzioni ausiliarie.

Per includere queste librerie nel file principale, utilizziamo la direttiva #include. Poiché il file principale di Expert Advisor e la cartella include file (Include) si trovano nella stessa cartella, il codice per l'inclusione dei file sarà il seguente:

//--- Include custom libraries
#include "Include\Enums.mqh"
#include "Include\InfoPanel.mqh"
#include "Include\Errors.mqh"
#include "Include\TradeSignals.mqh"
#include "Include\TradeFunctions.mqh"
#include "Include\ToString.mqh"
#include "Include\Auxiliary.mqh"

Quindi, saremo in grado di aprirli e modificarli e spostare una parte del codice sorgente dal file principale di Expert Advisor.

Per navigare correttamente nel codice, i riferimenti ai file di intestazione adiacenti e al file principale di Expert Advisor verranno aggiunti a ciascun file di intestazione. Ad esempio, per la nostra libreria di funzioni di trading, TradeFunctions.mqh, questo assomiglierà a:

//--- Connection with the main file of the Expert Advisor
#include "..\TestIndicatorConditions.mq5"
//--- Include custom libraries
#include "Enums.mqh"
#include "InfoPanel.mqh"
#include "Errors.mqh"
#include "TradeSignals.mqh"
#include "ToString.mqh"
#include "Auxiliary.mqh"

Per i file allo stesso livello di nidificazione, è sufficiente specificare semplicemente il nome. Per salire di un livello, è necessario mettere due punti prima della barra posteriore nel percorso.

Aggiungiamo l'enumerazione per gli indicatori nel file Enums.mqh. A scopo illustrativo, in questo Expert Advisor utilizzeremo due indicatori standard (Moving Average e Commodity Channel Index) e un indicatore personalizzato ( MultiRange_PCH ). L'enumerazione sarà la seguente:

//--- Indicators
enum ENUM_INDICATORS
  {
   MA       = 0, // Moving Average
   CCI      = 1, // CCI
   PCH      = 2  // Price Channel
  };

I parametri esterni vengono modificati come segue:

//--- External parameters of the Expert Advisor
sinput   long              MagicNumber=777;        // Magic number
sinput   int               Deviation=10;           // Slippage
input    ENUM_INDICATORS   Indicator=MA;           // Indicator
input    int               IndicatorPeriod=5;      // Indicator period
input    int               IndicatorSegments=2;    // Number of one direction indicator segments
input    double            Lot=0.1;                // Lot
input    double            VolumeIncrease=0.1;     // Position volume increase
input    double            VolumeIncreaseStep=10;  // Step for volume increase
input    double            StopLoss=50;            // Stop Loss
input    double            TakeProfit=100;         // Take Profit
input    double            TrailingStop=10;        // Trailing Stop
input    bool              Reverse=true;           // Position reversal
sinput   bool              ShowInfoPanel=true;     // Display of the info panel

Come accennato in precedenza, sarà possibile selezionare uno dei tre indicatori nell'elenco a discesa del parametro Indicatore.

Esiste un solo parametro applicabile a tutti gli indicatori in cui è possibile impostare il periodo dell'indicatore: IndicatorPeriod. Il parametro NumberOfBars della versione precedente di Expert Advisor è stato rinominato in IndicatorSegments e ora indica il numero di barre durante le quali un determinato indicatore deve salire/scendere per soddisfare la condizione di apertura della posizione.

Inoltre, abbiamo aggiunto un altro parametro esterno, VolumeIncreaseStep, che può essere utilizzato per impostare il passo per l'aumento del volume in punti.

Il valore della variabile AllowedNumberOfBars (ora AllowedNumberOfSegments)veniva regolato nella funzione personalizzata GetBarsData(). Ora verrà inserito in una funzione separata e chiamato solo all'inizializzazione.

Poiché la condizione di apertura della posizione verrà ora controllata utilizzando i valori dell'indicatore, il valore da assegnare sarà sempre maggiore di due. In altre parole, se alla variabile esterna IndicatorSegments viene assegnato il valore di 1, alla variabile AllowedNumberOfSegments verrà assegnato il valore di 3, poiché per soddisfare la condizione (ad esempio per un BUY), il valore dell'indicatore sulla barra completata deve essere maggiore di quello sulla barra precedente. A tal fine, dobbiamo ottenere gli ultimi tre valori dell'indicatore.

Di seguito è riportato il codice funzione CorrectInputParameters():

//+------------------------------------------------------------------+
//| Adjusting input parameters                                       |
//+------------------------------------------------------------------+
void CorrectInputParameters()
  {
//--- Adjust the number of bars for the position opening condition
   if(AllowedNumberOfSegments<=0)
     {
      if(IndicatorSegments<=1)
         AllowedNumberOfSegments=3;                     // At least three bars are required
      if(IndicatorSegments>=5)
         AllowedNumberOfSegments=5;                     // but no more than 7
      else
         AllowedNumberOfSegments=IndicatorSegments+1;   // and always greater by two
     }
  }

Prima di iniziare a gestire gli indicatori, creiamo una funzione che verificherà se il trading è consentito - CheckTradingPermission(). Se il trading non è consentito per uno dei motivi elencati nella funzione, verrà restituito il valore zero. Ciò significa che il prossimo tentativo dovrà essere fatto sulla barra successiva.

//+------------------------------------------------------------------+
//| Checking if trading is allowed                                   |
//+------------------------------------------------------------------+
bool CheckTradingPermission()
  {
//--- For real-time mode
   if(IsRealtime())
     {
      //--- Checking server connection
      if(!TerminalInfoInteger(TERMINAL_CONNECTED))
         return(1);
      //--- Permission to trade at the running program level
      if(!MQL5InfoInteger(MQL5_TRADE_ALLOWED))
         return(2);
      //--- Permission to trade at the terminal level
      if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
         return(3);
      //--- Permission to trade for the current account
      if(!AccountInfoInteger(ACCOUNT_TRADE_ALLOWED))
         return(4);
      //--- Permission to trade automatically for the current account
      if(!AccountInfoInteger(ACCOUNT_TRADE_EXPERT))
         return(5);
     }
//---
   return(0);
  }

Passiamo ora al punto principale dell'articolo. Per ottenere l'accesso ai valori dell'indicatore, dobbiamo prima ottenere la sua maniglia. Questo viene fatto usando funzioni speciali i cui nomi sono fatti del nome breve dell'indicatore e del simbolo 'i' che lo precede.

Ad esempio, l'indicatore della media mobile ha la funzione corrispondente iMA(). Tutte le maniglie standard degli indicatori nel terminale MetaTrader 5 possono essere ottenute utilizzando queste funzioni. L'elenco completo è disponibile nella sezione MqL5 Reference chiamata Indicatori tecnici. Se è necessario ottenere una maniglia di un indicatore personalizzato, utilizzare la funzione iCustom().

Implementeremo la funzione GetIndicatorHandle() in cui, a seconda dell'indicatore selezionato nel parametro Indicator, il valore handle dell'indicatore corrispondente verrà assegnato alla variabile globale indicator_handle. Il codice funzione può essere trovato nella nostra libreria di funzioni del segnale di trading (il file \Include\TradeSignals.mqh), mentre la variabile con l'handle dell'indicatore si trova nel file principale dell'Expert Advisor.

//+------------------------------------------------------------------+
//| Getting the indicator handle                                     |
//+------------------------------------------------------------------+
void GetIndicatorHandle()
  {
//--- If the Moving Average indicator is selected
   if(Indicator==MA)
      indicator_handle=iMA(_Symbol,Period(),IndicatorPeriod,0,MODE_SMA,PRICE_CLOSE);
//--- If the CCI indicator is selected
   if(Indicator==CCI)
      indicator_handle=iCCI(_Symbol,Period(),IndicatorPeriod,PRICE_CLOSE);
//--- If the MultiRange_PCH indicator is selected
   if(Indicator==PCH)
      indicator_handle=iCustom(_Symbol,Period(),"MultiRange_PCH",IndicatorPeriod);
//--- If the indicator handle could not be obtained
   if(indicator_handle==INVALID_HANDLE)
      Print("Failed to get the indicator handle!");
  }

Inoltre, creiamo la funzione GetDataIndicators() in cui utilizzando le maniglie degli indicatori ottenuti, possiamo ottenere i loro valori. Questo viene fatto usando la funzione CopyBuffer() in modo simile a ottenere i valori della barra usando le funzioni CopyTime(), CopyClose(), CopyOpen(), CopyHigh() e CopyLow() considerate nell'articolo chiamato "Manuale MQL5: Analisi delle proprietà di posizione nel MetaTrader 5 Strategy Tester".

Poiché l'indicatore può avere diversi buffer (righe di valori), l'indice del buffer viene passato alla funzione CopyBuffer() come secondo parametro. Gli indici buffer per gli indicatori standard sono disponibili in MQL5 Reference. Per gli indicatori personalizzati, gli indici del buffer sono disponibili nel codice, a condizione che il codice sorgente sia disponibile. Se non c'è codice, dovrai trovare l'indice tramite esperimento, osservando come le condizioni sono soddisfatte nella modalità di visualizzazione dello Strategy Tester.

Prima di ciò, dobbiamo creare matrici dinamiche per i valori del buffer degli indicatori nel file principale di Expert Advisor:

//--- Arrays for indicator values
double indicator_buffer1[];
double indicator_buffer2[];

Il codice di GetIndicatorsData() è fornito di seguito:

//+------------------------------------------------------------------+
//| Getting indicator values                                         |
//+------------------------------------------------------------------+
bool GetIndicatorsData()
  {
//--- If the indicator handle has been obtained
   if(indicator_handle!=INVALID_HANDLE)
     {
      //--- For the Moving Average or CCI indicator
      if(Indicator==MA || Indicator==CCI)
        {
         //--- Reverse the indexing order (... 3 2 1 0)
         ArraySetAsSeries(indicator_buffer1,true);
         //--- Get indicator values
         if(CopyBuffer(indicator_handle,0,0,AllowedNumberOfSegments,indicator_buffer1)<AllowedNumberOfSegments)
           {
            Print("Failed to copy the values ("+
                  _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer1 array! Error ("+
                  IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError()));
            return(false);
           }
        }
      //--- For the MultiRange_PCH indicator
      if(Indicator==PCH)
        {
         //--- Reverse the indexing order (... 3 2 1 0)
         ArraySetAsSeries(indicator_buffer1,true);
         ArraySetAsSeries(indicator_buffer2,true);
         //--- Get indicator values
         if(CopyBuffer(indicator_handle,0,0,AllowedNumberOfSegments,indicator_buffer1)<AllowedNumberOfSegments || 
            CopyBuffer(indicator_handle,1,0,AllowedNumberOfSegments,indicator_buffer2)<AllowedNumberOfSegments)
           {
            Print("Failed to copy the values ("+
                  _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer1 or indicator_buffer2 array! Error ("+
                  IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError()));
            return(false);
           }
        }
      //---
      return(true);
     }
//--- If the indicator handle has not been obtained, retry
   else
      GetIndicatorHandle();
//---
   return(false);
  }

La funzione GetTradingSignal() è stata sostanzialmente modificata. Le condizioni sono diverse in assenza della posizione e dove esiste la posizione. Per gli indicatori della media mobile e del CCI, le condizioni sono le stesse. Per MultiRange_PCH, sono disposti in un blocco separato. Per rendere il codice più leggibile ed evitare ripetizioni, creiamo una funzione ausiliaria, GetSignal(), che restituisce un segnale per l'apertura o l'inversione della posizione, a condizione che tale posizione esista e che l'azione pertinente sia consentita dal parametro esterno.

Di seguito è riportato il codice della funzione GetSignal():

//+------------------------------------------------------------------+
//| Checking the condition and returning a signal                    |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE GetSignal()
  {
//--- Check conditions for the Moving Average and CCI indicators
   if(Indicator==MA || Indicator==CCI)
     {
      //--- A Sell signal
      if(AllowedNumberOfSegments==3 && 
         indicator_buffer1[1]<indicator_buffer1[2])
         return(ORDER_TYPE_SELL);
      //---
      if(AllowedNumberOfSegments==4 && 
         indicator_buffer1[1]<indicator_buffer1[2] && 
         indicator_buffer1[2]<indicator_buffer1[3])
         return(ORDER_TYPE_SELL);
      //---
      if(AllowedNumberOfSegments==5 && 
         indicator_buffer1[1]<indicator_buffer1[2] && 
         indicator_buffer1[2]<indicator_buffer1[3] && 
         indicator_buffer1[3]<indicator_buffer1[4])
         return(ORDER_TYPE_SELL);
      //---
      if(AllowedNumberOfSegments==6 && 
         indicator_buffer1[1]<indicator_buffer1[2] && 
         indicator_buffer1[2]<indicator_buffer1[3] && 
         indicator_buffer1[3]<indicator_buffer1[4] && 
         indicator_buffer1[4]<indicator_buffer1[5])
         return(ORDER_TYPE_SELL);
      //---
      if(AllowedNumberOfSegments>=7 && 
         indicator_buffer1[1]<indicator_buffer1[2] && 
         indicator_buffer1[2]<indicator_buffer1[3] && 
         indicator_buffer1[3]<indicator_buffer1[4] && 
         indicator_buffer1[4]<indicator_buffer1[5] && 
         indicator_buffer1[5]<indicator_buffer1[6])
         return(ORDER_TYPE_SELL);

      //--- A Buy signal
      if(AllowedNumberOfSegments==3 && 
         indicator_buffer1[1]>indicator_buffer1[2])
         return(ORDER_TYPE_BUY);
      //---
      if(AllowedNumberOfSegments==4 && 
         indicator_buffer1[1]>indicator_buffer1[2] && 
         indicator_buffer1[2]>indicator_buffer1[3])
         return(ORDER_TYPE_BUY);
      //---
      if(AllowedNumberOfSegments==5 && 
         indicator_buffer1[1]>indicator_buffer1[2] && 
         indicator_buffer1[2]>indicator_buffer1[3] && 
         indicator_buffer1[3]>indicator_buffer1[4])
         return(ORDER_TYPE_BUY);
      //---
      if(AllowedNumberOfSegments==6 && 
         indicator_buffer1[1]>indicator_buffer1[2] && 
         indicator_buffer1[2]>indicator_buffer1[3] && 
         indicator_buffer1[3]>indicator_buffer1[4] && 
         indicator_buffer1[4]>indicator_buffer1[5])
         return(ORDER_TYPE_BUY);
      //---
      if(AllowedNumberOfSegments>=7 && 
         indicator_buffer1[1]>indicator_buffer1[2] && 
         indicator_buffer1[2]>indicator_buffer1[3] && 
         indicator_buffer1[3]>indicator_buffer1[4] && 
         indicator_buffer1[4]>indicator_buffer1[5] && 
         indicator_buffer1[5]>indicator_buffer1[6])
         return(ORDER_TYPE_BUY);
     }
//--- Block that checks conditions for the MultiRange_PCH indicator
   if(Indicator==PCH)
     {
      //--- A Sell signal
      if(close_price[1]<indicator_buffer2[1] && 
         open_price[1]>indicator_buffer2[1])
         return(ORDER_TYPE_SELL);
      //--- A Buy signal
      if(close_price[1]>indicator_buffer1[1] && 
         open_price[1]<indicator_buffer1[1])
         return(ORDER_TYPE_BUY);
     }
//--- No signal
   return(WRONG_VALUE);
  }

Il codice della funzione GetTradingSignal() è ora il seguente:

//+------------------------------------------------------------------+
//| Determining trading signals                                      |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE GetTradingSignal()
  {
//--- If there is no position
   if(!pos.exists)
     {
      //--- A Sell signal
      if(GetSignal()==ORDER_TYPE_SELL)
         return(ORDER_TYPE_SELL);
      //--- A Buy signal
      if(GetSignal()==ORDER_TYPE_BUY)
         return(ORDER_TYPE_BUY);
     }
//--- If the position exists
   if(pos.exists)
     {
      //--- Get the position type
      GetPositionProperties(P_TYPE);
      //--- Get the last deal price
      GetPositionProperties(P_PRICE_LAST_DEAL);
      //--- Block that checks conditions for the Moving Average and CCI indicators
      if(Indicator==MA || Indicator==CCI)
        {
         //--- A Sell signal
         if(pos.type==POSITION_TYPE_BUY && 
            GetSignal()==ORDER_TYPE_SELL)
            return(ORDER_TYPE_SELL);
         //---
         if(pos.type==POSITION_TYPE_SELL && 
            GetSignal()==ORDER_TYPE_SELL && 
            close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))
            return(ORDER_TYPE_SELL);
         //--- A Buy signal
         if(pos.type==POSITION_TYPE_SELL && 
            GetSignal()==ORDER_TYPE_BUY)
            return(ORDER_TYPE_BUY);
         //---
         if(pos.type==POSITION_TYPE_BUY && 
            GetSignal()==ORDER_TYPE_BUY && 
            close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))
            return(ORDER_TYPE_BUY);
        }
      //--- Block that checks conditions for the MultiRange_PCH indicator
      if(Indicator==PCH)
        {
         //--- A Sell signal
         if(pos.type==POSITION_TYPE_BUY && 
            close_price[1]<indicator_buffer2[1] && 
            open_price[1]>indicator_buffer2[1])
            return(ORDER_TYPE_SELL);
         //---
         if(pos.type==POSITION_TYPE_SELL && 

            close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))
            return(ORDER_TYPE_SELL);
         //--- A Buy signal
         if(pos.type==POSITION_TYPE_SELL && 
            close_price[1]>indicator_buffer1[1] && 
            open_price[1]<indicator_buffer1[1])
            return(ORDER_TYPE_BUY);
         //---
         if(pos.type==POSITION_TYPE_BUY && 
            close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))
            return(ORDER_TYPE_BUY);
        }
     }
//--- No signal
   return(WRONG_VALUE);
  }

Ora, abbiamo solo bisogno di vedere nelle modalità Instant Execution e Market Execution che fanno parte delle proprietà dei simboli e di modificare di conseguenza il codice della funzione di apertura della posizione OpenPosition(). Le modalità i cui nomi sono autoesplicativi si trovano anche in MQL5 Reference:

  • Instant Execution (Esecuzione Istantanea)
  • Market Execution (Esecuzione a Mercato)

Si ricorda che quando si ha a che fare con la modalità Market Execution, non è possibile aprire una posizione con i livelli di Stop Loss e Take Profit impostati: è necessario prima aprire una posizione e poi modificarla, impostando i livelli.

A partire dalla build 803, Stop Loss e Take Profit possono essere impostati quando si apre una posizione per le modalità Esecuzione di mercato ed Esecuzione di scambio.

Aggiungiamo la modalità di esecuzione alla struttura delle proprietà dei simboli:

//--- Symbol properties
struct symbol_properties
  {
   int               digits;           // Number of decimal places in the price
   int               spread;           // Spread in points
   int               stops_level;      // Stops level
   double            point;            // Point value
   double            ask;              // Ask price
   double            bid;              // Bid price
   double            volume_min;       // Minimum volume for a deal
   double            volume_max;       // Maximum volume for a deal
   double            volume_limit;     // Maximum permissible volume for a position and orders in one direction
   double            volume_step;      // Minimum volume change step for a deal
   double            offset;           // Offset from the maximum possible price for a transaction
   double            up_level;         // Upper Stop level price
   double            down_level;       // Lower Stop level price
   ENUM_SYMBOL_TRADE_EXECUTION execution_mode; // Execution mode
  };

Di conseguenza, è necessario modificare l'enumerazione ENUM_SYMBOL_PROPERTIES

//--- Enumeration of position properties
enum ENUM_SYMBOL_PROPERTIES
  {
   S_DIGITS          = 0,
   S_SPREAD          = 1,
   S_STOPSLEVEL      = 2,
   S_POINT           = 3,
   S_ASK             = 4,
   S_BID             = 5,
   S_VOLUME_MIN      = 6,
   S_VOLUME_MAX      = 7,
   S_VOLUME_LIMIT    = 8,
   S_VOLUME_STEP     = 9,
   S_FILTER          = 10,
   S_UP_LEVEL        = 11,
   S_DOWN_LEVEL      = 12,
   S_EXECUTION_MODE  = 13,
   S_ALL             = 14
  };

e la funzione GetSymbolProperties():

case S_EXECUTION_MODE: symb.execution_mode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_EXEMODE);   break;
      //---
      case S_ALL           :
         symb.digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
         symb.spread=(int)SymbolInfoInteger(_Symbol,SYMBOL_SPREAD);
         symb.stops_level=(int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL);
         symb.point=SymbolInfoDouble(_Symbol,SYMBOL_POINT);
         symb.ask=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),symb.digits);
         symb.bid=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),symb.digits);
         symb.volume_min=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
         symb.volume_max=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
         symb.volume_limit=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_LIMIT);
         symb.volume_step=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
         symb.offset=NormalizeDouble(CorrectValueBySymbolDigits(lot_offset*symb.point),symb.digits);
         symb.up_level=NormalizeDouble(symb.ask+symb.stops_level*symb.point,symb.digits);
         symb.down_level=NormalizeDouble(symb.bid-symb.stops_level*symb.point,symb.digits);
         symb.execution_mode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_EXEMODE);                       break;
         //---

Di conseguenza, il codice della funzione OpenPosition() è ora il seguente:

//+------------------------------------------------------------------+
//| Opening a position                                               |
//+------------------------------------------------------------------+
void OpenPosition(double lot,
                  ENUM_ORDER_TYPE order_type,
                  double price,
                  double sl,
                  double tp,
                  string comment)
  {
//--- Set the magic number in the trading structure
   trade.SetExpertMagicNumber(MagicNumber);
//--- Set the slippage in points
   trade.SetDeviationInPoints(CorrectValueBySymbolDigits(Deviation));
//--- The Instant Execution mode
//    A position can be opened with the Stop Loss and Take Profit levels set
   if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_INSTANT)
     {
      //--- If the position failed to open, print the relevant message
      if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment))
         Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
     }
//--- The Market Execution mode 
//    First open a position and only then set the Stop Loss and Take Profit levels
//    *** Starting with build 803, Stop Loss and Take Profit can be set upon position opening ***
   if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_MARKET)
     {
      //--- If there is no position, first open a position and then set Stop Loss and Take Profit
      if(!pos.exists)
        {
         //--- If the position failed to open, print the relevant message
         if(!trade.PositionOpen(_Symbol,order_type,lot,price,0,0,comment))
            Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
         //--- Get the flag of presence/absence of the position
         pos.exists=PositionSelect(_Symbol);
         //--- If the position exists
         if(pos.exists)
           {
            //--- Set Stop Loss and Take Profit
            if(!trade.PositionModify(_Symbol,sl,tp))
               Print("Error modifying the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
           }
        }
      //--- If the position exists, increase its volume and leave the Stop Loss and Take Profit levels unchanged
      else
        {
         //--- If the position failed to open, print the relevant message
         if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment))
            Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
        }
     }
  }

Dobbiamo ancora aggiungere il tocco finale e molto importante alle funzioni di gestione degli eventi:

  • OnInit
    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
      {
    //--- Adjust the input parameters
       CorrectInputParameters();
    //--- Get indicator handles
       GetIndicatorHandle();
    //--- Initialize the new bar
       CheckNewBar();
    //--- Get the properties
       GetPositionProperties(P_ALL);
    //--- Set the info panel
       SetInfoPanel();
    //---
       return(0);
      }
  • OnDeinit
    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
      {
    //--- Print the deinitialization reason to the journal
       Print(GetDeinitReasonText(reason));
    //--- When deleting from the chart
       if(reason==REASON_REMOVE)
         {
          //--- Delete all objects relating to the info panel from the chart
          DeleteInfoPanel();
          //--- Delete the indicator handle
          IndicatorRelease(indicator_handle);
         }
      }
  • OnTick
    //+------------------------------------------------------------------+
    //| Expert tick function                                             |
    //+------------------------------------------------------------------+
    void OnTick()
      {
    //--- If the bar is not new, exit
       if(!CheckNewBar())
         {
          if(IsVisualMode() || IsRealtime())
            {
             //--- Get the properties and update the values on the panel
             GetPositionProperties(P_ALL);
             //--- Set/update the info panel
             SetInfoPanel();
            }
          return;
         }
    
    //--- If there is a new bar
       else
         {
          //--- If trading is allowed
          if(CheckTradingPermission()==0)
            {
             if(!GetIndicatorsData())
                return;
             GetBarsData();          // Get bar data
             TradingBlock();         // Check the conditions and trade
             ModifyTrailingStop();   // Modify the Trailing Stop level
            }
         }
    //--- Get the properties
       GetPositionProperties(P_ALL);
    //--- Update the info panel
       SetInfoPanel();
      }

Ora che tutte le funzioni sono pronte, possiamo ottimizzare i parametri. Tieni presente che è necessario compilare il codice dal file di programma principale.

 

Ottimizzazione dei parametri e test expert advisor

Il tester strategico deve essere impostato come mostrato di seguito:

Fig. 1. Impostazioni di Strategy Tester.

Fig. 1. Impostazioni di Strategy Tester.

Inoltre, impostiamo i parametri di Expert Advisor per l'ottimizzazione (vedere anche il file *.set allegato con le impostazioni):

Fig. 2. Impostazioni dell'Expert Advisor.

Fig. 2. Impostazioni dell'Expert Advisor.

L'ottimizzazione ha richiesto circa 40 minuti su un processore dual-core. Il grafico di ottimizzazione consente di valutare in parte la qualità di un sistema di trading in base ai risultati nella zona di profitto:

Fig. 3. Grafico di ottimizzazione.

Fig. 3. Grafico di ottimizzazione.

I risultati del test del fattore di recupero massimo sono i seguenti:

Fig. 4. Risultati del test del fattore di recupero massimo.

Fig. 4. Risultati del test del fattore di recupero massimo.

 

Conclusione

Allegato all'articolo è l'archivio scaricabile con i codici sorgente dell'Expert Advisor. Una volta estratto, è necessario inserire la cartella del file \TestIndicatorConditions nel terminale <Metatrader 5>\MQL5\Experts. Per garantire il corretto funzionamento dell'Expert Advisor, l'indicatore MultiRange_PCH deve essere scaricato e inserito nel terminale <Metatrader 5 Terminal>\MQL5\Indicators.

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

L'indicatore ZigZag: Nuovo approccio e nuove soluzioni L'indicatore ZigZag: Nuovo approccio e nuove soluzioni
L'articolo esamina la possibilità di creare un indicatore ZigZag avanzato. L'idea di identificare i nodi si basa sull'uso dell'indicatore Inviluppo (Envelopes)a. Supponiamo di poter trovare una certa combinazione di parametri di input per una serie di inviluppo, per cui tutti i nodi ZigZag si trovano all'interno dei confini delle bande di Envelopes (inviluppo). Di conseguenza, possiamo provare a prevedere le coordinate del nuovo nodo.
Manuale MQL5: La cronologia delle offerte e la libreria di funzioni per ottenere proprietà di posizione Manuale MQL5: La cronologia delle offerte e la libreria di funzioni per ottenere proprietà di posizione
È il momento di riassumere brevemente le informazioni fornite nei precedenti articoli sulle proprietà della posizione. In questo articolo creeremo alcune funzioni aggiuntive per ottenere le proprietà che possono essere ottenute solo dopo aver effettuato l'accesso alla cronologia delle offerte. Acquisiremo anche familiarità con le strutture dati che ci consentiranno di accedere alle proprietà di posizione e simbolo in modo più comodo.
Manuale MQL5: Sviluppo di un framework per un sistema di trading basato sulla strategia a triplo schermo Manuale MQL5: Sviluppo di un framework per un sistema di trading basato sulla strategia a triplo schermo
In questo articolo, svilupperemo un framework per un sistema di trading basato sulla strategia Triple Screen in MQL5. L'Expert Advisor non sarà sviluppato da zero. Invece, modificheremo semplicemente il programma dal precedente articolo "Manuale MQL5: Utilizzo di indicatori per impostare le condizioni di trading in Expert Advisors" che già sostanzialmente serve al nostro scopo. Quindi l'articolo dimostrerà anche come è possibile modificare facilmente i modelli di programmi già pronti.
Manuale MQL5: Come evitare errori durante l'impostazione/modifica dei livelli di trading Manuale MQL5: Come evitare errori durante l'impostazione/modifica dei livelli di trading
In continuazione del nostro lavoro sull'Expert Advisor dal precedente articolo della serie chiamata "Manuale MQL5: Analizzando le proprietà della posizione nel tester di strategia MetaTrader 5", lo miglioreremo con un sacco di funzioni utili, oltre a migliorare e ottimizzare quelle esistenti. L'Expert Advisor questa volta avrà parametri esterni che possono essere ottimizzati nel MetaTrader 5 Strategy Tester e in qualche modo assomiglierà a un semplice sistema di trading.