20 Segnali di Trading in MQL5

Sergey Gritsay | 9 dicembre, 2021

Introduzione

I trader cercano di trovare regolarità nel comportamento dei prezzi, si sforzano di formare regole usando le quali avranno una buona possibilità di determinare un momento favorevole per l'acquisto o la vendita. Per creare un sistema completamente automatico, è necessario imparare come informare sull'arrivo di tali momenti - segnali di trading.

I segnali informano i trader sui potenziali punti di inserimento di una posizione, tuttavia non tutti sono da eseguire obbligatoriamente. Dei criteri aggiuntivi possono filtrare anche la maggior parte dei segnali, ma per noi non è significativo. L'argomento dell'articolo è come programmare i segnali di trading più popolari in MQL5.


1. Quali Segnali Conosciamo?

Tutti i metodi per determinare i momenti di ingresso nel mercato possono essere suddivisi in diversi tipi:


2. Come Codificarlo Meglio?

Esistono molti modi per scrivere un codice; può essere scritto all'interno di OnStart(), OnTick() e delle altre funzioni. Puoi trovare informazioni più dettagliate su di esse nella documentazione su questo sito Web o nella guida per l'utente integrata nel MetaEditor;tuttavia, questo metodo non è efficace e talvolta è necessario scrivere più volte le stesse parti del codice. Questo è il caso in cui considereremo un altro modo: useremo funzioni personalizzate che possono essere chiamate da qualsiasi parte del codice del nostro programma.

Per comodità di utilizzo delle funzioni create, combiniamole in un gruppo separato come include file esterno e nominiamolo SignalTrade; verrà memorizzato nella directory ...\MQL5\Include. Permetterà di collegare facilmente questo modulo a qualsiasi programma. 

Nonostante tutti i segnali sembrino diversi, essi hanno molte cose in comune. Esistono tre varianti che possono essere ricevute da una funzione che genera i segnali:

Quindi, creiamo un'enumerazione che corrisponda a questi segnali.

Scriviamo un prototipo della funzione che restituisce un segnale. Dividere la nostra funzione in più parti nelle quali verrà eseguita l'una o l'altra operazione. Le variabili necessarie per l'archiviazione dei dati vengono dichiarate e inizializzate al principio della funzione. Il caricamento e il controllo delle informazioni necessarie dall'indicatore creato verranno eseguiti in seguito. Il controllo delle informazioni è essenziale per evitare conseguenze impreviste nel lavorare con i dati e del programma nel suo complesso. 

Una volta caricate e controllate le informazioni, vai a formare un segnale. Non appena si forma un segnale, esci dalla funzione e restituisci il segnale ottenuto ad esso come uno dei valori descritti sopra.

int TradeSignal()
  {
   //--- zero means absence of signal
   int sig=0;
   
   //--- check the handles of indicators

   //--- if all the handles are invalid, create them

   //--- if the handles are valid, copy the values from indicators

   //--- check the copied data

   //--- in case of an error of copying, exit from the function

   //--- perform the indexation of the array as a timeseries

   //--- in case of an indexation error, exit from the function

   //--- check conditions and set the value for sig
 
   //--- return the trade signal
   return(sig);
  }


3. Esempi dei 20 Segnali di Trading.

Useremo diversi indicatori per ottenere i segnali di trading. In MQL5 gli indicatori sono chiamati utilizzando le funzioni speciali, ad esempio iMA, iAC, iMACD, iIchimoku, ecc.; esse creanouna copia dell'indicatore tecnico corrispondente nella cache globale del client terminal. Se esiste già una copia dell'indicatore con tali parametri, la nuova copia non viene creata ed il contatore dei riferimenti alle attuali copie aumenta.

Queste funzioni restituiscono l'handle della copia corrispondente dell'indicatore. Inoltre, con questo handle, è possibile ricevere i dati calcolati dall' indicatore corrispondente. I dati del buffer corrispondente (gli indicatori tecnici contengono i dati calcolati nei loro buffer interni; il loro numero può variare da 1 a 5, a seconda del tipo di indicatore) possono essere copiati in un programma MQL5 utilizzando la funzione CopyBuffer().

È impossibile utilizzare i dati di un indicatore subito dopo la sua creazione, poiché è necessario un po’ di tempo per calcolare i valori dell'indicatore; quindi, il modo migliore, è creare gli handle all'interno di OnInit(). La funzione iCustom() crea l'indicatore personalizzato corrispondente e, se la creazione ha esito positivo, restituisce l'handle dell'indicatore. Gli indicatori personalizzati possono contenere fino a 512 buffer di indicatori, il cui contenuto si può ottenere anche utilizzando la funzione CopyBuffer() e l'handle ottenuto.

Per ogni segnale, creiamo una funzione in base al nostro prototipo TradeSignal() e numeriamoli nel seguente ordine: TradeSignal_01() - TradeSignal_20(). Analizziamo in dettaglio la struttura della funzione per formare un segnale usando l'esempio di un segnale basato sull'intersezione di medie mobili; quindi, scriveremo le funzioni per gli altri segnali in modo simile.

3.1. Intersezione delle Medie Mobili

Figura 1. L'intersezione di due medie mobili

Figura 1. L'intersezione di due medie mobili

Usando la funzione TradeSignal_01(), otterremo un segnale sull'intersezione di due Medie Mobili (МА): quella veloce con periodo 8 e quella lenta con periodo 16.

Nella nostra funzione, fisseremo solo il fatto dell'intersezione e restituiremo il valore del segnale corrispondente alla funzione. Secondo le nostre regole e il prototipo, la funzione sarà simile:

int TradeSignal_01()
  {
//--- zero means that there is no signal
   int sig=0;

//--- check the handles of indicators
   if(h_ma1==INVALID_HANDLE)//--- if the handle is invalid
     {
      //--- create is again                                                      
      h_ma1=iMA(Symbol(),Period(),8,0,MODE_SMA,PRICE_CLOSE);
      //--- exit from the function
      return(0);
     }
   else //--- if the handle is valid
     {
      //--- copy value of the indicator to the array
      if(CopyBuffer(h_ma1,0,0,3,ma1_buffer)<3) //--- if the array of data is less than required
         //--- exit from the function
         return(0);
      //--- set the indexation in the array as in a timeseries                                   
      if(!ArraySetAsSeries(ma1_buffer,true))
         //--- in case of an indexation error, exit from the function
         return(0);
     }

   if(h_ma2==INVALID_HANDLE)//--- if the handle is invalid
     {
      //--- create it again                                                      
      h_ma2=iMA(Symbol(),Period(),16,0,MODE_SMA,PRICE_CLOSE);
      //--- exit from the function
      return(0);
     }
   else //--- if the handle is valid 
     {
      //--- copy values of the indicator to the array
      if(CopyBuffer(h_ma2,0,0,2,ma2_buffer)<2) //--- if there is less data than required
         //--- exit from the function
         return(0);
      //--- set the indexation in the array as in a timeseries                                   
      if(!ArraySetAsSeries(ma1_buffer,true))
         //--- in case of an indexation error, exit from the function
         return(0);
     }

//--- check the condition and set a value for the sig
   if(ma1_buffer[2]<ma2_buffer[1] && ma1_buffer[1]>ma2_buffer[1])
      sig=1;
   else if(ma1_buffer[2]>ma2_buffer[1] && ma1_buffer[1]<ma2_buffer[1])
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);
  }

