English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
MQL5 Wizard (Procedura guidata): Effettuare ordini, stop-loss e Take Profit su prezzi calcolati. Estensione libreria standard

MQL5 Wizard (Procedura guidata): Effettuare ordini, stop-loss e Take Profit su prezzi calcolati. Estensione libreria standard

MetaTrader 5Esempi | 12 gennaio 2022, 11:21
473 0
Andrey Shpilev
Andrey Shpilev

Introduzione

La libreria standard MQL5 è un utile aiuto nello sviluppo di progetti di grandi dimensioni che richiedono un'architettura rigorosa. Una funzionalità molto importante è la procedura guidata MQL5 che consente di assemblare in pochi minuti parti già pronte in uno schema esteso in modalità dialogo. La procedura guidata MQL5 automatizza la raccolta di tutte le parti dell'Expert e dichiara automaticamente i parametri del modulo nell'Expert in base ai loro manci. Quando c'è un gran numero di moduli differenti, tale automazione consente di risparmiare molto tempo e molte operazioni di routine.

Tuttavia c'è un ovvio svantaggio: le capacità dei sistemi di trading creati con la procedura guidata basati su classi standard sono limitate. Questo articolo considera un metodo universale che consente di aumentare significativamente le funzionalità degli Expert creati. Quando questo metodo viene implementato, la compatibilità con la procedura guidata e i moduli standard rimane la stessa.

L'idea dietro a questo metodo è l'utilizzo di meccanismi di ereditarietà e polimorfismo nella programmazione orientata agli oggetti o la creazione di classi per sostituire le classi standard nel codice degli Expert generati. In questo modo vengono utilizzati tutti i vantaggi della procedura guidata e della libreria standard, il che si traduce nello sviluppo di un Expert con le funzionalità richieste. Per arrivarci, però, il codice deve essere ridotto di quattro stringhe.

Lo scopo pratico di questo articolo è aggiungere agli Expert generati, la capacità di effettuare ordini, Stop Loss e Take Profit ai livelli di prezzo richiesti, non solo alla distanza specificata dal prezzo corrente.

Un'idea simile è stata discussa nell'articolo "MQL5 Wizard: Come insegnare a un EA ad aprire ordini in sospeso a qualsiasi prezzo". Lo svantaggio significativo della soluzione suggerita è il cambiamento "forzato" del parametro del modulo del segnale di trading dal filtro subordinato. Questo approccio non favorisce il lavoro con molti moduli. Inoltre, l'utilizzo della procedura guidata per l'ottimizzazione dei processi in questo caso non ha molto senso.

L'implementazione di ordini di piazzamento, nonché Stop Loss e Take Profit a qualsiasi prezzo in classi ereditate da quelle standard è trattata in dettaglio più in basso. Detto questo, qualsiasi conflitto tra i moduli è impossibile. Spero che questo articolo serva da esempio e ispiri i lettori a contribuire scrivendo i propri miglioramenti del framework standard e consenta anche agli utenti di implementare l'estensione Library sviluppata.


1. Algoritmo standard del processo decisionale

Gli Expert, generati nella procedura guidata MQL5, si basano sull'istanza della classe CExpert. Il puntatore all'oggetto della classe CExpertSignal è dichiarato in questa classe. Più avanti nell'articolo questo oggetto è chiamato il segnale principale per brevità. Il segnale principale contiene puntatori ai filtri subordinati (i moduli di segnale sono gli eredi della classe CExpertSignal).

Se non ci sono posizioni e ordini aperti, l'Expert fa riferimento al segnale principale per verificare che ci sia l'opportunità di aprire una posizione su un nuovo tick. Il segnale principale interroga i filtri subordinati uno per uno e calcola la previsione media ponderata (direzione) in base alla previsione ottenuta. Se il suo valore supera la soglia (valore del parametro m_threshold_open nel segnale principale), i parametri dell'ordine e i risultati del controllo delle condizioni del tipo bool vengono passati all'Expert. Se queste condizioni sono soddisfatte, viene aperta una posizione sul prezzo di mercato o viene aperto un ordine in sospeso a una certa distanza da esso (vedi Fig. 1). Gli Stop Loss possono essere posizionati solo a una distanza fissa. Le indicazioni del prezzo di apertura, Stop Loss e Take Profit dal prezzo di mercato sono specificati nelle impostazioni Expert e memorizzati nel segnale principale, rispettivamente nelle variabili m_price_level, m_stop_level e m_take_level.

Quindi, attualmente al momento dell’effettuazione di un ordine devono essere soddisfatte due condizioni:

  1. Nessuna posizione deve essere aperta per il simbolo corrente;
  2. Il valore assoluto della previsione media ponderata deve superare il valore soglia, (il che significa che una tendenza è piuttosto forte).

Fig. 1. Modello del processo decisionale all'ingresso nel mercato

Fig. 1. Modello di processo decisionale al momento dell'ingresso nel mercato

L'attuale modello di processo decisionale in Fig. 1 limita significativamente l'area di applicazione della procedura guidata MQL5. Le strategie con valore fisso di Stop Loss sono raramente efficienti nel trading a lungo termine a causa della volatilità mutevole. I sistemi che impiegano ordini in sospeso di solito richiedono che questi ordini siano collocati su livelli calcolati dinamicamente.


2. Algoritmo modificato del processo decisionale

Dal punto di vista del calcolo dei livelli e dell'inoltro degli ordini, questa situazione non porterà a nulla, in quanto i moduli di segnale non possono generare altro che un valore di previsione. Inoltre, il segnale principale non è stato progettato per lavorare con i livelli. A tal proposito ti suggeriamo di:

  • Introdurre un nuovo tipo di moduli di segnale (li chiameremo moduli di prezzo) in grado di generare parametri di ordine;
  • Addestrare il segnale principale a gestire tali parametri, ovvero selezionare i migliori e trasmetterli all'Expert.

L'algoritmo modificato (Fig. 2) consente di lavorare con altre richieste oltre che con gli ordini in sospeso. L'essenza di questo algoritmo è la separazione del punto di ingresso (prezzo) dalla definizione di una tendenza (previsione media ponderata). Ciò significa che per prendere una decisione, viene definita la direzione preferita di trading con i filtri e viene selezionata una serie di parametri dell'ordine con una direzione adeguata ottenuta dai moduli di prezzo. Se sono disponibili diversi set simili, viene scelto il set ricevuto dal modulo con il peso maggiore (viene scelto il valore del parametro m_weight). Se la direzione è stata determinata ma non ci sono punti di ingresso attualmente disponibili, l'Expert è inattivo.

Fig. 2. Modello modificato del processo decisionale all'ingresso nel mercato

Fig. 2. Modello modificato del processo decisionale all'ingresso nel mercato

Per effettuare un nuovo ordine, devono essere soddisfatti i seguenti requisiti:

  1. Nessuna posizione deve essere aperta e non ci possono essere ordini aperti per il simbolo corrente;
  2. Il valore assoluto della previsione media ponderata deve superare il valore soglia;
  3. Deve essere stato trovato almeno un prezzo di apertura dell'ordine.

L'algoritmo della Fig. 2 consente di gestire molti possibili punti di ingresso, filtrandoli per direzione e scegliendo il migliore in un Expert.


3. Sviluppo di classi modificate dell'esperto e del modulo di segnale