Ora diamo uno sguardo più dettagliato a ciascuna parte del codice. All'inizio della funzione, dichiariamo una variabile locale che memorizzerà il tipo di segnale e la inizializziamo con zero che indica assenza di segnale.

int sig=0;

Inoltre, controlliamo la validità dell’nandle; se l’handle non è valido, lo creiamo e usciamo dalla funzione, perché il calcolo dell'indicatore richiede del tempo. Viene implementato per evitare l'errore di copiare i dati dal buffer dell'indicatore.

   if(h_ma1==INVALID_HANDLE)//--- if the handle is invalid
     {
      //--- create it again                                                      
      h_ma1=iMA(Symbol(),Period(),8,0,MODE_SMA,PRICE_CLOSE);
      //--- exit from the function
      return(0);
     }

Se l'handle è valido, copiare i dati nell’array. Per analizzare la situazione, è sufficiente copiare i dati delle ultime tre barre della MA veloce e due barre di quella lenta. A tale scopo, utilizzare la seguente funzione :

int  CopyBuffer(
   int       indicator_handle,     // handle of an indicator
   int       buffer_num,           // number of buffer of an indicator
   int       start_pos,            // where to start from 
   int       count,                // amount to be copied
   double    buffer[]              // an array to copy data to
   );

Controllali: se ci sono meno dati del necessario, significa che si è verificato un errore di copia; di conseguenza, l’array in cui i dati avrebbero dovuto essere memorizzati determinerà un errore. Per evitarlo, usciamo dalla funzione. Inoltre abbiamo bisogno di impostare l’indicizzazione nell'array come in una timeserie; la seguente funzione è destinata a questo:

bool  ArraySetAsSeries(
   void  array[],     // array by a link
   bool  set          // true means that the indexation order is reversed
   );

Se si è verificato un errore durante l'indicizzazione dell'array, esci dalla funzione, altrimenti possiamo ottenere risultati errati.

else //--- if the handle is valid 
     {
      //--- copy values of the indicator to the array
      if(CopyBuffer(h_ma1,0,0,3,ma1_buffer)<3) //--- if there is less data than required
         //--- exit from the function
         return(0);
      //--- set the indexation in the array like in a timeseries                                   
      if(!ArraySetAsSeries(ma1_buffer,true))
         //--- in case of an indexation error, exit from the function
         return(0);
     }

Ora, man mano che gli indicatori vengono creati e si ottengono tutte le informazioni necessarie, procediamo alla fase principale: la formazione di un segnale.

Per eliminare l’oscillazione del segnale nella barra corrente, analizza solo le barre chiuse 1-st e 2-nd.

Forma il segnale per acquistare. A tale scopo, prendi il valore della MA veloce alla 2a barra e confrontalo con il valore della MA lenta a 1 barra; confronta il valore della MA veloce alla barra 1-st con il valore della MA lenta alla barra 1-st. Se il valore della MA veloce nella barra 2-nd è inferiore al valore della MA lenta nella barra 1-st, e il valore della MA veloce nella barra 1-st è maggiore del valore della MA lenta nella barra 1-st, significa che la MA veloce ha attraversato quella lenta verso l'alto; questo è il nostro segnale per comprare. Se la nostra condizione è vera, scrivi 1 nella variabile sig.

Il segnale per vendere si forma in modo simile. Se la MA veloce nella barra 2-nd è maggiore della MA lenta nella barra 1-st, e se la MA veloce nella barra 1-st è inferiore alla MA lenta nella barra 1-st, significa incrocio top-down della MA lenta da parte della MA veloce. Se la nostra condizione è vera, scrivi il valore -1 nella variabile sig. Se entrambe le condizioni sono false, significa che non c'è segnale, quindi scriviamo il valore 0 nella variabile sig. Ora i segnali si formano, restituiscono il tipo di segnale ottenuto alla nostra funzione TradeSignal_01()

//--- check the condition and set a value for the sig
   if(ma1_buffer[2]<ma2_buffer[1] && ma1_buffer[1]>ma2_buffer[1])
      sig=1;
   else if(ma1_buffer[2]>ma2_buffer[1] && ma1_buffer[1]<ma2_buffer[1])
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);

3.2. Intersezione della Linea Principale e di Segnale del MACD

Figura 2. L'intersezione della linea principale e del segnale dell'indicatore MACD

Nella funzione TradeSignal_02() otterremo il segnale sull'intersezione del segnale e la linea principale di MACD. Se la linea del segnale attraversa quella principale dall'alto verso il basso, è il segnale per acquistare. Se la linea del segnale attraversa quella principale dal basso verso l'alto, è il segnale per vendere. Altri casi verranno considerati come assenza di segnale.

int TradeSignal_02()
  {
   int sig=0;

   if(h_macd==INVALID_HANDLE)
     {
      h_macd=iMACD(Symbol(),Period(),12,26,9,PRICE_CLOSE);
      return(0);
     }
   else
     {
      if(CopyBuffer(h_macd,0,0,2,macd1_buffer)<2)
         return(0);
      if(CopyBuffer(h_macd,1,0,3,macd2_buffer)<3)
         return(0);
      if(!ArraySetAsSeries(macd1_buffer,true))
         return(0);
      if(!ArraySetAsSeries(macd2_buffer,true))
         return(0);
     }

//--- check the condition and set a value for sig
   if(macd2_buffer[2]>macd1_buffer[1] && macd2_buffer[1]<macd1_buffer[1])
      sig=1;
   else if(macd2_buffer[2]<macd1_buffer[1] && macd2_buffer[1]>macd1_buffer[1])
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);
  }

3.3. Rottura del Range del Canale di Prezzo

Figura 3. Rottura dei bordi inferiore e superiore del Canale di Prezzo

Nella funzione TradeSignal_03() riceveremo il segnale di una rottura dei bordi superiore o inferiore del Canale di Prezzo.

Se il prezzo buca il bordo superiore del Canale di Prezzo e il prezzo è fissato al di sopra di questo bordo, è il segnale per acquistare. Se il prezzo buca il bordo inferiore del Canale di Prezzo e il prezzo è fissato al di sotto di questo bordo, allora è il segnale per vendere. Altri casi, vengono considerati come assenza di segnale.

A differenza di due funzioni precedenti, qui abbiamo bisogno di un array per memorizzare i prezzi di chiusura. per ottenerli, utilizza la seguente funzione :

int  CopyClose(
   string           symbol_name,       // symbol name
   ENUM_TIMEFRAMES  timeframe,          // period
   int              start_pos,         // where to start from 
   int              count,             // amount to be copied
   double           close_array[]      // array for copying close prices to
   );
int TradeSignal_03()
  {
   int sig=0;

   if(h_pc==INVALID_HANDLE)
     {
      h_pc=iCustom(Symbol(),Period(),"Price Channel",22);
      return(0);
     }
   else
     {
      if(CopyBuffer(h_pc,0,0,3,pc1_buffer)<3)
         return(0);
      if(CopyBuffer(h_pc,1,0,3,pc2_buffer)<3)
         return(0);
      if(CopyClose(Symbol(),Period(),0,2,Close)<2)
         return(0);
      if(!ArraySetAsSeries(pc1_buffer,true))
         return(0);
      if(!ArraySetAsSeries(pc2_buffer,true))
         return(0);
      if(!ArraySetAsSeries(Close,true))
         return(0);
     }
//--- check the conditions and set a value for sig
   if(Close[1]>pc1_buffer[2])
      sig=1;
   else if(Close[1]<pc2_buffer[2])
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);
  }

3.4. Rottura del Range dei Canali Adattivi ADX

Figura 4. La rottura dei bordi superiore e inferiore del canale adattivo ADX.

Usando la funzione TradeSignal_04(), otterremo il segnale di rottura dei bordi superiore o inferiore del canale adattivo ADX.

Se il prezzo buca il bordo superiore del canale adattivo ADX e il prezzo di chiusura è fissato al di sopra di questo bordo, è il segnale per acquistare. Se il prezzo buca il bordo inferiore del Canale di Prezzo e il prezzo di chiusura è fissato al di sotto di questo confine, è il segnale per vendere. Altri casi, vengono considerati come assenza di segnale.

int TradeSignal_04()
  {
   int sig=0;

   if(h_acadx==INVALID_HANDLE)
     {
      h_acadx=iCustom(Symbol(),Period(),"AdaptiveChannelADX",14);
      return(0);
     }
   else
     {
      if(CopyBuffer(h_acadx,0,0,2,acadx1_buffer)<2)
         return(0);
      if(CopyBuffer(h_acadx,1,0,2,acadx2_buffer)<2)
         return(0);
      if(CopyClose(Symbol(),Period(),0,2,Close)<2)
         return(0);
      if(!ArraySetAsSeries(acadx1_buffer,true))
         return(0);
      if(!ArraySetAsSeries(acadx2_buffer,true))
         return(0);
      if(!ArraySetAsSeries(Close,true))
         return(0);
     }
//--- check the condition and set a value for the sig
   if(Close[1]>acadx1_buffer[1])
      sig=1;
   else if(Close[1]<acadx2_buffer[1])
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);
  }

3.5. Esci dalle zone di Overbuying/Overselling di Stochastic

Figura 5. Attraversamento dei livelli di overbuying e overselling da parte dello stocastico.

Usando il TradeSignal_05() otterremo il segnale di uscita dello stocastico dalle zone dioverbuying/overselling;i livelli di tali zone saranno livelli con valori 80 e 20.

Compriamo, poiché l'oscillatore (%K o %D) scende al di sotto di un certo livello (di solito, è 20) e poi sale al di sopra. Vendiamo, poiché l'oscillatore sale più in alto di un certo livello (di solito, è 80) e poi scende al di sotto.

int TradeSignal_05()
  {
   int sig=0;

   if(h_stoh==INVALID_HANDLE)
     {
      h_stoh=iStochastic(Symbol(),Period(),5,3,3,MODE_SMA,STO_LOWHIGH);
      return(0);
     }
   else
     {
      if(CopyBuffer(h_stoh,0,0,3,stoh_buffer)<3)
         return(0);

      if(!ArraySetAsSeries(stoh_buffer,true))
         return(0);
     }
//--- check the condition and set a value for sig
   if(stoh_buffer[2]<20 && stoh_buffer[1]>20)
      sig=1;
   else if(stoh_buffer[2]>80 && stoh_buffer[1]<80)
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);
  }

3.6. Uscita dalle zone Overbuying/Overselling dell’RSI

Figura 6. Incrocio dei livelli di overbuying e overselling da parte dell'indicatore RSI

Utilizzando la funzione TradeSignal_06() otterremo il segnale sull'uscita dell'indicatore RSI dalle zone di overbuying/overselling; i livelli per queste zone sono i livelli con i valori 70 e 30.

Compriamo, poiché l'RSI scende al di sotto di un certo livello (di solito, è 30) e poi sale al di sopra. Vendiamo, poiché l'RSI sale più in alto di un certo livello (di solito, è 70) e poi scende al di sotto .

int TradeSignal_06()
  {
   int sig=0;

   if(h_rsi==INVALID_HANDLE)
     {
      h_rsi=iRSI(Symbol(),Period(),14,PRICE_CLOSE);
      return(0);
     }
   else
     {
      if(CopyBuffer(h_rsi,0,0,3,rsi_buffer)<3)
         return(0);

      if(!ArraySetAsSeries(rsi_buffer,true))
         return(0);
     }
//--- check the condition and set a value for sig
   if(rsi_buffer[2]<30 && rsi_buffer[1]>30)
      sig=1;
   else if(rsi_buffer[2]>70 && rsi_buffer[1]<70)
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);
 
3.7. Esci dalle zone Overbuying/Overselling del CCI

Figura 7. Incrocio dei livelli di overbuying e overselling da parte dell'indicatore CCI

Usando il TradeSignal_07() otterremo il segnale di uscita dell'indicatore CCI dalle zone di overbuying/overselling; i livelli per tali zone sono i livelli con i valori 100 e -100.

Compriamo, poiché ilCCI scende più in basso del livello -100 e poi sale al di sopra. Vendiamo, poiché il CCI sale al di sopra dellivello 100 e poi scende al di sotto.

int TradeSignal_07()
  {
   int sig=0;

   if(h_cci==INVALID_HANDLE)
     {
      h_cci=iCCI(Symbol(),Period(),14,PRICE_TYPICAL);
      return(0);
     }
   else
     {
      if(CopyBuffer(h_cci,0,0,3,cci_buffer)<3)
         return(0);

      if(!ArraySetAsSeries(cci_buffer,true))
         return(0);
     }
//--- check the condition and set a value for sig
   if(cci_buffer[2]<-100 && cci_buffer[1]>-100)
      sig=1;
   else if(cci_buffer[2]>100 && cci_buffer[1]<100)
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);
  }

3.8. Uscita dalle zone Overbuying/Overselling di Williams %

Figura 8. Incrocio dei livelli di overbuying e overselling da parte dell'indicatore Williams %

Utilizzando la funzione TradeSignal_08() otterremo il segnale di uscita dell'indicatore Williams % dalle zone di overbuying/overselling; i livelli per tali zone sono i livelli con valori -20 e -80.

Compriamo, poiché Williams % scende al di sotto del livello -80 e poi sale al di sopra di esso. Vendiamo, poiché Williams % sale al di sopra del livello -20 e poi scende al di sotto di esso.