L'estensione della Biblioteca si basa su due classi: CExpertSignalAdvanced e CExpertAdvanced, ereditati rispettivamente da CExpertSignal e CExpert.

Tutte le misure sull'aggiunta di nuove funzionalità volte a cambiare le interfacce utilizzate per lo scambio di dati tra diversi blocchi dell'Expert. Ad esempio, per implementare l'algoritmo dal modello in Fig.2 è necessario organizzare l'interazione del segnale principale (classe CExpertSignalAdvanced) con i moduli di prezzo (discendenti di quella classe). L'aggiornamento degli ordini già effettuati al cambio dei dati, implica l'interazione dell'Expert (classe CExpertAdvanced)con il segnale principale.

Quindi in questa fase implementeremo il modello in Fig. 2 per l'apertura delle posizioni e organizzeremo l'aggiornamento degli ordini già effettuati quando i parametri cambiano (ad esempio, quando appare un punto di ingresso più favorevole). Consideriamo la classe CExpertSignalAdvanced.

3.1. CExpertSignalAdvanced

Questa classe sostituirà il suo antenato nel ruolo del segnale principale e diventerà quello di base per i moduli di prezzo allo stesso modo in cui il suo antenato è di base per i moduli di segnale.

class CExpertSignalAdvanced : public CExpertSignal
  {
protected:
   //---data members for storing parameters of the orders being placed
   double            m_order_open_long;         //opening price of the order to buy
   double            m_order_stop_long;         //Stop Loss of the order to buy
   double            m_order_take_long;         //Take Profit of the order to buy
   datetime          m_order_expiration_long;   //expiry time of the order to buy
   double            m_order_open_short;        //opening price of the order to sell
   double            m_order_stop_short;        //Stop Loss of the order to sell
   double            m_order_take_short;        //Take Profit of the order to sell
   datetime          m_order_expiration_short;  //expiry time of the order to sell
   //---             
   int               m_price_module;            //index of the first price module in the m_filters array
public:
                     CExpertSignalAdvanced();
                    ~CExpertSignalAdvanced();
   virtual void      CalcPriceModuleIndex() {m_price_module=m_filters.Total();}
   virtual bool      CheckOpenLong(double &price,double &sl,double &tp,datetime &expiration);
   virtual bool      CheckOpenShort(double &price,double &sl,double &tp,datetime &expiration);
   virtual double    Direction(void);		//calculating weighted average forecast based on the data received from signal modules
   virtual double    Prices(void);		//updating of parameters of the orders being placed according to the data received from price modules
   virtual bool      OpenLongParams(double &price,double &sl,double &tp,datetime &expiration);
   virtual bool      OpenShortParams(double &price,double &sl,double &tp,datetime &expiration);
   virtual bool      CheckUpdateOrderLong(COrderInfo *order_ptr,double &open,double &sl,double &tp,datetime &ex);
   virtual bool      CheckUpdateOrderShort(COrderInfo *order_ptr,double &open,double &sl,double &tp,datetime &ex);
   double            getOpenLong()              { return m_order_open_long;         }
   double            getOpenShort()             { return m_order_open_short;        }
   double            getStopLong()              { return m_order_stop_long;         }
   double            getStopShort()             { return m_order_stop_short;        }
   double            getTakeLong()              { return m_order_take_long;         }
   double            getTakeShort()             { return m_order_take_short;        }
   datetime          getExpLong()               { return m_order_expiration_long;   }
   datetime          getExpShort()              { return m_order_expiration_short;  }
   double            getWeight()                { return m_weight;                  }
  };

I membri dei dati per l'archiviazione dei parametri dell'ordine sono stati dichiarati nella classe CExpertSignalAdvanced. I valori di queste variabili vengono aggiornati nel metodo Prices(). Queste variabili fungono da buffer.

Quindi viene dichiarato il parametro m_price_module. Questo memorizza l'indice del primo modulo di prezzo nella matrice m_filters dichiarata in CExpertSignal. Questa matrice contiene i puntatori ai moduli di segnale inclusi. I puntatori ai moduli standard (filtri) vengono memorizzati all'inizio della matrice. Quindi, a partire dall'indice m_price_module, arrivano i moduli di prezzo. Per evitare la necessità di modificare i metodi di inizializzazione di indicatori e timeseries, è stato deciso di archiviare tutto in un unico array. Inoltre, c'è la possibilità di includere 64 moduli attraverso un array, numero solitamente sufficiente.

Inoltre, nella classe CExpertSignalAdvanced sono stati dichiarati metodi helper per ottenere valori di membri di dati protetti. I loro nomi iniziano con get (vedi dichiarazione di classe).

3.1.1. Costruttore

Il costruttore CExpertSignalAdvanced inizializza le variabili dichiarate all'interno della classe:

CExpertSignalAdvanced::CExpertSignalAdvanced()
  {
   m_order_open_long=EMPTY_VALUE;
   m_order_stop_long=EMPTY_VALUE;
   m_order_take_long=EMPTY_VALUE;
   m_order_expiration_long=0;
   m_order_open_short=EMPTY_VALUE;
   m_order_stop_short=EMPTY_VALUE;
   m_order_take_short=EMPTY_VALUE;
   m_order_expiration_short=0;
   m_price_module=-1;
  }

3.1.2. CalcPriceModuleIndex()

Il metodo CalcPriceModuleIndex() assegna in m_price_module numero corrente di elementi di matrice, che è uguale all'indice del seguente modulo aggiunto. Questo metodo viene chiamato prima di aggiungere il primo modulo di prezzo. Il corpo della funzione si trova nella dichiarazione di classe.

virtual void      CalcPriceModuleIndex() {m_price_module=m_filters.Total();}

3.1.3. CheckOpenLong(...) e CheckOpenShort(...)

Il metodo CheckOpenLong(...) viene chiamato dall'istanza della classe CExpert e funziona come descritto di seguito:

  1. Controlla i moduli di prezzo inclusi. Se non ce ne sono, chiama il metodo omonimo della classe padre;
  2. Riceve previsioni medie ponderate (direzione) dal metodo Direction();
  3. Verifica se le condizioni di ingresso sono soddisfatte confrontando la direzione con EMPTY_VALUE e il valore soglia di m_threshold_open;
  4. Rinnova i valori dei parametri dell'ordine con il metodo Prices(), e li passa all'Expert con la funzione OpenLongParams(...). Salva il risultato di questa funzione;
  5. Restituisci il risultato salvato.
bool CExpertSignalAdvanced::CheckOpenLong(double &price,double &sl,double &tp,datetime &expiration)
  {
//--- if price modules were not found, call the method of the basic class CExpertSignal
   if(m_price_module<0)
      return(CExpertSignal::CheckOpenLong(price,sl,tp,expiration));

   bool   result   =false;
   double direction=Direction();
//--- prohibitive signal
   if(direction==EMPTY_VALUE)
      return(false);
//--- check for exceeding the threshold
   if(direction>=m_threshold_open)
     {
      Prices();
      result=OpenLongParams(price,sl,tp,expiration);//there's a signal if m_order_open_long!=EMPTY_VALUE
     }
//--- return the result
   return(result);
  }

CheckOpenShort(...) ha lo stesso principio di funzionamento e viene utilizzato allo stesso modo, per questo motivo non lo prenderemo in considerazione.

3.1.4 Direction()