int TradeSignal_08()
  {
   int sig=0;

   if(h_wpr==INVALID_HANDLE)
     {
      h_wpr=iWPR(Symbol(),Period(),14);
      return(0);
     }
   else
     {
      if(CopyBuffer(h_wpr,0,0,3,wpr_buffer)<3)
         return(0);

      if(!ArraySetAsSeries(wpr_buffer,true))
         return(0);
     }
//--- check the condition and set a value for sig
   if(wpr_buffer[2]<-80 && wpr_buffer[1]>-80)
      sig=1;
   else if(wpr_buffer[2]>-20 && wpr_buffer[1]<-20)
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);
  }
3.9. Bounce dai Bordi del Canale Bollinger

Figura 9. Bounce del prezzo dal bordo del Canale Bollinger

Usando la funzione TradeSignal_09() otterremo il segnale quando il prezzo rimbalza dai bordi del canale Bollinger.

Se il prezzo buca o tocca il bordo superiore del Bollinger e poi ritorna indietro, è il segnale per vendere. Se il prezzo buca o tocca il bordo inferiore del Bollinger, allora è il segnale per acquistare.

int TradeSignal_09()
  {
   int sig=0;

   if(h_bb==INVALID_HANDLE)
     {
      h_bb=iBands(Symbol(),Period(),20,0,2,PRICE_CLOSE);
      return(0);
     }
   else
     {
      if(CopyBuffer(h_bb,1,0,2,bb1_buffer)<2)
         return(0);
      if(CopyBuffer(h_bb,2,0,2,bb2_buffer)<2)
         return(0);
      if(CopyClose(Symbol(),Period(),0,3,Close)<3)
         return(0);
      if(!ArraySetAsSeries(bb1_buffer,true))
         return(0);
      if(!ArraySetAsSeries(bb2_buffer,true))
         return(0);
      if(!ArraySetAsSeries(Close,true))
         return(0);
     }
//--- check the condition and set a value for sig
   if(Close[2]<=bb2_buffer[1] && Close[1]>bb2_buffer[1])
      sig=1;
   else if(Close[2]>=bb1_buffer[1] && Close[1]<bb1_buffer[1])
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);
  }

3.10. Bounce dai Bordi del Canale di Deviazione Standard

Figura 10. Bounce del prezzo dai bordi del canale di deviazione standard

Usando la funzione TradeSignal_10(), otterremo il segnale se il prezzo rimbalza dai bordi del canale di deviazione standard.

Se il prezzo buca o tocca il bordo superiore del canale di deviazione standard e poi ritorna indietro, è il segnale per vendere. Se il prezzo buca o tocca il bordo inferiore del canale di deviazione standard, allora è il segnale per acquistare.

int TradeSignal_10()
  {
   int sig=0;

   if(h_sdc==INVALID_HANDLE)
     {
      h_sdc=iCustom(Symbol(),Period(),"StandardDeviationChannel",14,0,MODE_SMA,PRICE_CLOSE,2.0);
      return(0);
     }
   else
     {
      if(CopyBuffer(h_sdc,0,0,2,sdc1_buffer)<2)
         return(0);
      if(CopyBuffer(h_sdc,1,0,2,sdc2_buffer)<2)
         return(0);
      if(CopyClose(Symbol(),Period(),0,3,Close)<3)
         return(0);
      if(!ArraySetAsSeries(sdc1_buffer,true))
         return(0);
      if(!ArraySetAsSeries(sdc2_buffer,true))
         return(0);
      if(!ArraySetAsSeries(Close,true))
         return(0);
     }
//--- check the condition and set a value for sig
   if(Close[2]<=sdc2_buffer[1] && Close[1]>sdc2_buffer[1])
      sig=1;
   else if(Close[2]>=sdc1_buffer[1] && Close[1]<sdc1_buffer[1])
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);
  }

3.11. Bounce dai Bordi del Canale di Prezzo

Figura 11. Il bounce del prezzo dai bordi del Canale di Prezzo

Usando la funzione TradeSignal_11() otterremo il segnale se il prezzo rimbalza dai bordi del Canale di Prezzo.

Se il prezzo buca o tocca il bordo superiore del canale di prezzo e poi ritorna indietro, è il segnale per vendere. Se il prezzo buca o tocca il bordo inferiore del Canale di Prezzo, allora è il segnale per acquistare.

int TradeSignal_11()
  {
   int sig=0;

   if(h_pc==INVALID_HANDLE)
     {
      h_pc=iCustom(Symbol(),Period(),"Price Channel",22);
      return(0);
     }
   else
     {
      if(CopyBuffer(h_pc,0,0,4,pc1_buffer)<4)
         return(0);
      if(CopyBuffer(h_pc,1,0,4,pc2_buffer)<4)
         return(0);
      if(CopyClose(Symbol(),Period(),0,3,Close)<3)
         return(0);
      if(!ArraySetAsSeries(pc1_buffer,true))
         return(0);
      if(!ArraySetAsSeries(pc2_buffer,true))
         return(0);
      if(!ArraySetAsSeries(Close,true))
         return(0);
     }
//--- check the condition and set a value for sig
   if(Close[1]>pc2_buffer[2] && Close[2]<=pc2_buffer[3])
      sig=1;
   else if(Close[1]<pc1_buffer[2] && Close[2]>=pc1_buffer[3])
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);
  }

3.12. Bounce dai Bordi del Canale Envelopes

Figura 12. Il bounce del prezzo dai bordi del canale Envelopes

Usando la funzione TradeSignal_12(), otterremo il segnale se il prezzo rimbalza dai bordi del canale Envelopes.

Se il prezzo buca o tocca il bordo superiore del canale Envelopes e poi ritorna indietro, è il segnale per vendere. Se il prezzo buca o tocca il bordo inferiore del canale Envelopes, è il segnale per acquistare.

int TradeSignal_12()
  {
   int sig=0;

   if(h_env==INVALID_HANDLE)
     {
      h_env=iEnvelopes(Symbol(),Period(),28,0,MODE_SMA,PRICE_CLOSE,0.1);
      return(0);
     }
   else
     {
      if(CopyBuffer(h_env,0,0,2,env1_buffer)<2)
         return(0);
      if(CopyBuffer(h_env,1,0,2,env2_buffer)<2)
         return(0);
      if(CopyClose(Symbol(),Period(),0,3,Close)<3)
         return(0);
      if(!ArraySetAsSeries(env1_buffer,true))
         return(0);
      if(!ArraySetAsSeries(env2_buffer,true))
         return(0);
      if(!ArraySetAsSeries(Close,true))
         return(0);
     }
//--- check the condition and set a value for sig
   if(Close[2]<=env2_buffer[1] && Close[1]>env2_buffer[1])
      sig=1;
   else if(Close[2]>=env1_buffer[1] && Close[1]<env1_buffer[1])
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);
  }

3.13. Rottura del Canale Donchian

Figura 13. Rottura dei bordi del Canale Donchian

Nella funzione TradeSignal_13(), otterremo il segnale quando il prezzo buca i bordi del canale Donchian.