Il metodo Direction() esegue query sui filtri e calcola la previsione media ponderata. Questo metodo è molto simile a un metodo eponimo della classe padre CExpertSignal con l'eccezione che nel ciclo non ci riferiamo a tutti gli elementi della matrice m_filters ma solo a quelli che hanno un indice che varia da 0 a quello inferiore a m_price_module. Tutto il resto è simile a CExpertSignal::D irection().

double CExpertSignalAdvanced::Direction(void)
  {
   long   mask;
   double direction;
   double result=m_weight*(LongCondition()-ShortCondition());
   int    number=(result==0.0)? 0 : 1;      // number of queried modules
//--- loop by filters
   for(int i=0;i<m_price_module;i++)
     {
      //--- mask for bitmaps (variables, containing flags)
      mask=((long)1)<<i;
      //--- checking for a flag of ignoring a filter signal
      if((m_ignore&mask)!=0)
         continue;
      CExpertSignal *filter=m_filters.At(i);
      //--- checking for a pointer
      if(filter==NULL)
         continue;
      direction=filter.Direction();
      //--- prohibitive signal
      if(direction==EMPTY_VALUE)
         return(EMPTY_VALUE);
      if((m_invert&mask)!=0)
         result-=direction;
      else
         result+=direction;
      number++;
     }
//--- averaging the sum of weighted forecasts
   if(number!=0)
      result/=number;
//--- return the result
   return(result);
  }

3.1.5. Prices()

Il metodo Prices() viene eseguito in iterazione sulla seconda parte della matrice m_filters a partire dall'indice m_price_module fino alla fine. Questo interroga i moduli di prezzo e rinnova i valori delle variabili di classe con le funzioni OpenLongParams(...) e OpenShortParams(...). Prima del ciclo, i valori dei parametri vengono cancellati.

Durante il ciclo, i valori dei parametri vengono sovrascritti se il peso del modulo di prezzo corrente (m_weight) è maggiore di quello dei moduli precedentemente interrogati, quelli che hanno fornito i valori. Di conseguenza, vengono lasciati parametri vuoti (se non è stato trovato nulla) o parametri con il miglior peso disponibile al momento della chiamata di un metodo.

double CExpertSignalAdvanced::Prices(void)
  {
   m_order_open_long=EMPTY_VALUE;
   m_order_stop_long=EMPTY_VALUE;
   m_order_take_long=EMPTY_VALUE;
   m_order_expiration_long=0;
   m_order_open_short=EMPTY_VALUE;
   m_order_stop_short=EMPTY_VALUE;
   m_order_take_short=EMPTY_VALUE;
   m_order_expiration_short=0;
   int    total=m_filters.Total();
   double last_weight_long=0;
   double last_weight_short=0;
//--- cycle for price modules
   for(int i=m_price_module;i<total;i++)
     {   
      CExpertSignalAdvanced *prm=m_filters.At(i);
      if(prm==NULL)
         continue;
//--- ignore the current module if it has returned EMPTY_VALUE
      if(prm.Prices()==EMPTY_VALUE)continue;
      double weight=prm.getWeight();
      if(weight==0.0)continue;
//--- select non-empty values from modules with the greatest weight
      if(weight>last_weight_long && prm.getExpLong()>TimeCurrent())
         if(prm.OpenLongParams(m_order_open_long,m_order_stop_long,m_order_take_long,m_order_expiration_long))
            last_weight_long=weight;
      if(weight>last_weight_short && prm.getExpShort()>TimeCurrent())
         if(prm.OpenShortParams(m_order_open_short,m_order_stop_short,m_order_take_short,m_order_expiration_short))
            last_weight_short=weight;
     }
   return(0);
  }

3.1.6. OpenLongParams(...) and OpenShortParams(...)

All'interno della classe CExpertSignalAdvanced, il metodo OpenLongParams(...) passa i valori dei parametri dell'ordine di acquisto per riferimento dalle variabili di classe ai parametri di input.

Il ruolo di questo metodo nella classe padre era leggermente diverso. Questo era il calcolo dei parametri richiesti in base al prezzo di mercato e alle rientranze specificate nel segnale principale. Ora questo passa solo parametri pronti. Se il prezzo di apertura è corretto (non uguale a EMPTY_VALUE), il metodo restituisce true, altrimenti false.

bool CExpertSignalAdvanced::OpenLongParams(double &price,double &sl,double &tp,datetime &expiration)
  {
   if(m_order_open_long!=EMPTY_VALUE)
     {
      price=m_order_open_long;
      sl=m_order_stop_long;
      tp=m_order_take_long;
      expiration=m_order_expiration_long;
      return(true);
     }
   return(false);
  }

Non prenderemo in considerazione OpenShortParams(...) poiché il suo principio di funzionamento è lo stesso e viene utilizzato in modo simile.

3.1.7. CheckUpdateOrderLong(...) e CheckUpdateOrderShort(...)

I metodi CheckUpdateOrderLong(...) e CheckUpdateOrderShort(...) sono denominati classe CExpertAdvanced. Vengono utilizzati per aggiornare un ordine già effettuato in sospeso in base agli ultimi livelli di prezzo.

Esamineremo più da vicino il metodo CheckUpdateOrderLong(...) Inizialmente i livelli di prezzo vengono aggiornati quando si chiama il metodo Prices (...), quindi viene effettuato un controllo per gli aggiornamenti dei dati per escludere possibili errori di modifica. Infine, viene richiesto il metodo OpenLongParams(...) per passare i dati aggiornati e restituire il risultato.

bool CExpertSignalAdvanced::CheckUpdateOrderLong(COrderInfo *order_ptr,double &open,double &sl,double &tp,datetime &ex)
  {
   Prices();   //update prices
//--- check for changes
   double point=m_symbol.Point();
   if(   MathAbs(order_ptr.PriceOpen() - m_order_open_long)>point
      || MathAbs(order_ptr.StopLoss()  - m_order_stop_long)>point
      || MathAbs(order_ptr.TakeProfit()- m_order_take_long)>point
      || order_ptr.TimeExpiration()!=m_order_expiration_long)
      return(OpenLongParams(open,sl,tp,ex));
//--- update is not required   
   return (false);
  }

CheckUpdateOrderShort(...) non sarà considerato in quanto funziona in modo simile ed è applicato allo stesso modo.

3.2. CExpertAdvanced

Le variazioni nella classe di Expert riguardano solo la modifica degli ordini già effettuati in base ai dati aggiornati sui prezzi nel segnale principale. La dichiarazione della classe CExpertAdvanced è presentata di seguito.

class CExpertAdvanced : public CExpert
  {
protected:
   virtual bool      CheckTrailingOrderLong();
   virtual bool      CheckTrailingOrderShort();
   virtual bool      UpdateOrder(double price,double sl,double tp,datetime ex);
public:
                     CExpertAdvanced();
                    ~CExpertAdvanced();
  };

Come possiamo vedere, i metodi sono pochi, il costruttore e il distruttore sono vuoti.

3.2.1. CheckTrailingOrderLong() and CheckTrailingOrderShort()

Il metodo CheckTrailingOrderLong() esegue l'override di un metodo eponimo della classe di base e chiama il metodo CheckUpdateOrderLong(...) del segnale principale per capire la necessità di modificare l'ordine. Se è necessaria una modifica, viene chiamato il metodo UpdateOrder(...) e il risultato viene restituito.