Se il prezzo buca il bordo superiore del canale Donchian e il prezzo di chiusura è fissato al di sopra quel bordo, è il segnale per acquistare. Se il prezzo buca il bordo inferiore del canale Donchian e il prezzo di chiusura è fissato al di sotto di questo bordo, è il segnale per vendere.

int TradeSignal_13()
  {
   int sig=0;

   if(h_dc==INVALID_HANDLE)
     {
      h_dc=iCustom(Symbol(),Period(),"Donchian Channels",24,3,-2);
      return(0);
     }
   else
     {
      if(CopyBuffer(h_dc,0,0,3,dc1_buffer)<3)
         return(0);
      if(CopyBuffer(h_dc,1,0,3,dc2_buffer)<3)
         return(0);
      if(CopyClose(Symbol(),Period(),0,2,Close)<2)
         return(0);
      if(!ArraySetAsSeries(dc1_buffer,true))
         return(0);
      if(!ArraySetAsSeries(dc2_buffer,true))
         return(0);
      if(!ArraySetAsSeries(Close,true))
         return(0);
     }
//--- check the condition and set a value for sig
   if(Close[1]>dc1_buffer[2])
      sig=1;
   else if(Close[1]<dc2_buffer[2])
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);
  }

3.14. Rottura del Silver-Channel

Figura 14. Rottura dei bordi del Silver-Channel

Nella funzione TradeSignal_14(), otterremo il segnale quando il prezzo buca i bordi del Silver-Channel.  L'indicatore Silver-Channel disegna 8 bordi che possono fungere anche da livelli di supporto e resistenza. Per ottenere il segnale, useremo 2 bordi centrali. 

Se il prezzo buca il bordo superiore del Silver-Channel e il prezzo di chiusura è fissato al di sopra di questo bordo, è il segnale per acquistare. Se il prezzo buca il bordo inferiore del Silver-Channel e il prezzo di chiusura è fissato al di sotto di questo bordo, è il segnale per vendere.

int TradeSignal_14()
  {
   int sig=0;

   if(h_sc==INVALID_HANDLE)
     {
      h_sc=iCustom(Symbol(),Period(),"Silver-channels",26,38.2,23.6,0,61.8);
      return(0);
     }
   else
     {
      if(CopyBuffer(h_sc,0,0,2,sc1_buffer)<2)
         return(0);
      if(CopyBuffer(h_sc,1,0,2,sc2_buffer)<2)
         return(0);
      if(CopyClose(Symbol(),Period(),0,3,Close)<3)
         return(0);
      if(!ArraySetAsSeries(sc1_buffer,true))
         return(0);
      if(!ArraySetAsSeries(sc2_buffer,true))
         return(0);
      if(!ArraySetAsSeries(Close,true))
         return(0);
     }
//--- check the condition and set a value for sig
   if(Close[2]<sc1_buffer[1] && Close[1]>sc1_buffer[1])
      sig=1;
   else if(Close[2]>sc2_buffer[1] && Close[1]<sc2_buffer[1])
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);
  }

3.15. Rottura del Canale Gallagher

Figura 15. Rottura dei bordi del canale Gallagher

Nel canale TradeSignal_15(), otterremo il segnale quando il prezzo buca i bordi del canale Gallagher. L'indicatore del canale Gallagher è disegnato da massimi e minimi per 10 giorni. 

Se il prezzo buca il bordo superiore del canale Gallagher e il prezzo di chiusura è fissato al di sopra di questo bordo, è il segnale per acquistare. Se il prezzo buca il bordo inferiore del canale Gallagher e il prezzo di chiusura è fissato al di sotto di questo bordo, è il segnale per vendere.

int TradeSignal_15()
  {
   int sig=0;

   if(h_gc==INVALID_HANDLE)
     {
      h_gc=iCustom(Symbol(),Period(),"PriceChannelGalaher");
      return(0);
     }
   else
     {
      if(CopyBuffer(h_gc,0,0,3,gc1_buffer)<3)
         return(0);
      if(CopyBuffer(h_gc,1,0,3,gc2_buffer)<3)
         return(0);
      if(CopyClose(Symbol(),Period(),0,2,Close)<2)
         return(0);
      if(!ArraySetAsSeries(gc1_buffer,true))
         return(0);
      if(!ArraySetAsSeries(gc2_buffer,true))
         return(0);
      if(!ArraySetAsSeries(Close,true))
         return(0);
     }
//--- check the condition and set a value for sig
   if(Close[1]>gc1_buffer[2])
      sig=1;
   else if(Close[1]<gc2_buffer[2])
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);
  }

3.16. Cambio di tendenza da parte dell’NRTR

Figura 16. Identificazione di un cambiamento di tendenza utilizzando l'indicatore NRTR

Nella funzione TradeSignal_16(), otterremo il segnale quando cambia la tendenza dell’NRTR.

Se l'indicatore NRTR mostra una tendenza al rialzo, è il segnale per acquistare. Se l’NRTR mostra una tendenza al ribasso, è il segnale per vendere.

int TradeSignal_16()
  {
   int sig=0;

   if(h_nrtr==INVALID_HANDLE)
     {
      h_nrtr=iCustom(Symbol(),Period(),"NRTR",40,2.0);
      return(0);
     }
   else
     {
      if(CopyBuffer(h_nrtr,0,0,2,nrtr1_buffer)<2)
         return(0);
      if(CopyBuffer(h_nrtr,1,0,2,nrtr2_buffer)<2)
         return(0);
      if(!ArraySetAsSeries(nrtr1_buffer,true))
         return(0);
      if(!ArraySetAsSeries(nrtr2_buffer,true))
         return(0);
     }
//--- check the condition and set a value for sig
   if(nrtr1_buffer[1]>0)
      sig=1;
   else if(nrtr2_buffer[1]>0)
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);
  }

3.17. Cambiamento di Tendenza da parte di Alligator

Figura 17. Cambiamento della Tendenza da parte di Alligator

Nella funzione TradeSignal_17(), otterremo il segnale quando Alligator cambia la tendenza.

Se Jaw, Teeth e Lips sono chiusi e attorcigliati, l'Alligator sta andando a dormire o sta già dormendo. Quando dorme, la sua fame cresce; e più dorme, più è affamato quando si sveglia. La prima cosa che fa quando si sveglia è aprire la bocca e sbadigliare. Poi inizia a sentire l'odore del cibo - la carne di un toro o di un orso, e poi inizia a cacciarlo. Quando Alligator ha mangiato abbastanza, perde il suo interesse per il prezzo del cibo (le Balance Lines convergono); è il momento di fissare il profitto.

int TradeSignal_17()
  {
   int sig=0;

   if(h_al==INVALID_HANDLE)
     {
      h_al=iAlligator(Symbol(),Period(),13,0,8,0,5,0,MODE_SMMA,PRICE_MEDIAN);
      return(0);
     }
   else
     {
      if(CopyBuffer(h_al,0,0,2,al1_buffer)<2)
         return(0);
      if(CopyBuffer(h_al,1,0,2,al2_buffer)<2)
         return(0);
      if(CopyBuffer(h_al,2,0,2,al3_buffer)<2)
         return(0);
      if(!ArraySetAsSeries(al1_buffer,true))
         return(0);
      if(!ArraySetAsSeries(al2_buffer,true))
         return(0);
      if(!ArraySetAsSeries(al3_buffer,true))
         return(0);
     }
//--- check the condition and set a value for sig
   if(al3_buffer[1]>al2_buffer[1] && al2_buffer[1]>al1_buffer[1])
      sig=1;
   else if(al3_buffer[1]<al2_buffer[1] && al2_buffer[1]<al1_buffer[1])
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);
  }

3.18. Cambiamento di Tendenza da parte dell’AMA

Figura 18. Cambiamento di tendenza da parte dell’AMA

Nella funzione TradeSignal_18(), otterremo il segnale quando cambia la tendenza dell’AMA.

Se l'indicatore AMA è diretto verso l'alto, è il segnale per acquistare. Se l'AMA è diretto verso il basso, allora è il segnale per vendere.

int TradeSignal_18()
  {
   int sig=0;

   if(h_ama==INVALID_HANDLE)
     {
      h_ama=iAMA(Symbol(),Period(),9,2,30,0,PRICE_CLOSE);
      return(0);
     }
   else
     {
      if(CopyBuffer(h_ama,0,0,3,ama_buffer)<3)
         return(0);
      if(!ArraySetAsSeries(ama_buffer,true))
         return(0);
     }
//--- check the condition and set a value for sig
   if(ama_buffer[2]<ama_buffer[1])
      sig=1;
   else if(ama_buffer[2]>ama_buffer[1])
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);
  }

3.19. Cambio di Colore dell'Awesome Oscillator

Figura 19. Identificazione di un cambiamento di tendenza utilizzando l'indicatore Awesome Oscillator

Nella funzione TradeSignal_19(), otterremo il segnale quando cambia il colore dell'istogramma Awesome Oscillator.

Una delle caratteristiche di MQL5 è la possibilità di creare buffer per indicatori, in cui è possibile memorizzare indici del colore delle linee impostate nelle proprietà #property indicator_colorN. Quando il colore dell'istogramma Awesome Oscillator è verde, è il segnale per acquistare. Se il suo colore diventa rosso, è il segnale per vendere.

int TradeSignal_19()
  {
   int sig=0;

   if(h_ao==INVALID_HANDLE)
     {
      h_ao=iAO(Symbol(),Period());
      return(0);
     }
   else
     {
      if(CopyBuffer(h_ao,1,0,20,ao_buffer)<20)
         return(0);
      if(!ArraySetAsSeries(ao_buffer,true))
         return(0);
     }
//--- check the condition and set a value for sig
   if(ao_buffer[1]==0)
      sig=1;
   else if(ao_buffer[1]==1)
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);
  }

3.20. Cambiamento di Tendenza da parte di Ichimoku

Figura 20. Identificazione di un cambiamento di tendenza utilizzando l'indicatore Ichimoku

Nella funzione TradeSignal_20(), otterremo il segnale quando cambia la tendenza di Ichimoku. A tale scopo, analizzeremo l'intersezione delle linee Tenkan-sen e Kijun-sen.

Il segnale di acquisto viene generato quando la linea Tenkan-sen attraversa il kijun-sen bottom-up. L'incrocio top-down è il segnale per vendere.

int TradeSignal_20()
  {
   int sig=0;

   if(h_ich==INVALID_HANDLE)
     {
      h_ich=iIchimoku(Symbol(),Period(),9,26,52);
      return(0);
     }
   else
     {
      if(CopyBuffer(h_ich,0,0,2,ich1_buffer)<2)
         return(0);
      if(CopyBuffer(h_ich,1,0,2,ich2_buffer)<2)
         return(0);
      if(!ArraySetAsSeries(ich1_buffer,true))
         return(0);
      if(!ArraySetAsSeries(ich2_buffer,true))
         return(0);
     }
//--- check the condition and set a value for sig
   if(ich1_buffer[1]>ich2_buffer[1])
      sig=1;
   else if(ich1_buffer[1]<ich2_buffer[1])
      sig=-1;
   else sig=0;

//--- return the trade signal
   return(sig);
  }


4. Rendilo un Indicatore

Ora, poiché abbiamo i blocchi di indicatori già pronti, possiamo iniziare a scrivere un indicatore che mostri i segnali sulla base di tutti i metodi selezionati. Utilizzando il modello creato, possiamo implementare la ricezione del segnale da qualsiasi indicatore; è sufficiente formulare correttamente una condizione di segnale e aggiungerla al codice.

Scriviamo un indicatore con parametri inflessibili integrati. I segnali degli indicatori saranno disegnati sotto forma di frecce (freccia in su -ma, giù - vendere, una croce - nessun segnale) sulla parte destra del grafico. Prendiamo il carattere standard Wingdings per disegnare le frecce. Inoltre, abbiamo bisogno di creare diverse altre funzioni per visualizzare le informazioni sui segnali sul grafico di un simbolo. Li combineremo in un blocco separato come una libreria che può essere utilizzata per scrivere i propri programmi aggiungendo nuove funzioni ad esso. Nominiamo LibFunctions questa libreria.

Nell'intestazione del nostro indicatore futuro, scrivi il collegamento del file con le funzioni per la generazione del segnale e la funzione di importazione necessarie per la visualizzazione grafica del segnale, oltre a dichiarare le variabili sul global scape che memorizzerà il tipo di segnale ricevuto dall'indicatore.

//--- Connect necessary libraries of functions
#include <SignalTrade.mqh>
//--- Import of functions from the LibFunctions library
#import "LibFunctions.ex5"
void SetLabel(string nm,string tx,ENUM_BASE_CORNER cn,ENUM_ANCHOR_POINT cr,int xd,int yd,string fn,int fs,double yg,color ct);
string arrow(int sig);
color Colorarrow(int sig);
#import
//+------------------------------------------------------------------+
//| Declare variables for storing signals of indicators              |
//+------------------------------------------------------------------+
int SignalMA;
int SignalMACD;
int SignalPC;
int SignalACADX;
int SignalST;
int SignalRSI;
int SignalCCI;
int SignalWPR;
int SignalBB;
int SignalSDC;
int SignalPC2;
int SignalENV;
int SignalDC;
int SignalSC;
int SignalGC;
int SignalNRTR;
int SignalAL;
int SignalAMA;
int SignalAO;
int SignalICH;

Come accennato in precedenza, gli indicatori vengono caricati sul terminale una sola volta e vengono creati i puntatori (handle) per tali indicatori; ecco perché implementiamo la loro creazione nella funzione OnInit(), poiché questa funzione viene eseguita solo una volta all'avvio del programma.