bool CExpertAdvanced::CheckTrailingOrderLong(void)
  {
   CExpertSignalAdvanced *signal_ptr=m_signal;
//--- check for the opportunity to modify the order to buy
   double price,sl,tp;
   datetime ex;
   if(signal_ptr.CheckUpdateOrderLong(GetPointer(m_order),price,sl,tp,ex))
      return(UpdateOrder(price,sl,tp,ex));
//--- return with no actions taken
   return(false);
  }

Il metodo CheckTrailingOrderShort() è simile e viene utilizzato allo stesso modo.

3.2.2. UpdateOrder()

La funzione UpdateOrder() inizia con il controllo di un prezzo pertinente (non EMPTY_VALUE). Se il prezzo non è presente, l'ordine viene eliminato, altrimenti l'ordine viene modificato in base ai parametri ricevuti.

bool CExpertAdvanced::UpdateOrder(double price,double sl,double tp,datetime ex)
  {
   ulong  ticket=m_order.Ticket();
   if(price==EMPTY_VALUE)
      return(m_trade.OrderDelete(ticket));
//--- modify the order, return the result
   return(m_trade.OrderModify(ticket,price,sl,tp,m_order.TypeTime(),ex));
  }

Lo sviluppo di eredi di classi standard è completo.


4. Sviluppo di moduli di prezzo

Abbiamo già la base per creare Expert che effettuino ordini e Stop Loss a livelli calcolati. Per essere precisi, abbiamo classi pronte all'uso per il lavoro con livelli di prezzo. Ora sono rimasti da scrivere solo i moduli per generare quei livelli.

Il processo di sviluppo dei moduli di prezzo è simile alla scrittura di moduli di segnali di trading. L'unica differenza tra loro è che è , Prices(), il metodo responsabile dell'aggiornamento dei prezzi all'interno del modulo, deve essere sovrascritto, non LongCondition(), ShortCondition() o Direction() come nei moduli di segnale. Idealmente, il lettore dovrebbe avere un'idea chiara sullo sviluppo dei moduli di segnale. Gli articoli "Crea il tuo robot di trading in 6 passaggi!" e "Generatore di segnali di trading basato su un indicatore personalizzato" possono essere utili in questo caso.

I codici di diversi moduli di prezzo serviranno da esempio.

4.1. Modulo di prezzo basato sull'indicatore "Delta ZigZag"

L'indicatore Delta ZigZag disegna i livelli in funzione del numero specificato dei diversi picchi più recenti. Se il prezzo supera quei livelli, ci potrebbe essere una probabile inversione di tendenza.

L'obiettivo del modulo di prezzo è quello di prendere il livello di ingresso dal buffer dell'indicatore, trovare l'estremo locale più vicino per posizionare Stop Loss, calcolare Take Profit moltiplicando Stop Loss per il coefficiente specificato nelle impostazioni.

Fig. 3. Illustrazione del funzionamento del modulo di prezzo sull'indicatore Delta ZigZag utilizzando l'ordine di acquisto come esempio

Fig. 3. Illustrazione del funzionamento del modulo di prezzo sull'indicatore Delta ZigZag utilizzando l'ordine di acquisto come esempio

Fig 3. rappresenta i livelli generati dal modulo prezzo. Prima che l'ordine si attivi, Stop Loss e Take Profit cambiano in seguito agli aggiornamenti del minimo.

4.1.1. Descrittore del modulo

// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=DeltaZZ Price Module                                       |
//| Type=SignalAdvanced                                              |
//| Name=DeltaZZ Price Module                                        |
//| ShortName=DeltaZZ_PM                                             |
//| Class=CPriceDeltaZZ                                              |
//| Page=not used                                                    |
//| Parameter=setAppPrice,int,1, Applied price: 0 - Close, 1 - H/L   |
//| Parameter=setRevMode,int,0, Reversal mode: 0 - Pips, 1 - Percent |
//| Parameter=setPips,int,300,Reverse in pips                        |
//| Parameter=setPercent,double,0.5,Reverse in percent               |
//| Parameter=setLevels,int,2,Peaks number                           |
//| Parameter=setTpRatio,double,1.6,TP:SL ratio                      |
//| Parameter=setExpBars,int,10,Expiration after bars number         |
//+------------------------------------------------------------------+
// wizard description end

I primi cinque parametri del descrittore sono necessari per impostare l'indicatore in uso. Poi arriva il coefficiente per il calcolo del Take Profit in base allo Stop Loss e al tempo di scadenza nelle barre per gli ordini dal modulo di prezzo corrente.

4.1.2. Dichiarazioni della classe

class CPriceDeltaZZ : public CExpertSignalAdvanced
  {
protected:
   CiCustom          m_deltazz;           //object of the DeltaZZ indicator
   //--- module settings
   int               m_app_price;
   int               m_rev_mode;
   int               m_pips;
   double            m_percent;
   int               m_levels;
   double            m_tp_ratio;          //tp:sl ratio
   int               m_exp_bars;          //lifetime of the orders in bars
   //--- method of indicator initialization
   bool              InitDeltaZZ(CIndicators *indicators);
   //--- helper methods
   datetime          calcExpiration() { return(TimeCurrent()+m_exp_bars*PeriodSeconds(m_period)); }
   double            getBuySL();          //function for searching latest minimum of ZZ for buy SL
   double            getSellSL();         //function for searching latest maximum of ZZ for sell SL
public:
                     CPriceDeltaZZ();
                    ~CPriceDeltaZZ();
   //--- methods of changing module settings
   void              setAppPrice(int ap)           { m_app_price=ap; }
   void              setRevMode(int rm)            { m_rev_mode=rm;  }
   void              setPips(int pips)             { m_pips=pips;    }
   void              setPercent(double perc)       { m_percent=perc; }
   void              setLevels(int rnum)           { m_levels=rnum;  }
   void              setTpRatio(double tpr)        { m_tp_ratio=tpr; }
   void              setExpBars(int bars)          { m_exp_bars=bars;}
   //--- method of checking correctness of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating indicators
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- main method of price module updating the output data
   virtual double    Prices();
  }; 

Dati protetti - l’oggetto dell'indicatore del tipo CiCustom e i parametri in base ai tipi specificati nel descrittore sono dichiarati nel modulo.

4.1.3. Costruttore

Il costruttore inizializza i parametri della classe con valori predefiniti. Successivamente, questi valori vengono inizializzati ancora una volta quando il modulo viene incluso nel segnale principale in base ai parametri di ingresso dell'Expert.

CPriceDeltaZZ::CPriceDeltaZZ() : m_app_price(1),
                                 m_rev_mode(0),
                                 m_pips(300),
                                 m_percent(0.5),
                                 m_levels(2),
                                 m_tp_ratio(1),
                                 m_exp_bars(10)
  {
  }

4.1.4. ValidationSettings()

ValidationSettings() è un metodo importante per il controllo dei parametri di input. Se i valori dei parametri del modulo non sono validi, viene restituito il risultato false e viene stampato un messaggio di errore nel journal.