int OnInit()
  {
//--- create indicator handles
   h_ma1=iMA(Symbol(),Period(),8,0,MODE_SMA,PRICE_CLOSE);
   h_ma2=iMA(Symbol(),Period(),16,0,MODE_SMA,PRICE_CLOSE);
   h_macd=iMACD(Symbol(),Period(),12,26,9,PRICE_CLOSE);
   h_pc=iCustom(Symbol(),Period(),"Price Channel",22);
   h_acadx=iCustom(Symbol(),Period(),"AdaptiveChannelADX",14);
   h_stoh=iStochastic(Symbol(),Period(),5,3,3,MODE_SMA,STO_LOWHIGH);
   h_rsi=iRSI(Symbol(),Period(),14,PRICE_CLOSE);
   h_cci=iCCI(Symbol(),Period(),14,PRICE_TYPICAL);
   h_wpr=iWPR(Symbol(),Period(),14);
   h_bb=iBands(Symbol(),Period(),20,0,2,PRICE_CLOSE);
   h_sdc=iCustom(Symbol(),Period(),"StandardDeviationChannel",14,0,MODE_SMA,PRICE_CLOSE,2.0);
   h_env=iEnvelopes(Symbol(),Period(),28,0,MODE_SMA,PRICE_CLOSE,0.1);
   h_dc=iCustom(Symbol(),Period(),"Donchian Channels",24,3,-2);
   h_sc=iCustom(Symbol(),Period(),"Silver-channels",26,38.2,23.6,0,61.8);
   h_gc=iCustom(Symbol(),Period(),"PriceChannelGalaher");
   h_nrtr=iCustom(Symbol(),Period(),"NRTR",40,2.0);
   h_al=iAlligator(Symbol(),Period(),13,0,8,0,5,0,MODE_SMMA,PRICE_MEDIAN);
   h_ama=iAMA(Symbol(),Period(),9,2,30,0,PRICE_CLOSE);
   h_ao=iAO(Symbol(),Period());
   h_ich=iIchimoku(Symbol(),Period(),9,26,52);
   return(0);
  }

Tutti i calcoli principali vengono eseguiti nella funzione OnCalculate(); lì, inseriremo il resto del codice dell'indicatore.

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---assign the signal value to the variable
   SignalMA    = TradeSignal_01();
   SignalMACD  = TradeSignal_02();
   SignalPC    = TradeSignal_03();
   SignalACADX = TradeSignal_04();
   SignalST    = TradeSignal_05();
   SignalRSI   = TradeSignal_06();
   SignalCCI   = TradeSignal_07();
   SignalWPR   = TradeSignal_08();
   SignalBB    = TradeSignal_09();
   SignalSDC   = TradeSignal_10();
   SignalPC2   = TradeSignal_11();
   SignalENV   = TradeSignal_12();
   SignalDC    = TradeSignal_13();
   SignalSC    = TradeSignal_14();
   SignalGC    = TradeSignal_15();
   SignalNRTR  = TradeSignal_16();
   SignalAL    = TradeSignal_17();
   SignalAMA   = TradeSignal_18();
   SignalAO    = TradeSignal_19();
   SignalICH   = TradeSignal_20();

//--- draw graphical objects on the chart in the upper left corner
   int size=((int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS)/22);
   int i=0;
   int x=10;
   int y=0;
   int fz=size-4;

   y+=size;
   SetLabel("arrow"+(string)i,arrow(SignalMA),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+4,"Wingdings",fz-2,0,Colorarrow(SignalMA));
   x+=size;
   SetLabel("label"+(string)i,"Moving Average",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,0,BlueViolet);
   i++;y+=size;x=10;
   SetLabel("arrow"+(string)i,arrow(SignalMACD),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+4,"Wingdings",fz-2,0,Colorarrow(SignalMACD));
   x+=size;
   SetLabel("label"+(string)i,"MACD",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,0,BlueViolet);
   i++;y+=size;x=10;
   SetLabel("arrow"+(string)i,arrow(SignalPC),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+4,"Wingdings",fz-2,0,Colorarrow(SignalPC));
   x+=size;
   SetLabel("label"+(string)i,"Price Channell",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,0,BlueViolet);
   i++;y+=size;x=10;
   SetLabel("arrow"+(string)i,arrow(SignalACADX),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+4,"Wingdings",fz-2,0,Colorarrow(SignalACADX));
   x+=size;
   SetLabel("label"+(string)i,"Adaptive Channel ADX",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,0,BlueViolet);
   i++;y+=size;x=10;
   SetLabel("arrow"+(string)i,arrow(SignalST),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+4,"Wingdings",fz-2,0,Colorarrow(SignalST));
   x+=size;
   SetLabel("label"+(string)i,"Stochastic Oscillator",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,0,BlueViolet);
   i++;y+=size;x=10;
   SetLabel("arrow"+(string)i,arrow(SignalRSI),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+4,"Wingdings",fz-2,0,Colorarrow(SignalRSI));
   x+=size;
   SetLabel("label"+(string)i,"RSI",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,0,BlueViolet);
   i++;y+=size;x=10;
   SetLabel("arrow"+(string)i,arrow(SignalCCI),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+4,"Wingdings",fz-2,0,Colorarrow(SignalCCI));
   x+=size;
   SetLabel("label"+(string)i,"CCI",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,0,BlueViolet);
   i++;y+=size;x=10;
   SetLabel("arrow"+(string)i,arrow(SignalWPR),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+4,"Wingdings",fz-2,0,Colorarrow(SignalWPR));
   x+=size;
   SetLabel("label"+(string)i,"WPR",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,0,BlueViolet);
   i++;y+=size;x=10;
   SetLabel("arrow"+(string)i,arrow(SignalBB),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+4,"Wingdings",fz-2,0,Colorarrow(SignalBB));
   x+=size;
   SetLabel("label"+(string)i,"Bollinger Bands",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,0,BlueViolet);
   i++;y+=size;x=10;
   SetLabel("arrow"+(string)i,arrow(SignalSDC),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+4,"Wingdings",fz-2,0,Colorarrow(SignalSDC));
   x+=size;
   SetLabel("label"+(string)i,"StDevChannel",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,0,BlueViolet);
   i++;y+=size;x=10;
   SetLabel("arrow"+(string)i,arrow(SignalPC2),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+4,"Wingdings",fz-2,0,Colorarrow(SignalPC2));
   x+=size;
   SetLabel("label"+(string)i,"Price Channell 2",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,0,BlueViolet);
   i++;y+=size;x=10;
   SetLabel("arrow"+(string)i,arrow(SignalENV),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+4,"Wingdings",fz-2,0,Colorarrow(SignalENV));
   x+=size;
   SetLabel("label"+(string)i,"Envelopes",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,0,BlueViolet);
   i++;y+=size;x=10;
   SetLabel("arrow"+(string)i,arrow(SignalDC),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+4,"Wingdings",fz-2,0,Colorarrow(SignalDC));
   x+=size;
   SetLabel("label"+(string)i,"Donchian Channels",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,0,BlueViolet);
   i++;y+=size;x=10;
   SetLabel("arrow"+(string)i,arrow(SignalSC),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+4,"Wingdings",fz-2,0,Colorarrow(SignalSC));
   x+=size;
   SetLabel("label"+(string)i,"Silver-channels",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,0,BlueViolet);
   i++;y+=size;x=10;
   SetLabel("arrow"+(string)i,arrow(SignalGC),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+4,"Wingdings",fz-2,0,Colorarrow(SignalGC));
   x+=size;
   SetLabel("label"+(string)i,"Galaher Channel",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,0,BlueViolet);
   i++;y+=size;x=10;
   SetLabel("arrow"+(string)i,arrow(SignalNRTR),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+4,"Wingdings",fz-2,0,Colorarrow(SignalNRTR));
   x+=size;
   SetLabel("label"+(string)i,"NRTR",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,0,BlueViolet);
   i++;y+=size;x=10;
   SetLabel("arrow"+(string)i,arrow(SignalAL),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+4,"Wingdings",fz-2,0,Colorarrow(SignalAL));
   x+=size;
   SetLabel("label"+(string)i,"Alligator",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,0,BlueViolet);
   i++;y+=size;x=10;
   SetLabel("arrow"+(string)i,arrow(SignalAMA),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+4,"Wingdings",fz-2,0,Colorarrow(SignalAMA));
   x+=size;
   SetLabel("label"+(string)i,"AMA",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,0,BlueViolet);
   i++;y+=size;x=10;
   SetLabel("arrow"+(string)i,arrow(SignalAO),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+4,"Wingdings",fz-2,0,Colorarrow(SignalAO));
   x+=size;
   SetLabel("label"+(string)i,"Awesome oscillator",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,0,BlueViolet);
   i++;y+=size;x=10;
   SetLabel("arrow"+(string)i,arrow(SignalICH),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+4,"Wingdings",fz-2,0,Colorarrow(SignalICH));
   x+=size;
   SetLabel("label"+(string)i,"Ichimoku Kinko Hyo",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,0,BlueViolet);

   return(rates_total);
  }