bool CPriceDeltaZZ::ValidationSettings(void)
  {
//--- checking for settings of additional filters
   if(!CExpertSignal::ValidationSettings())
      return(false);
//--- initial data check
   if(m_app_price<0 || m_app_price>1)
     {
      printf(__FUNCTION__+": Applied price must be 0 or 1");
      return(false);
     }
   if(m_rev_mode<0 || m_rev_mode>1)
     {
      printf(__FUNCTION__+": Reversal mode must be 0 or 1");
      return(false);
     }
   if(m_pips<10)
     {
      printf(__FUNCTION__+": Number of pips in a ray must be at least 10");
      return(false);
     }
   if(m_percent<=0)
     {
      printf(__FUNCTION__+": Percent must be greater than 0");
      return(false);
     }
   if(m_levels<1)
     {
      printf(__FUNCTION__+": Ray Number must be at least 1");
      return(false);
     }
   if(m_tp_ratio<=0)
     {
      printf(__FUNCTION__+": TP Ratio must be greater than zero");
      return(false);
     }
   if(m_exp_bars<0)
     {
      printf(__FUNCTION__+": Expiration must be zero or positive value");
      return(false);
     }
//--- parameter check passed
   return(true);
  } 

4.1.5. InitIndicators(...)

Il metodo InitIndicators(...) chiama un metodo omonimo della classe base e inizializza l'indicatore del modulo corrente con il metodo InitDeltaZZ(...).

bool CPriceDeltaZZ::InitIndicators(CIndicators *indicators)
  {
//--- initialization of indicator filters
   if(!CExpertSignal::InitIndicators(indicators))
      return(false);
//--- creating and initializing of custom indicator
   if(!InitDeltaZZ(indicators))
      return(false);
//--- success
   return(true);
  }

4.1.6. InitDeltaZZ(...)

Il metodo InitDeltaZZ(...) aggiunge l'oggetto dell'indicatore personalizzato alla raccolta e crea il nuovo indicatore "Delta ZigZag".

bool CPriceDeltaZZ::InitDeltaZZ(CIndicators *indicators)
  {
//--- adds to collection
   if(!indicators.Add(GetPointer(m_deltazz)))
     {
      printf(__FUNCTION__+": error adding object");
      return(false);
     }
//--- specifies indicator parameters
   MqlParam parameters[6];
//---
   parameters[0].type=TYPE_STRING;
   parameters[0].string_value="deltazigzag.ex5";
   parameters[1].type=TYPE_INT;
   parameters[1].integer_value=m_app_price;
   parameters[2].type=TYPE_INT;
   parameters[2].integer_value=m_rev_mode;
   parameters[3].type=TYPE_INT;
   parameters[3].integer_value=m_pips;
   parameters[4].type=TYPE_DOUBLE;
   parameters[4].double_value=m_percent;
   parameters[5].type=TYPE_INT;
   parameters[5].integer_value=m_levels;
//--- object initialization
   if(!m_deltazz.Create(m_symbol.Name(),m_period,IND_CUSTOM,6,parameters))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
//--- number of the indicator buffers
   if(!m_deltazz.NumBuffers(5)) return(false);
//--- ок
   return(true);
  }

Dopo aver completato con successo i metodi ValidationSettings(),, InitDeltaZZ(...) e InitIndicators(...), il modulo viene inizializzato ed è pronto per il lavoro.

4.1.7. Prices()

Questo è un metodo di base per il modulo prezzo. Questo è il posto giusto in cui i parametri dell'ordine vengono aggiornati. I loro valori vengono trasmessi al segnale principale. Questo metodo restituisce il risultato dell'operazione del tipo doppio. Questo è stato implementato principalmente per uno sviluppo futuro. Il risultato del metodo Price() può codificare alcune situazioni ed eventi particolari in modo che il segnale principale possa gestirli di conseguenza. Attualmente è prevista solo la gestione del valore restituito EMPTY_VALUE. Dopo aver ricevuto questo risultato, il segnale principale ignorerà i parametri suggeriti dal modulo.

Algoritmo di funzionamento del metodo Prices() in questo modulo:

  1. Prendi i prezzi di apertura degli ordini dai buffer indicatori 3 e 4, rispettivamente per l'acquisto e la vendita;
  2. Azzera i parametri finali degli ordini;
  3. Controlla il prezzo per l’acquisto. Se ce n'è uno, identifica il livello per posizionare lo Stop Loss con il metodo getBuySL(), calcola il livello di Take Profit in base al valore di Stop Loss e al prezzo di apertura e calcola il tempo di scadenza dell'ordine;
  4. Controlla il prezzo di vendita. Se rilevato, trova il livello per posizionare Stop Loss con il metodo getSellSL(), calcola il livello di Take Profit in base al valore dello Stop Loss e al prezzo di lancio e calcola il tempo di scadenza dell'ordine;
  5. Esci
Le condizioni di presenza dei prezzi di acquisto e di vendita si escludono a vicenda a causa di alcuni aspetti operativi dell'indicatore "Delta ZigZag". I buffer 3 e 4 sono disegnati come punti per impostazione predefinita (vedere la Fig. 3).

double CPriceDeltaZZ::Prices(void)
  {
   double openbuy =m_deltazz.GetData(3,0);//receive the last value from buffer 3
   double opensell=m_deltazz.GetData(4,0);//receive the last value from buffer 4
//--- clear parameter values
   m_order_open_long=EMPTY_VALUE;
   m_order_stop_long=EMPTY_VALUE;
   m_order_take_long=EMPTY_VALUE;
   m_order_expiration_long=0;
   m_order_open_short=EMPTY_VALUE;
   m_order_stop_short=EMPTY_VALUE;
   m_order_take_short=EMPTY_VALUE;
   m_order_expiration_short=0;
   int digits=m_symbol.Digits();
//--- check for the prices to buy
   if(openbuy>0)//if buffer 3 is not empty
     {
      m_order_open_long=NormalizeDouble(openbuy,digits);
      m_order_stop_long=NormalizeDouble(getBuySL(),digits);
      m_order_take_long=NormalizeDouble(m_order_open_long + m_tp_ratio*(m_order_open_long - m_order_stop_long),digits);
      m_order_expiration_long=calcExpiration();
     }
//--- check for the prices to sell
   if(opensell>0)//if buffer 4 is not empty
     {
      m_order_open_short=NormalizeDouble(opensell,digits);
      m_order_stop_short=NormalizeDouble(getSellSL(),digits);
      m_order_take_short=NormalizeDouble(m_order_open_short - m_tp_ratio*(m_order_stop_short - m_order_open_short),digits);
      m_order_expiration_short=calcExpiration();
     }
   return(0);
  }

4.1.8. getBuySL() and getSellSL()

I metodi getBuySL() e getSellSL() sono alla ricerca dei rispettivi minimi e massimi locali per inserire lo Stop Loss. L'ultimo valore diverso da zero in un buffer di riferimento - il livello di prezzo dell'ultimo estremo locale è ricercato in ogni metodo.

double CPriceDeltaZZ::getBuySL(void)
  {
   int i=0;
   double sl=0.0;
   while(sl==0.0)
     {
      sl=m_deltazz.GetData(0,i);
      i++;
     }
   return(sl);
  }
double CPriceDeltaZZ::getSellSL(void)
  {
   int i=0;
   double sl=0.0;
   while(sl==0.0)
     {
      sl=m_deltazz.GetData(1,i);
      i++;
     }
   return(sl);
  }

4.2. Modulo di prezzo basato sulla Barra Interna (Inside Bar)

La barra interna è uno dei modelli ampiamente utilizzati nel trading senza indicatori chiamato Azione dei prezzi. Una barra interna è una barra con Alto e Basso all'interno dell'estremità della barra precedente. Una barra interna indica l'inizio della stabilizzazione o la possibile inversione del movimento dei prezzi.