Bene, il nostro indicatore è pronto. Alla fine, avremo la seguente immagine sul grafico.



5. Rendilo un Expert Advisor

Allo stesso modo, possiamo scrivere un Expert Advisor che mostra il segnale dell'indicatore sul grafico. Implementiamo un sistema informativo con gli elementi di controllo grafico. È possibile scegliere un indicatore necessario e impostarne i parametri attraverso l'interfaccia grafica.


Qui non parleremo dell'implementazione dell'interfaccia grafica; puoi trovare le informazioni al riguardo nell'articolo Creazione di Pannelli di Controllo Attivi in MQL5 per il Trading.

Per modificare le impostazioni degli indicatori attraverso la nostra interfaccia grafica, miglioriamo la nostra libreria SignalTrade.mqh e la nominiamo SignalTradeExp.mqh.

Innanzitutto, abbiamo bisogno di variabili aggiuntive per memorizzare le impostazioni degli indicatori.

//--- input parameters Moving Average
int                periodma1=8;
int                periodma2=16;
ENUM_MA_METHOD     MAmethod=MODE_SMA;
ENUM_APPLIED_PRICE MAprice=PRICE_CLOSE;
//--- input parameters MACD
int                FastMACD=12;
int                SlowMACD=26;
int                MACDSMA=9;
ENUM_APPLIED_PRICE MACDprice=PRICE_CLOSE;
//--- input parameters Price Channel
int                PCPeriod=22;
//--- input parameters Adaptive Channel ADX
int                ADXPeriod=14;
//--- input parameters Stochastic Oscillator
int                SOPeriodK=5;
int                SOPeriodD=3;
int                SOslowing=3;
ENUM_MA_METHOD     SOmethod=MODE_SMA;
ENUM_STO_PRICE     SOpricefield=STO_LOWHIGH;
//--- input parameters RSI
int                RSIPeriod=14;
ENUM_APPLIED_PRICE RSIprice=PRICE_CLOSE;
//--- input parameters CCI
int                CCIPeriod=14;
ENUM_APPLIED_PRICE CCIprice=PRICE_TYPICAL;
//--- input parameters WPR
int                WPRPeriod=14;
//--- input parameters Bollinger Bands
int                BBPeriod=20;
double             BBdeviation=2.0;
ENUM_APPLIED_PRICE BBprice=PRICE_CLOSE;
//--- input parameters Standard Deviation Channel
int                SDCPeriod=14;
double             SDCdeviation=2.0;
ENUM_APPLIED_PRICE SDCprice=PRICE_CLOSE;
ENUM_MA_METHOD     SDCmethod=MODE_SMA;
//--- input parameters Price Channel 2
int                PC2Period=22;
//--- input parameters Envelopes
int                ENVPeriod=14;
double             ENVdeviation=0.1;
ENUM_APPLIED_PRICE ENVprice=PRICE_CLOSE;
ENUM_MA_METHOD     ENVmethod=MODE_SMA;
//--- input parameters Donchian Channels
int                DCPeriod=24;
int                DCExtremes=3;
int                DCMargins=-2;
//--- input parameters Silver-channels
int                SCPeriod=26;
double             SCSilvCh=38.2;
double             SCSkyCh=23.6;
double             SCFutCh=61.8;
//--- input parameters NRTR
int                NRTRPeriod   =  40;
double             NRTRK        =  2.0;
//--- input parameters Alligator
int                ALjawperiod=13;
int                ALteethperiod=8;
int                ALlipsperiod=5;
ENUM_MA_METHOD     ALmethod=MODE_SMMA;
ENUM_APPLIED_PRICE ALprice=PRICE_MEDIAN;
//--- input parameters AMA
int                AMAperiod=9;
int                AMAfastperiod=2;
int                AMAslowperiod=30;
ENUM_APPLIED_PRICE AMAprice=PRICE_CLOSE;
//--- input parameters Ichimoku Kinko Hyo
int                IKHtenkansen=9;
int                IKHkijunsen=26;
int                IKHsenkouspanb=52;

Sostituire i valori costanti degli indicatori con le variabili. Altre cose dovrebbero essere lasciate invariate.

h_ma1=iMA(Symbol(),Period(),periodma1,0,MAmethod,MAprice);

Un punto significativo è l'uso economico della memoria del computer; quando si modificano le impostazioni, è necessario scaricare la copia dell'indicatore con le vecchie impostazioni e caricarne una nuova. Questo si può fare usando la seguente funzione:

bool  IndicatorRelease(
   int       indicator_handle,     // indicator handle
   );
   if(id==CHARTEVENT_OBJECT_ENDEDIT && sparam=="PIPSetEditMA2")
     {
      periodma2=(int)ObjectGetString(0,"PIPSetEditMA2",OBJPROP_TEXT);
      ObjectSetString(0,"PIPSetEditMA2",OBJPROP_TEXT,(string)periodma2);
      //--- unload old copy of the indicator
      IndicatorRelease(h_ma2);
      //--- create new copy of the indicator
      h_ma2=iMA(Symbol(),Period(),periodma2,0,MAmethod,MAprice);
      ChartRedraw();
     }

Conclusione

Pertanto, abbiamo imparato come leggere le informazioni dagli indicatori e come passarle all’Expert Advisor. In tal modo, è possibile ottenere segnali da qualsiasi indicatore.

Nota