In Fig. 4 le barre interne sono all'interno di ellissi rosse. Quando viene rilevata una barra interna, il modulo prezzo genera i prezzi di apertura degli ordini buystop e sellstop alle estremità della barra che precede la barra interna.

I prezzi di apertura sono i livelli di Stop Loss per gli ordini opposti. Take Profit viene calcolato come nel modulo discusso sopra - moltiplicando il livello di Stop Loss per il coefficiente specificato nelle impostazioni. I prezzi di apertura e gli Stop Loss sono contrassegnati con linee orizzontali rosse e i Take Profit con quelle verdi.

Fig. 4. Illustrazione delle barre interne e dei livelli del modulo dei prezzi

Fig. 4. Illustrazione delle barre interne e dei livelli del modulo dei prezzi

In Fig. 4 gli ordini di vendita non vengono inseriti in quanto la tendenza è in ascesa. Tuttavia, il modulo dei prezzi genera livelli di ingresso in entrambe le direzioni. Alcuni livelli di Take Profit sono al di fuori della griglia.

A differenza del modulo precedente, l'algoritmo di questo modulo è semplice e non richiede l'inizializzazione degli indicatori. C'è poco codice nel modulo, questo sarà presentato di seguito per intero. Tuttavia, non analizzeremo ogni funzione separatamente.

#include <Expert\ExpertSignalAdvanced.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Inside Bar Price Module                                    |
//| Type=SignalAdvanced                                              |
//| Name=Inside Bar Price Module                                     |
//| ShortName=IB_PM                                                  |
//| Class=CPriceInsideBar                                            |
//| Page=not used                                                    |
//| Parameter=setTpRatio,double,2,TP:SL ratio                        |
//| Parameter=setExpBars,int,10,Expiration after bars number         |
//| Parameter=setOrderOffset,int,5,Offset for open and stop loss     |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CPriceInsideBar                                            |
//| Purpose: Class of the generator of price levels for orders based |
//|          on the "inside bar" pattern.                            |
//| Is derived from the CExpertSignalAdvanced class.                 |
//+------------------------------------------------------------------+
class CPriceInsideBar : public CExpertSignalAdvanced
  {
protected:
   double            m_tp_ratio;          //tp:sl ratio
   int               m_exp_bars;          //lifetime of the orders in bars
   double            m_order_offset;      //shift of the opening and Stop Loss levels
   datetime          calcExpiration()  { return(TimeCurrent()+m_exp_bars*PeriodSeconds(m_period)); }
public:
                     CPriceInsideBar();
                    ~CPriceInsideBar();
   void              setTpRatio(double ratio){ m_tp_ratio=ratio; }
   void              setExpBars(int bars)    { m_exp_bars=bars;}
   void              setOrderOffset(int pips){ m_order_offset=m_symbol.Point()*pips;}
   bool              ValidationSettings();
   double            Prices();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CPriceInsideBar::CPriceInsideBar()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CPriceInsideBar::~CPriceInsideBar()
  {
  }
//+------------------------------------------------------------------+
//| Validation of protected settings                                 |
//+------------------------------------------------------------------+
bool CPriceInsideBar::ValidationSettings(void)
  {
//--- verification of the filter parameters
   if(!CExpertSignal::ValidationSettings())
      return(false);
//--- initial data check
  if(m_tp_ratio<=0)
     {
      printf(__FUNCTION__+": TP Ratio must be greater than zero");
      return(false);
     }
   if(m_exp_bars<0)
     {
      printf(__FUNCTION__+": Expiration must be zero or positive value");
      return(false);
     }
//--- check passed
   return(true);
  }
//+------------------------------------------------------------------+
//| Price levels refreshing                                          |
//+------------------------------------------------------------------+
double CPriceInsideBar::Prices(void)
  {
   double h[2],l[2];
   if(CopyHigh(m_symbol.Name(),m_period,1,2,h)!=2 || CopyLow(m_symbol.Name(),m_period,1,2,l)!=2)
      return(EMPTY_VALUE);
//--- check for inside bar      
   if(h[0] >= h[1] && l[0] <= l[1])
     {
      m_order_open_long=h[0]+m_order_offset;
      m_order_stop_long=l[0]-m_order_offset;
      m_order_take_long=m_order_open_long+(m_order_open_long-m_order_stop_long)*m_tp_ratio;
      m_order_expiration_long=calcExpiration();
      
      m_order_open_short=m_order_stop_long;
      m_order_stop_short=m_order_open_long;
      m_order_take_short=m_order_open_short-(m_order_stop_short-m_order_open_short)*m_tp_ratio;
      m_order_expiration_short=m_order_expiration_long;
      return(0);
     }
   return(EMPTY_VALUE);
  }  
//+------------------------------------------------------------------+

Nel metodo Price() di questo modulo, la restituzione del risultato EMPTY_VALUE viene utilizzata per provare al segnale principale che non ci sono livelli di prezzo disponibili.

4.3. Modulo di prezzo basato sulla Outside Bar (barra esterna)

La barra esterna è un altro modello molto usato di Price Action chiamato anche "assorbimento". La barra esterna è chiamata così perché i suoi punti più alti e più bassi si sovrappongono a quelli più alti e più bassi della barra precedente. L'aspetto di una barra esterna mostra l'aumento della volatilità seguito da un movimento diretto dei prezzi.

In Fig. 5 le barre esterne sono contrassegnate da ellissi rosse. Dopo aver rilevato una barra esterna, il modulo prezzo genera i prezzi di apertura degli ordini buystop e sellstop sui suoi estremi

I prezzi di apertura sono i livelli di Stop Loss per gli ordini opposti. Take Profit viene calcolato come nel modulo discusso sopra - moltiplicando il livello di Stop Loss per il coefficiente specificato nelle impostazioni. I prezzi di apertura e gli Stop Loss sono contrassegnati con linee orizzontali rosse e i Take Profit con quelle verdi.

Fig. 5. Illustrazione delle barre esterne e dei livelli dei moduli di prezzo

Fig. 5. Illustrazione delle barre esterne e dei livelli dei moduli di prezzo

In Fig. 5 le barre esterne sono contrassegnate da ellissi rosse. Le linee orizzontali mostrano i prezzi di apertura degli ordini in sospeso generati dal modulo prezzi.

In questo caso, vengono aperti solo gli ordini di vendita perché il trend è in ribasso. Il funzionamento di questo modulo è essenzialmente simile al precedente. L'unica differenza nel suo codice è solo il metodo Prices(), le altre parti sono esattamente le stesse e hanno gli stessi nomi. Di seguito è riportato il codice di Prices().

double CPriceOutsideBar::Prices(void)
{
   double h[2],l[2];
   if(CopyHigh(m_symbol.Name(),m_period,1,2,h)!=2 || CopyLow(m_symbol.Name(),m_period,1,2,l)!=2)
      return(EMPTY_VALUE);
//--- check of outside bar
   if(h[0] <= h[1] && l[0] >= l[1])
   {
      m_order_open_long=h[1]+m_order_offset;
      m_order_stop_long=l[1]-m_order_offset;
      m_order_take_long=m_order_open_long+(m_order_open_long-m_order_stop_long)*m_tp_ratio;
      m_order_expiration_long=calcExpiration();
      
      m_order_open_short=m_order_stop_long;
      m_order_stop_short=m_order_open_long;
      m_order_take_short=m_order_open_short-(m_order_stop_short-m_order_open_short)*m_tp_ratio;
      m_order_expiration_short=m_order_expiration_long;
      return(0);
   }
   return(EMPTY_VALUE);
} 

4.4. Test delle prestazioni del modulo

Nella sezione successiva vengono testati tre esempi di moduli. Prima vengono testati singolarmente, poi tutti e tre insieme come unico Expert, per assicurarsi che il sistema funzioni come da progetto. Di conseguenza, vengono generati quattro Expert. Il modulo del segnale di trading basato sull'indicatore Awesome Oscillator che lavora sul timeframe H12 viene utilizzato come filtro in ciascuno degli esperti generati. I moduli di prezzo lavorano su H6.

Gestione del denaro: lotto fisso e Trailing Stop non vengono utilizzati. Tutti i test vengono effettuati sulle quotazioni EURUSD dal conto demo del server MetaQuotes-Demo per il periodo dal 2013.01.01 al 2014.06.01. Versione del terminale: 5.00, build 965 (27 giugno 2014).

Per brevità, i risultati dei test sono rappresentati solo da grafici di equilibrio. Questi bastano per capire il comportamento dell'Esperto in ogni caso particolare.

4.4.1. Test del modulo basato sull'indicatore Delta ZigZag

Fig. 6. Grafico di equilibrio generato dal test del modulo di prezzo basato su Delta ZigZag

Fig. 6. Grafico di equilibrio generato dal test del modulo di prezzo basato sull'indicatore "Delta ZigZag"

4.4.2. Test del modulo basato sul modello "Inside Bar"

Fig. 7. Grafico di equilibrio generato dal test del modulo di prezzo, basato sulla barra interna

Fig. 7. Grafico di equilibrio generato dal test del modulo di prezzo basato sulla barra interna

Guardando la Fig. 7., va tenuto presente che lo scopo dei test in questa fase è quello di verificare le prestazioni del codice, non di ottenere una strategia vincente.

4.4.3. Test del modulo basato sul modello "Outside Bar"

Fig. 8. Grafico di equilibrio generato dal test del modulo del prezzo in base alla barra esterna

Fig. 8. Grafico di equilibrio generato dal test del modulo del prezzo in base alla barra esterna

4.4.4. Test del lavoro congiunto dei moduli di prezzo

Prendendo in considerazione i risultati dei test precedenti, i moduli di prezzo basati su DeltaZigZag, barra interna ed barra esterna hanno ricevuto coefficienti di peso rispettivamente di 1, 0,5 e 0,7. I coefficienti di peso definiscono le priorità dei moduli di prezzo.

Fig. 9. Grafico di equilibrio generato dal test dell'Expert con tre moduli di prezzo

Fig. 9. Grafico di equilibrio generato dal test dell'Expert con tre moduli di prezzo

In ogni fase del test, tutte le operazioni eseguite sui grafici dei prezzi vengono attentamente analizzate. Gli errori e le deviazioni della strategia non sono stati provocati volontariamente. Tutti i programmi utilizzati sono allegati a questo articolo, ti invitiamo a testarli.


5. Istruzioni per l'uso

Ora prenderemo in considerazione le fasi dello sviluppo dell’Expert, utilizzando l'estensione sviluppata sull'esempio dell’Expert con tre moduli di prezzo e Awesome Oscillator come filtro.

Prima dell'inizio della generazione, assicurati che i file di intestazione "CExpertAdvanced.mqh" e "CExpertSignalAdvanced.mqh" siano nel catalogo del terminale MetaTrader 5 nella cartella MQL5/Include/Expert e i file dei moduli di prezzo siano nella cartella MQL5/Include/Expert/MySignal. Prima di avviare l'Expert, assicurati che gli indicatori compilati si trovino nella cartella MQL5/Indicatori. In questo caso si tratta del file "DeltaZigZag.ex5". Nell'archivio in allegato, tutti i file sono al loro posto. Non dovremo fare altro che decomprimere questo archivio in una cartella con il terminale MetaTrader 5 e confermare l'unione dei cataloghi.

5.1. Creazione dell’Expert

Per avviare la creazione dell’Expert, selezionare "File"->"Nuovo" nel MetaEditor.

Fig. 10. Creazione di un nuovo Expert utilizzando la procedura guidata(Wizard) MQL5

Fig. 10. Creazione di un nuovo Expert mediante la procedura guidata MQL5

Nella nuova finestra selezionare "Expert Advisor (genera)" e quindi premere "Avanti".


Fig. 11. Generazione di un Expert utilizzando la procedura guidata MQL5 (Wizard)

Fig. 11. Generazione di un Expert utilizzando la procedura guidata MQL5 (Wizard)

Verrà visualizzata una finestra in cui è possibile specificare il nome. In questo particolare esempio, il nome dell'Expert è "TEST_EA_AO_DZZ_IB_OB", i parametri Symbol e TimeFrame hanno valori predefiniti. Quindi fare clic su OK.

Fig. 12. Parametri comuni dell'Expert Advisor


Fig. 12. Proprietà generali dell'Expert Advisor

Nella finestra visualizzata aggiungi i moduli uno per uno premendo "Aggiungi". L'intero processo è mostrato qui di seguito.

NOTA BENE! Quando aggiungi moduli, in un primo momento includi tutti i moduli di segnale (eredi CExpertSignal) e poi i moduli di prezzo (eredi CExpertSignalAdvanced). È impossibile prevedere cosa succederà se questo ordine di inclusione/aggiunta non sarà rispettato.

Quindi, iniziamo con l'inclusione di moduli di segnali da Awesome Oscillator. È l'unico filtro in questo esempio.

Fig. 13. Aggiunta del modulo di segnali di Awesome Oscillator

Fig. 13. Aggiunta del modulo di segnali di Awesome Oscillator

Aggiungi i moduli di prezzo richiesti in un ordine casuale dopo che tutti i moduli di segnale sono stati inclusi. Ce ne sono tre in questo esempio.

Fig. 14. Aggiunta del modulo di segnali del DeltaZZ Price Module

Fig. 14. Aggiunta del modulo di segnali di DeltaZZ Price Module


Fig. 15. Aggiunta del modulo di segnali del DeltaZZ Price Module

Fig. 15. Aggiunta del modulo di segnali da Inside Bar Price Module


Fig. 16. Aggiunta del modulo di segnali dal modulo di prezzo della Barra Esterna

Fig. 16. Aggiunta del modulo di segnali dal modulo di prezzo della barra esterna

Dopo aver aggiunto tutti i moduli, apparirà questa finestra:

Fig. 17. Elenco dei moduli inclusi dei segnali di trading

Fig. 17. Elenco dei moduli inclusi dei segnali di trading

Il valore del parametro "Peso" per il modulo prezzo ne definisce la priorità.

Dopo aver premuto il pulsante "Avanti", la procedura guidata suggerirà di selezionare i moduli di gestione del denaro e i moduli Trailing Stop. Seleziona uno di questi o lascia tutto così com'è, premendo "Next" o "Ready".

Premendo "Ready" riceverai il codice generato di Advisor.

5.2. Modifica del codice generato

A questo punto abbiamo il codice.

1. Troverai la stringa all'inizio

#include <Expert\Expert.mqh>

e modificala in modo che assomigli a

#include <Expert\ExpertAdvanced.mqh>

È necessario includere i file delle classi sviluppate.

2. Quindi trova la stringa

CExpert ExtExpert;

e cambia in

CExpertAdvanced ExtExpert;

Questo cambierà la classe standard dell’Expert per il suo discendente con le funzioni richieste.

3. Ora trova la stringa

CExpertSignal *signal=new CExpertSignal;

e cambia in

CExpertSignalAdvanced *signal=new CExpertSignalAdvanced;

Questo è il metodo per cambiare la classe standard del segnale principale per il suo discendente con le funzioni richieste.

4. Trova la stringa che implementa l'aggiunta del primo modulo di prezzo all'array m_filters del segnale principale. In questo esempio, si presenta in questo modo:

signal.AddFilter(filter1);

Prima di questo inseriamo la stringa

signal.CalcPriceModuleIndex();

Questo è necessario per il segnale principale per riconoscere fino a quale indice nell'array m_filters ci sono puntatori di moduli di segnale e a partire da quale indice ci sono puntatori di moduli di prezzo.

Trovare la posizione giusta per l'inserimento della stringa specificata può essere difficile. Usa il numero dopo la parola "filtro" come punto di riferimento. Semplificherà la ricerca e permetterà di non perdere la giusta posizione. I nomi della procedura guidata MQL5 includevano automaticamente i moduli nel loro ordine. Il primo modulo si chiama filter0,, il secondo – filter1, il terzo – filter2 ecc. Nel nostro caso c'è un solo modulo di segnale. Pertanto, il primo modulo di prezzo incluso è il numero due e dobbiamo cercare la stringa "signal.AddFilter(filter1);" per l'aggiunta del filtro in quanto la numerazione nel codice inizia da zero. L'illustrazione è in Fig. 18:

Fig. 18. Nomi dei moduli in codice secondo l'ordine di inclusione

Fig. 18. Nomi dei moduli in codice secondo l'ordine di inclusione

5. Questa parte non è obbligatoria. Attraverso le modifiche introdotte, i parametri degli Expert responsabili delle rientranze dei prezzi di apertura, stop loss, take profit e tempo di scadenza degli ordini non sono più utilizzabili. Per rendere il codice più compatto, è possibile eliminare le stringhe seguenti:

input double Signal_PriceLevel            =0.0;                    // Price level to execute a deal
input double Signal_StopLevel             =50.0;                   // Stop Loss level (in points)
input double Signal_TakeLevel             =50.0;                   // Take Profit level (in points)
input int    Signal_Expiration            =4;                      // Expiration of pending orders (in bars)

L'errore di compilazione riscontrato dopo aver eliminato le stringhe precedenti, ci porta a dover eliminare il gruppo successivo di stringhe:

   signal.PriceLevel(Signal_PriceLevel);
   signal.StopLevel(Signal_StopLevel);
   signal.TakeLevel(Signal_TakeLevel);
   signal.Expiration(Signal_Expiration);

Dopo che quest'ultimo è stato eliminato, la compilazione avrà successo.

Commenti e spiegazioni sulle modifiche possono essere trovati nel codice allegato dell'Expert "TEST_EA_AO_DZZ_IB_OB". Le stringhe del codice che possono essere eliminate hanno commenti di accompagnamento.


Conclusione

In questo articolo è stata ampliata in modo significativo l'area di applicazione della procedura guidata MQL5. Ora può essere utilizzata per l'ottimizzazione dello sviluppo di sistemi di trading automatico che richiedono l'effettuazione di ordini, Stop Loss e Take Profit a diversi livelli di prezzo indipendentemente dal prezzo corrente.

Gli Expert generati possono includere una serie di moduli di prezzo che calcolano i parametri degli ordini inviati. Il set di parametri più adatto viene selezionato tra quelli disponibili. Le preferenze sono specificate nelle impostazioni. Permette di utilizzare molti punti di ingresso differenti con la massima efficienza. Questo approccio rende gli Expert selettivi. Se la direzione è nota ma il punto di ingresso non è definito, l'Expert attenderà che esso appaia.

L'introduzione di moduli standard compatibili, responsabili della ricerca dei livelli di prezzo è un vantaggio significativo e ha lo scopo di semplificare lo sviluppo degli Expert. Anche se al momento ci sono solo tre moduli, il loro numero aumenterà sicuramente col passare del tempo. Se hai trovato utile questo articolo, suggerisci algoritmi di funzionamento dei moduli di prezzo nei commenti. Idee interessanti saranno implementate nel codice.

In questo articolo viene inoltre utilizzato un metodo per un'ulteriore estensione delle funzionalità di Expert sviluppate nella procedura guidata. L'ereditarietà è il modo ottimale per introdurre cambiamenti.

Gli utenti senza competenze di programmazione ma in grado di modificare il codice seguendo le istruzioni, avranno l'opportunità di creare Expert più evoluti in base ai modelli disponibili.

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

Come preparare un Account di trading per la migrazione sull'Hosting Virtuale Come preparare un Account di trading per la migrazione sull'Hosting Virtuale
Il terminale cliente MetaTrader è perfetto per automatizzare le strategie di trading. Possiede tutti gli strumenti necessari per gli sviluppatori di trading robot ‒ potente linguaggio di programmazione MQL4/MQL5 basato su C++, comodo ambiente di sviluppo MetaEditor e tester di strategia multi-thread che supporta il calcolo distribuito in MQL5 Cloud Network. In questo articolo scoprirai come trasferire il tuo terminale cliente verso l’ambiente virtuale mantenendo tutti gli elementi personalizzati.
Come accedere al database MySQL da MQL5 (MQL4) Come accedere al database MySQL da MQL5 (MQL4)
L'articolo descrive lo sviluppo di un'interfaccia tra MQL e il database MySQL. Espone le soluzioni pratiche esistenti e offre un modo più conveniente per implementare una libreria da utilizzare per lavorare con i database. L'articolo contiene una descrizione dettagliata delle funzioni, della struttura dell'interfaccia, degli esempi e di alcune caratteristiche specifiche per lavorare con MySQL. Per quanto riguarda le soluzioni software, gli allegati agli articoli includono i file delle librerie dinamiche, la documentazione ed esempi di script per i linguaggi MQL4 e MQL5.
Suggerimenti per una presentazione efficace del prodotto sul Market Suggerimenti per una presentazione efficace del prodotto sul Market
Per vendere programmi ai trader in modo efficace, non basta solo creare un prodotto efficiente e utile e pubblicarlo sul Market. È fondamentale fornire una descrizione completa e dettagliata e allegare le giuste illustrazioni. Un logo di qualità e i giusti screenshot sono importanti come la fase di codifica vera e propria Ricorda questa formula semplice: nessun download = nessuna vendita.
Costruire una startup di tecnologia sociale, parte I: Twitta i tuoi segnali MetaTrader 5 Costruire una startup di tecnologia sociale, parte I: Twitta i tuoi segnali MetaTrader 5
Oggi impareremo come collegare un terminale MetaTrader 5 con Twitter in modo da poter twittare i segnali di trading dei tuoi EA. Stiamo sviluppando un Social Decision Support System in PHP basato su un servizio web RESTful. Questa idea nasce da una particolare concezione del trading automatico chiamato trading assistito da un computer. Vogliamo che le capacità cognitive dei trader umani filtrino quei segnali di trading che altrimenti verrebbero automaticamente immessi sul mercato dagli Expert Advisor.