English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Il Wizard MQL5: Come creare un modulo di segnali di trading

Il Wizard MQL5: Come creare un modulo di segnali di trading

MetaTrader 5Sistemi di trading | 17 dicembre 2021, 15:01
319 0
MetaQuotes
MetaQuotes

Introduzione

MetaTrader 5 fornisce un potente strumento per il controllo rapido delle idee di trading. Questo è il generatore di strategie di trading del Wizard MQL5. L'utilizzo del Wizard MQL5 per la creazione automatica di codici per Expert Advisor è descritto nell'articolo "MQL5 Wizard: Creazione di Expert Advisor senza Programmazione". L'apertura del sistema di generazione del codice ti consente di aggiungere le tue classi di segnali di trading, sistemi di gestione del denaro e moduli di trailing a quelle standard.

Questo articolo descrive i principi della scrittura di moduli di segnali di trading per utilizzarli durante la creazione di Expert Advisor con il Wizard MQL5.

L'Expert Advisor creato con il Wizard MQL5 si basa su quattro pilastri, ovvero quattro classi base:

Figura 1. La struttura della classe base CExpert

Figura 1. La struttura della classe base CExpert

La classe CExpert (o la sua sottoclasse) è il "motore" principale di un robot di trading. Un'istanza di CExpert contiene una copia di ogni classe: CExpertSignal, CExpertMoney e CExpertTrailing (o le loro sottoclassi):

  1. CExpertSignal è la base del generatore di segnali di trading. Un'istanza della classe derivata CExpertSignal, inclusa in CExpert, fornisce a un Expert Advisor informazioni sulla possibilità di entrare nel mercato, sui livelli di ingresso e sull'immissione di ordini protettivi basandosi su algoritmi incorporati. La decisione finale sull'esecuzione delle operazioni di trading è presa dall'EA.
  2. CExpertMoney è la base dei sistemi di gestione del denaro e del rischio. Un'istanza della classe derivata CExpertMoney calcola i volumi per l'apertura di posizioni e l'immissione di ordini in sospeso. La decisione finale sul volume è presa dall'EA.
  3. CExpertTrailing è la base del modulo di supporto delle posizioni aperte. Un'istanza della classe derivata CExpertTrailing informa un EA della necessità di modificare gli ordini di protezione di una posizione. La decisione finale sulla modifica dell'ordine è presa dall'EA.

Inoltre, i membri della classe CExpert sono istanze delle seguenti classi:

  • CExpertTrade (per il trading)
  • CIndicators (per il controllo degli indicatori e delle serie temporali coinvolte nell'attività dell'EA).
  • CSymbolInfo (per ottenere informazioni sullo strumento)
  • CAccountInfo (per ottenere informazioni sullo stato del conto di trading)
  • CPositionInfo (per ottenere informazioni sulle posizioni)
  • COrderInfo (per ottenere informazioni sugli ordini in sospeso)

Di seguito, con il termine "expert" indicheremo un'istanza di CExpert o una sua sottoclasse.

Maggiori dettagli su CExpert e sul suo operato verranno descritti in un altro articolo.


1. Classe base CExpertSignal

CExpertSignal è la base del generatore di segnali di trading. Per la comunicazione con il "mondo esterno", CExpertSignal usa una serie di metodi virtuali pubblici:

Inizializzazione

Descrizione

virtual Init

L'inizializzazione dell'istanza della classe fornisce la sincronizzazione dei dati del modulo con i dati dell'EA

virtual ValidationSettings

Convalida dei parametri impostati

virtual InitIndicators

Creazione e inizializzazione di tutti gli indicatori e le serie temporali necessarie per il funzionamento del generatore di segnali di trading

Segnali di apertura/inversione/chiusura della posizione

 

virtual CheckOpenLong

Generazione del segnale di apertura della posizione long, definizione dei livelli di ingresso e collocazione degli ordini di protezione

virtual CheckOpenShort

Generazione del segnale di apertura di una posizione short, definizione dei livelli di ingresso e collocamento degli ordini di protezione

virtual CheckCloseLong

Generazione del segnale di chiusura della posizione long, definizione del livello di uscita

virtual CheckCloseShort

Generazione del segnale di chiusura della posizione short, definizione del livello di uscita

virtual CheckReverseLong

Generazione del segnale di inversione della posizione long, definizione dei livelli di inversione e immissione degli ordini di protezione

virtual CheckReverseShort

Generazione del segnale di inversione della posizione short, definizione dei livelli di inversione e immissione degli ordini di protezione

Gestione degli ordini in sospeso

 

virtual CheckTrailingOrderLong

Generazione del segnale di modifica di un ordine di acquisto in sospeso, definizione del nuovo prezzo dell'ordine

virtual CheckTrailingOrderShort

Generazione del segnale di modifica di un ordine di vendita in sospeso, definizione del nuovo prezzo dell'ordine

Descrizione dei metodi

1.1. Metodi di inizializzazione:

1.1.1 Init

Il metodo Init() viene chiamato automaticamente subito dopo l'aggiunta di un'istanza di classe all'expert. L'override del metodo non è richiesto.

virtual bool Init(CSymbolInfo* symbol, ENUM_TIMEFRAMES period, double adjusted_point);

1.1.2 ValidationSettings

Il metodo ValidationSettings() viene chiamato direttamente dall'expert dopo che tutti i parametri sono stati impostati. È necessario riscrivere il metodo se sono presenti parametri di configurazione.

virtual bool ValidationSettings();

Il metodo riscritto deve restituire true se tutte le opzioni sono valide (utilizzabili). Se almeno uno dei parametri non è corretto, deve restituire false (ulteriori lavori sono impossibili).

La classe base CExpertSignal non ha parametri regolabili, quindi il metodo della classe base restituisce sempre true senza eseguire alcun controllo.

1.1.3 InitIndicators

Il metodo InitIndicators() implementa la creazione e l'inizializzazione di tutti gli indicatori e le serie temporali necessari. Viene chiamato dall'expert dopo che tutti i parametri sono stati impostati e la loro correttezza è stata verificata con successo. Il metodo deve essere riscritto se il generatore di segnali di trading utilizza almeno un indicatore o serie temporali.

virtual bool InitIndicators(CIndicators* indicators);

Gli indicatori e/o le serie temporali devono essere utilizzati attraverso le classi apposite della Standard Library. I puntatori di tutti gli indicatori e/o le serie temporali devono essere aggiunti alla raccolta di indicatori di un expert (un puntatore al quale viene passato come parametro).

Il metodo riscritto deve restituire true se tutte le manipolazioni con gli indicatori e/o le serie temporali hanno avuto esito positivo (sono idonei per l'uso). Se almeno un'operazione con gli indicatori e/o le serie temporali fallisce, il metodo deve restituire false (impossibile eseguire ulteriori lavori).

La classe base CExpertSignal non utilizza indicatori o serie temporali, pertanto il metodo della classe base restituisce sempre true, senza eseguire alcuna azione.


1.2. Metodi di controllo del segnale di apertura della posizione:

1.2.1 CheckOpenLong

Il metodo CheckOpenLong() genera un segnale di apertura di una posizione long, definendo il livello di entrata e i livelli di immissione degli ordini protettivi. Viene chiamato da un expert per determinare se è necessario aprire una posizione long. Il metodo deve essere riscritto se si prevede che venga generato un segnale di apertura di una posizione long.

virtual bool CheckOpenLong(double& price, double& sl, double& tp, datetime& expiration);

Il metodo deve implementare l'algoritmo di verifica della condizione di apertura di una posizione long. Se la condizione è soddisfatta, alle variabili di prezzo sl, tp e scadenza (riferimenti a cui vengono passati come parametri) devono essere assegnati dei valori appropriati e il metodo deve restituire true. Se la condizione non è soddisfatta, il metodo deve restituire false.

La classe base CExpertSignal non ha un algoritmo integrato per generare un segnale di apertura di una posizione long, quindi il metodo della classe base restituisce sempre false.

1.2.2 CheckOpenShort

Il metodo CheckOpenShort() genera un segnale di apertura di una posizione short, definendo il livello di ingresso e i livelli di immissione degli ordini protettivi. Viene chiamato da un expert per determinare se è necessario aprire una posizione short. Il metodo deve essere riscritto se si prevede che venga generato un segnale di apertura di una posizione short. 

virtual bool CheckOpenShort(double& price, double& sl, double& tp, datetime& expiration);

Il metodo deve implementare l'algoritmo per verificare la condizione per aprire una posizione short. Se la condizione è soddisfatta, alle variabili di prezzo sl, tp e scadenza (riferimenti a cui vengono passati come parametri) devono essere assegnati dei valori appropriati e il metodo deve restituire vero. Se la condizione non è soddisfatta, il metodo deve restituire false.

La classe base CExpertSignal non ha un algoritmo integrato per generare un segnale di apertura di una posizione short, quindi il metodo della classe base restituisce sempre false.


1.3. Metodi di controllo del segnale di chiusura della posizione:

1.3.1 CheckCloseLong

Il metodo CheckCloseLong() genera un segnale di chiusura di una posizione long, definendo il livello di uscita. Viene chiamato da un expert per determinare se è necessario chiudere una posizione long. Il metodo deve essere riscritto se si prevede che venga generato un segnale di chiusura di una posizione long.

virtual bool CheckCloseLong(double& price);

Il metodo deve implementare l'algoritmo per la verifica della condizione per chiudere la posizione long. Se la condizione è soddisfatta, alla variabile di prezzo (il cui riferimento è passato come parametro) deve essere assegnato il valore appropriato e il metodo deve restituire true. Se la condizione non è soddisfatta, il metodo deve restituire false.

La classe base CExpertSignal non possiede un algoritmo integrato per generare un segnale di chiusura di una posizione long, quindi il metodo della classe base restituisce sempre false.

1.3.2 CheckCloseShort

Il metodo CheckCloseShort() genera un segnale di chiusura di una posizione short, definendo il livello di uscita. Viene chiamato da un expert per determinare se è necessario chiudere una posizione short. Il metodo deve essere riscritto se si prevede che venga generato un segnale di chiusura di una posizione short.

virtual bool CheckCloseShort(double& price);

Il metodo deve implementare l'algoritmo per verificare la condizione per chiudere una posizione short. Se la condizione è soddisfatta, alla variabile di prezzo (il cui riferimento è passato come parametro) deve essere assegnato il valore appropriato e il metodo deve restituire true. Se la condizione non è soddisfatta, il metodo deve restituire false.

La classe base CExpertSignal non ha un algoritmo integrato per generare un segnale di chiusura di una posizione short, quindi il metodo della classe base restituisce sempre false.


1.4. Metodi di controllo del segnale di inversione della posizione:

1.4.1 CheckReverseLong

Il metodo CheckReverseLong genera un segnale di inversione di una posizione long, definendo il livello di inversione e i livelli di immissione degli ordini protettivi. Viene chiamato da un expert per determinare se è necessario invertire una posizione long. Il metodo deve essere riscritto se si prevede che venga generato un segnale di inversione della posizione long.

virtual bool CheckReverseLong(double& price, double& sl, double& tp, datetime& expiration);

Il metodo deve implementare l'algoritmo per la verifica della condizione di inversione della posizione long. Se la condizione è soddisfatta, alle variabili di prezzo sl, tp e scadenza (riferimenti a cui vengono passati come parametri) devono essere assegnati dei valori appropriati e il metodo deve restituire vero. Se la condizione non è soddisfatta, il metodo deve restituire false.

Nella classe base CExpertSignal è implementato il seguente algoritmo per la generazione di un segnale di inversione della posizione long:

  1. Verifica di un segnale per chiudere una posizione long
  2. Controllo di un segnale per aprire una posizione short
  3. Se entrambi i segnali sono attivi (le condizioni sono soddisfatte) e i prezzi di chiusura e di apertura corrispondono, alle variabili di prezzo sl, tp e scadenza (riferimenti a cui vengono passati come parametri) vengono assegnati i valori appropriati e il metodo restituisce true.
Se la condizione non è soddisfatta, il metodo restituisce false.

1.4.2 CheckReverseShort

Il metodo CheckReverseShort genera un segnale di inversione di una posizione short, definendo il livello di inversione e i livelli di immissione degli ordini protettivi. Viene chiamato da un expert per determinare se è necessario invertire una posizione short. Il metodo deve essere riscritto se si prevede che venga generato un segnale di inversione della posizione long secondo l'algoritmo diverso da quello implementato nella classe base.

virtual bool CheckReverseShort(double& price, double& sl, double& tp, datetime& expiration);

Il metodo deve implementare l'algoritmo per la verifica della condizione di inversione della posizione short. Se la condizione è soddisfatta, alle variabili di prezzo sl, tp e scadenza (riferimenti a cui vengono passati come parametri) devono essere assegnati dei valori appropriati e il metodo deve restituire vero. Se la condizione non è soddisfatta, il metodo deve restituire false.

Nella classe base CExpertSignal è implementato il seguente algoritmo per la generazione di un segnale di inversione della posizione short:

  1. Controllo di un segnale per chiudere una posizione short
  2. Verifica di un segnale per aprire una posizione long
  3. Se entrambi i segnali sono attivi (le condizioni sono soddisfatte) e i prezzi di chiusura e di apertura corrispondono, alle variabili di prezzo sl, tp e scadenza (riferimenti a cui vengono passati come parametri) vengono assegnati i valori appropriati e il metodo restituisce true.

Se la condizione non è soddisfatta, il metodo restituisce false.


1.5. Modalità di verifica del segnale di modifica dell'ordine in sospeso:

1.5.1 CheckTrailingOrderLong

Il metodo CheckTrailingOrderLong() genera il segnale di modifica di un ordine di acquisto in sospeso, definendo un nuovo prezzo dell'ordine. Viene chiamato da un expert per determinare se è necessario modificare un ordine di acquisto in sospeso. Il metodo deve essere riscritto se si prevede che venga generato un segnale di modifica di un ordine di acquisto in sospeso.

virtual bool CheckTrailingOrderLong(COrderInfo* order, double& price)

Il metodo deve implementare l'algoritmo per la verifica della condizione di modifica di un ordine di acquisto in sospeso. Se la condizione è soddisfatta, alla variabile di prezzo (il cui riferimento è passato come parametro) deve essere assegnato il valore appropriato e il metodo deve restituire true. Se la condizione non è soddisfatta, il metodo deve restituire false.

La classe base CExpertSignal non ha un algoritmo integrato per generare un segnale di modifica di un ordine di acquisto in sospeso, quindi il metodo della classe base restituisce sempre false.

1.5.2 CheckTrailingOrderShort

Il metodo CheckTrailingOrderShort() genera il segnale di modifica di un ordine di vendita in sospeso, definendo un nuovo prezzo dell'ordine. Viene chiamato da un expert per determinare se è necessario modificare un ordine di vendita in sospeso. Il metodo deve essere riscritto se si prevede che venga generato un segnale di modifica di un ordine di vendita in sospeso.

virtual bool CheckTrailingOrderShort(COrderInfo* order, double& price)

Il metodo deve implementare l'algoritmo per la verifica della condizione di modifica di un ordine di vendita in sospeso. Se la condizione è soddisfatta, alla variabile di prezzo (il cui riferimento è passato come parametro) deve essere assegnato il valore appropriato e il metodo deve restituire true. Se la condizione non è soddisfatta, il metodo deve restituire false.

La classe base CExpertSignal non possiede un algoritmo integrato per generare un segnale di modifica di un ordine di vendita in sospeso, quindi il metodo della classe base restituisce sempre false.


2. Sviluppa il tuo generatore di segnali di trading

A questo punto, dopo aver esaminato la struttura della classe base CExpertSignal, puoi iniziare a creare il tuo generatore di segnali di trading.

Come accennato in precedenza, la classe CExpertSignal è un insieme di "ropes" virtuali pubbliche, ovvero metodi grazie al cui utilizzo l'expert può conoscere l'opinione del generatore di segnali di trading sull'ingresso nel mercato in una direzione o nell'altra.

Pertanto, il nostro obiettivo principale è creare una nostra classe di generatori di segnali di trading derivandola dalla classe CExpertSignal e riscrivere i metodi virtuali appropriati implementando gli algoritmi richiesti.

Il nostro secondo problema (che non è meno importante) - è rendere la nostra classe "visibile" al Wizard MQL5. Ma andiamo con ordine.

2.1. Creare la classe del generatore di segnali di trading

Cominciamo.

Innanzitutto, creiamo (ad esempio, utilizzando sempre il Wizard MQL5) un file include con l'estensione mqh.

Vai su File e seleziona "Create" (o digita la combinazione Ctrl+N) e indica la creazione di un file include :

Figura 2. Creare un file include il Wizard utilizzando MQL5.

Figura 2. Crea un file include utilizzando il Wizard MQL5

Da precisare che, affinché il file venga poi "rilevato" dal Wizard MQL5 come generatore di segnale, deve essere creato nella cartella Include\Expert\Signal\.

Per non cestinarlo nella Libreria Standard, creiamo la nostra cartella Include\Expert\Signal\MySignals, nella quale creiamo il file SampleSignal.mqh specificando questi parametri nel Wizard MQL5:

Figura 3. Impostazione della posizione del file include

Figura 3. Impostazione della posizione del file include

Come risultato dell'operazione del Wizard MQL5 otteniamo il seguente schema:

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| defines                                                          |
//+------------------------------------------------------------------+
// #define MacrosHello   "Hello, world!"
// #define MacrosYear    2010
//+------------------------------------------------------------------+
//| DLL imports                                                      |
//+------------------------------------------------------------------+
// #import "user32.dll"
//   int      SendMessageA(int hWnd,int Msg,int wParam,int lParam);
// #import "my_expert.dll"
//   int      ExpertRecalculate(int wParam,int lParam);
// #import
//+------------------------------------------------------------------+
//| EX5 imports                                                      |
//+------------------------------------------------------------------+
// #import "stdlib.ex5"
//   string ErrorDescription(int error_code);
// #import
//+------------------------------------------------------------------+

Quello che segue è semplicemente un lavoro da svolgere "manualmente". Rimuovi le parti non necessarie e aggiungi ciò che ti occorre (includi il file ExpertSignal.mqh della Libreria Standard e una descrizione della classe che adesso è vuota).

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| include files                                                    |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
//+------------------------------------------------------------------+
//| The CSampleSignal class.                                         |
//| Purpose: Class of trading signal generator.                      |
//|          It is derived from the CExpertSignal class.             |
//+------------------------------------------------------------------+
class CSampleSignal : public CExpertSignal
  {
  };
//+------------------------------------------------------------------+

Ora è necessario scegliere gli algoritmi.

Come base per il nostro generatore di segnali di trading, prendiamo il modello diffuso "prezzo che attraversa la media mobile". Ma facciamo un'altra ipotesi: "Dopo aver attraversato la media mobile, il prezzo torna indietro e solo allora va nella giusta direzione". Riporta questo nel nostro file.

In genere, quando scrivi qualcosa, non fare l’avaro con i commenti. Dopo un po', leggere un codice attentamente commentato sarà davvero comodo.

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| include files                                                    |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
//+------------------------------------------------------------------+
//| Class CSampleSignal.                                             |
//| Purpose: Class of trading signal generator when price            |
//|          crosses moving average,                                 |
//|          entering on the subsequent back movement.               |
//|          It is derived from the CExpertSignal class.             |
//+------------------------------------------------------------------+
class CSampleSignal : public CExpertSignal
  {
  };
//+------------------------------------------------------------------+

Ora definiamo quali dati sono necessari per prendere decisioni sulla generazione dei segnali di trading. Nel nostro caso, questo è il prezzo di apertura e di chiusura della barra precedente e il valore della media mobile sulla stessa barra precedente.

Per accedere a questi dati, utilizziamo le classi della libreria standard CiOpen, CiClose e CiMA. Discuteremo gli indicatori e le serie temporali in seguito.

Nel frattempo, definiamo un elenco di impostazioni per il nostro generatore. Per prima cosa, dobbiamo impostare la media mobile. Questi parametri includono il periodo, lo spostamento lungo l'asse temporale, il metodo di media e l'oggetto della media. In secondo luogo, dobbiamo impostare il livello di ingresso e i livelli di immissione degli ordini protettivi e la durata degli ordini in sospeso, perché lavoreremo con questi ultimi.

Tutte le impostazioni del generatore verranno archiviate nei dati membri protetti della classe. L'accesso alle impostazioni sarà attuato attraverso apposite modalità pubbliche.

Includiamo queste modifiche nel nostro file:

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| include files                                                    |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
//+------------------------------------------------------------------+
//| The CSampleSignal class.                                         |
//| Purpose: Class of trading signal generator when price            |
//|             crosses moving average,                              |
//|             entering on the subsequent back movement.            |
//|             It is derived from the CExpertSignal class.          |
//+------------------------------------------------------------------+
class CSampleSignal : public CExpertSignal
  {
protected:
   //--- Setup parameters
   int                m_period_ma;       // averaging period of the MA
   int                m_shift_ma;        // shift of the MA along the time axis
   ENUM_MA_METHOD     m_method_ma;       // averaging method of the MA
   ENUM_APPLIED_PRICE m_applied_ma;      // averaging object of the MA
   double             m_limit;           // level to place a pending order relative to the MA
   double             m_stop_loss;       // level to place a stop loss order relative to the open price
   double             m_take_profit;     // level to place a take profit order relative to the open price
   int                m_expiration;      // lifetime of a pending order in bars

public:
   //--- Methods to set the parameters
   void               PeriodMA(int value)                 { m_period_ma=value;   }
   void               ShiftMA(int value)                  { m_shift_ma=value;    }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;   }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;  }
   void               Limit(double value)                 { m_limit=value;       }
   void               StopLoss(double value)              { m_stop_loss=value;   }
   void               TakeProfit(double value)            { m_take_profit=value; }
   void               Expiration(int value)               { m_expiration=value;  }
  };
//+------------------------------------------------------------------+

Poiché stiamo usando dati membri protetti, dobbiamo aggiungere un costruttore di classi in cui inizializzeremo questi dati per valori predefiniti.

Per controllare i parametri, riscriviamo il metodo virtuale ValidationSettings secondo la descrizione della classe base.

Descrizione della classe:

class CSampleSignal : public CExpertSignal
  {
protected:
   //--- Setup parameters
   int                m_period_ma;       // averaging period of the MA
   int                m_shift_ma;        // shift of the MA along the time axis
   ENUM_MA_METHOD     m_method_ma;       // averaging method of the MA
   ENUM_APPLIED_PRICE m_applied_ma;      // averaging object of the MA
   double             m_limit;            // level to place a pending order relative to the MA
   double             m_stop_loss;        // level to place a stop loss order relative to the open price
   double             m_take_profit;      // level to place a take profit order relative to the open price
   int                m_expiration;       // lifetime of a pending order in bars

public:
                      CSampleSignal();
   //--- Methods to set the parameters
   void               PeriodMA(int value)                 { m_period_ma=value;   }
   void               ShiftMA(int value)                  { m_shift_ma=value;    }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;   }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;  }
   void               Limit(double value)                 { m_limit=value;       }
   void               StopLoss(double value)              { m_stop_loss=value;   }
   void               TakeProfit(double value)            { m_take_profit=value; }
   void               Expiration(int value)               { m_expiration=value;  }
   //--- Methods to validate the parameters
   virtual bool       ValidationSettings();
  };

Implementazione del metodo ValidationSettings():


//+------------------------------------------------------------------+
//| Validation of the setup parameters.                              |
//| INPUT:  No.                                                      |
//| OUTPUT: true if the settings are correct, otherwise false.       |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::ValidationSettings()
  {
//--- Validation of parameters
   if(m_period_ma<=0)
     {
      printf(__FUNCTION__+": the MA period must be greater than zero");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+

Adesso, una volta terminato il grosso del lavoro preparatorio, parleremo meglio degli indicatori e delle serie temporali.

Gli indicatori e le serie temporali sono la fonte principale di informazioni per il processo decisionale (di certo puoi anche lanciare una moneta o basarti sulle fasi lunari, ma questi metodi sono piuttosto difficili da formalizzare).

Come abbiamo già detto sopra, per prendere decisioni abbiamo bisogno delle seguenti informazioni: il prezzo di apertura della barra precedente, il prezzo di chiusura della barra precedente e il valore della media mobile sulla stessa barra precedente.

Per accedere a questi dati, utilizzeremo le seguenti classi della Libreria Standard:

  • CiOpen, per accedere al prezzo di apertura della barra precedente;
  • CiClose, per accedere al prezzo di chiusura della barra precedente;
  • CiMA, per accedere al valore della media mobile sulla barra precedente.

Potresti chiederti: "Perché usare l'indicatore o le serie temporali "avvolte" in una classe per ottenere un singolo numero?"

C'è un significato nascosto che adesso sveleremo.

Come utilizzare i dati di un indicatore o di una serie temporale?

Per prima cosa, dobbiamo creare un indicatore.

In secondo luogo, dobbiamo copiare la quantità necessaria di dati in un buffer intermedio.

Terzo, dobbiamo verificare se la copia è completa.

Solo dopo questi passaggi puoi utilizzare i dati.

Utilizzando le classi della Libreria Standard si evita la necessità di creare un indicatore, di preoccuparsi della disponibilità di buffer intermedi e del caricamento dei dati o del rilascio di un handle. L'oggetto di una classe apposita lo farà per te. Tutti gli indicatori richiesti saranno generati dal nostro generatore di segnali durante la fase di inizializzazione e tutti gli indicatori saranno dotati del buffer temporaneo necessario . Inoltre, una volta aggiunto un oggetto indicatore o una serie temporale nella raccolta (l'oggetto di una classe speciale), puoi smettere di preoccuparti della pertinenza dei dati (i dati verranno aggiornati automaticamente dall'expert).

Collocheremo gli oggetti di queste classi nei dati membri protetti. Per ogni oggetto creiamo un metodo di inizializzazione e un metodo di accesso ai dati.

Riscriviamo il metodo virtuale InitIndicators (secondo la descrizione della classe base).

Descrizione della classe:

class CSampleSignal : public CExpertSignal
  {
protected:
   CiMA               m_MA;              // object to access the values om the moving average
   CiOpen             m_open;            // object to access the bar open prices
   CiClose            m_close;           // object to access the bar close prices
   //--- Setup parameters
   int                m_period_ma;       // averaging period of the MA
   int                m_shift_ma;        // shift of the MA along the time axis
   ENUM_MA_METHOD     m_method_ma;       // averaging method of the MA
   ENUM_APPLIED_PRICE m_applied_ma;      // averaging object of the MA
   double             m_limit;            // level to place a pending order relative to the MA
   double             m_stop_loss;        // level to place a stop loss order relative to the open price
   double             m_take_profit;      // level to place a take profit order relative to the open price
   int                m_expiration;      // lifetime of a pending order in bars

public:
                      CSampleSignal();
   //--- Methods to set the parameters
   void               PeriodMA(int value)                 { m_period_ma=value;              }
   void               ShiftMA(int value)                  { m_shift_ma=value;               }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;              }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;             }
   void               Limit(double value)                 { m_limit=value;                  }
   void               StopLoss(double value)              { m_stop_loss=value;              }
   void               TakeProfit(double value)            { m_take_profit=value;            }
   void               Expiration(int value)               { m_expiration=value;             }
   //--- Method to validate the parameters
   virtual bool       ValidationSettings();
   //--- Method to validate the parameters
   virtual bool       InitIndicators(CIndicators* indicators);

protected:
   //--- Object initialization method
   bool               InitMA(CIndicators* indicators);
   bool               InitOpen(CIndicators* indicators);
   bool               InitClose(CIndicators* indicators);
   //--- Methods to access object data
   double             MA(int index)                       { return(m_MA.Main(index));       }
   double             Open(int index)                     { return(m_open.GetData(index));  }
   double             Close(int index)                    { return(m_close.GetData(index)); }
  };

Implementazione dei metodi InitIndicators, InitMA, InitOpen, InitClose:

//+------------------------------------------------------------------+
//| Initialization of indicators and timeseries.                     |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitIndicators(CIndicators* indicators)
  {
//--- Validation of the pointer
   if(indicators==NULL)       return(false);
//--- Initialization of the moving average
   if(!InitMA(indicators))    return(false);
//--- Initialization of the timeseries of open prices
   if(!InitOpen(indicators))  return(false);
//--- Initialization of the timeseries of close prices
   if(!InitClose(indicators)) return(false);
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the moving average                             |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitMA(CIndicators* indicators)
  {
//--- Initialization of the MA object
   if(!m_MA.Create(m_symbol.Name(),m_period,m_period_ma,m_shift_ma,m_method_ma,m_applied_ma))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
   m_MA.BufferResize(3+m_shift_ma);
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_MA)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the timeseries of open prices.                 |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitOpen(CIndicators* indicators)
  {
//--- Initialization of the timeseries object
   if(!m_open.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_open)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the timeseries of close prices.                |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitClose(CIndicators* indicators)
  {
//--- Initialization of the timeseries object
   if(!m_close.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_close)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+

Tutti i lavori preparatori sono stati completati. Come puoi vedere, la nostra classe è cresciuta in modo significativo.

Ma ora siamo pronti per generare i segnali di trading.

Figura 4. Segnali di trading per il prezzo che attraversa la media mobile

Figura 4. Segnali di trading per il prezzo che attraversano la media mobile

Consideriamo di nuovo i nostri algoritmi in modo più dettagliato.

1. Il segnale di acquisto appare quando sono state soddisfatte le seguenti condizioni sulla barra precedente:

  • il prezzo di apertura della barra è inferiore al valore della media mobile,
  • il prezzo di chiusura della barra è maggiore del valore della media mobile,
  • la media mobile è in aumento.

In questo caso, ci offriamo di inserire un ordine di acquisto in sospeso con i parametri definiti dalle impostazioni. A questo scopo, riscriviamo il metodo virtuale CheckOpenLong e lo compiliamo con la funzione corrispondente.

2. Il segnale di vendita appare quando le seguenti condizioni sono state soddisfatte sulla barra precedente:

  • il prezzo di apertura della barra è maggiore del valore della media mobile,
  • il prezzo di chiusura della barra è inferiore al valore della media mobile,
  • la media mobile sta diminuendo.

In questo caso, ci offriamo di inserire un ordine di vendita in sospeso con i parametri definiti dalle impostazioni. A tal fine, sovrascriviamo il metodo virtuale CheckOpenShort e lo compiliamo con la funzione corrispondente.

3. Non genereremo dei segnali per chiudere le posizioni. Lascia che le posizioni vengano chiuse da Stop Loss/Take Profit ордерам.

Di conseguenza, non sovrascriveremo i metodi virtuali CheckCloseLong e CheckCloseShort.

4. Proporremo la modifica di un ordine in sospeso lungo la media mobile alla "distanza" specificata dalle impostazioni.

 A questo scopo, sovrascriviamo i metodi virtuali CheckTrailingOrderLong e CheckTrailingOrderShort, compilandoli con la funzione corrispondente.

Descrizione della classe:

class CSampleSignal : public CExpertSignal
  {
protected:
   CiMA               m_MA;              // object to access the values of the moving average
   CiOpen             m_open;            // object to access the bar open prices
   CiClose            m_close;           // object to access the bar close prices
   //--- Setup parameters
   int                m_period_ma;       // averaging period of the MA
   int                m_shift_ma;        // shift of the MA along the time axis
   ENUM_MA_METHOD     m_method_ma;       // averaging method of the MA
   ENUM_APPLIED_PRICE m_applied_ma;      // averaging object of the MA
   double             m_limit;            // level to place a pending order relative to the MA
   double             m_stop_loss;        // level to place a stop loss order relative to the open price
   double             m_take_profit;      // level to place a take profit order relative to the open price
   int                m_expiration;       // lifetime of a pending order in bars

public:
                      CSampleSignal();
   //--- Methods to set the parameters

   void               PeriodMA(int value)                 { m_period_ma=value;              }
   void               ShiftMA(int value)                  { m_shift_ma=value;               }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;              }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;             }
   void               Limit(double value)                 { m_limit=value;                  }
   void               StopLoss(double value)              { m_stop_loss=value;              }
   void               TakeProfit(double value)            { m_take_profit=value;            }
   void               Expiration(int value)               { m_expiration=value;             }
   //--- Method to validate the parameters
   virtual bool       ValidationSettings();
   //--- Method to validate the parameters
   virtual bool       InitIndicators(CIndicators* indicators);
   //--- Methods to generate signals to enter the market
   virtual bool      CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration);
   virtual bool      CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration);
   //--- Methods to generate signals of pending order modification
   virtual bool      CheckTrailingOrderLong(COrderInfo* order,double& price);
   virtual bool      CheckTrailingOrderShort(COrderInfo* order,double& price);

protected:
   //--- Object initialization method
   bool               InitMA(CIndicators* indicators);
   bool               InitOpen(CIndicators* indicators);
   bool               InitClose(CIndicators* indicators);
   //--- Methods to access object data
   double             MA(int index)                       { return(m_MA.Main(index));       }
   double             Open(int index)                     { return(m_open.GetData(index));  }
   double             Close(int index)                    { return(m_close.GetData(index)); }
  };

Implementazione dei metodi CheckOpenLong, CheckOpenShort, CheckTrailingOrderLong, CheckTrailingOrderShort:

//+------------------------------------------------------------------+
//| Check whether a Buy condition is fulfilled                       |
//| INPUT:  price      - variable for open price                     |
//|         sl         - variable for stop loss price,               |
//|         tp         - variable for take profit price              |
//|         expiration - variable for expiration time.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration)
  {
//--- Preparing the data
   double spread=m_symbol.Ask()-m_symbol.Bid();
   double ma    =MA(1);
   double unit  =PriceLevelUnit();
//--- Checking the condition
   if(Open(1)<ma && Close(1)>ma && ma>MA(2))
     {
      price=m_symbol.NormalizePrice(ma-m_limit*unit+spread);
      sl   =m_symbol.NormalizePrice(price-m_stop_loss*unit);
      tp   =m_symbol.NormalizePrice(price+m_take_profit*unit);
      expiration+=m_expiration*PeriodSeconds(m_period);
      //--- Condition is fulfilled
      return(true);
     }
//--- Condition is not fulfilled
   return(false);
  }
//+------------------------------------------------------------------+
//| Check whether a Sell condition is fulfilled.                     |
//| INPUT:  price      - variable for open price,                    |
//|         sl         - variable for stop loss,                     |
//|         tp         - variable for take profit                    |
//|         expiration - variable for expiration time.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration)
  {
//--- Preparing the data
   double ma  =MA(1);
   double unit=PriceLevelUnit();
//--- Checking the condition
   if(Open(1)>ma && Close(1)<ma && ma<MA(2))
     {
      price=m_symbol.NormalizePrice(ma+m_limit*unit);
      sl   =m_symbol.NormalizePrice(price+m_stop_loss*unit);
      tp   =m_symbol.NormalizePrice(price-m_take_profit*unit);
      expiration+=m_expiration*PeriodSeconds(m_period);
      //--- Condition is fulfilled
      return(true);
     }
//--- Condition is not fulfilled
   return(false);
  }
//+------------------------------------------------------------------+
//| Check whether the condition of modification                      |
//|  of a Buy order is fulfilled.                                    |
//| INPUT:  order - pointer at the object-order,                     |
//|         price - a variable for the new open price.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckTrailingOrderLong(COrderInfo* order,double& price)
  {
//--- Checking the pointer
   if(order==NULL) return(false);
//--- Preparing the data
   double spread   =m_symbol.Ask()-m_symbol.Bid();
   double ma       =MA(1);
   double unit     =PriceLevelUnit();
   double new_price=m_symbol.NormalizePrice(ma-m_limit*unit+spread);
//--- Checking the condition
   if(order.PriceOpen()==new_price) return(false);
   price=new_price;
//--- Condition is fulfilled
   return(true);
  }
//+------------------------------------------------------------------+
//| Check whether the condition of modification                      |
//| of a Sell order is fulfilled.                                    |
//| INPUT:  order - pointer at the object-order,                     |
//|         price - a variable for the new open price.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckTrailingOrderShort(COrderInfo* order,double& price)
  {
//--- Checking the pointer
   if(order==NULL) return(false);
//--- Preparing the data
   double ma  =MA(1);
   double unit=PriceLevelUnit();
   double new_price=m_symbol.NormalizePrice(ma+m_limit*unit);
//--- Checking the condition
   if(order.PriceOpen()==new_price) return(false);
   price=new_price;
//--- Condition is fulfilled
   return(true);
  }
//+------------------------------------------------------------------+

Quindi abbiamo risolto il primo problema. Il codice sopra è un codice sorgente della classe di generatori di segnali di trading che soddisfa il nostro compito principale.


2.2. Preparare la descrizione della classe creata dei segnali di trading per il Wizard MQL5

Passiamo ora alla risoluzione del secondo problema. Il nostro segnale deve essere "riconosciuto" dal generatore di strategie di trading del Wizard MQL5.

Abbiamo soddisfatto la prima condizione necessaria: abbiamo posizionato il file dove verrà "trovato" dal Wizard MQL5. Ma questo non basta. Il Wizard MQL5 non deve solo "trovare" il file, ma anche "riconoscerlo". Per fare ciò dobbiamo aggiungere al testo originale il descrittore di classe per il Wizard MQL5.

Un descrittore di classe è un blocco di commenti composto secondo determinate regole.

Prendiamo in considerazione queste regole.

1. Il blocco di commenti deve iniziare con le seguenti righe:

// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |

2. La riga successiva è un descrittore di testo (ciò che vedremo nel Wizard MQL5 quando si sceglie il segnale) nel formato "//| Title=<Text> |". Se il testo è troppo grande per una riga, puoi aggiungere un'altra riga (ma non di più) dopo di essa. 

Nel nostro caso abbiamo quanto segue:

//| Title=Signal on the crossing of a price and the MA               |
//| entering on its back movement                                    |

3. Ecco quindi una riga con il tipo di classe specificato nel formato "//| Type=<Type> |". Il campo <Type> deve avere il valore Signal (oltre ai segnali, il Wizard MQL5 conosce altri tipi di classi).

Scrivi:

//| Type=Signal                                                      |

4. La riga seguente nel formato "//| Name=<Name> |" è il nome breve del segnale (viene utilizzato dal Wizard MQL5 per generare i nomi delle variabili globali dell'expert).

Otteniamo quanto segue:

//| Name=Sample                                                      |

5. Il nome di una classe è un elemento importante della descrizione. Nella riga con il formato "//| Class=<ClassNameа> |", il parametro <ClassName> deve corrispondere al nome della nostra classe:

//| Class=CSampleSignal                                              |

6. Non compiliamo questa riga, ma deve essere presente (questo è un link alla sezione di riferimento della lingua):

//| Page=                                                            |

7. Inoltre, ci sono le descrizioni dei parametri di configurazione del segnale.

Questo è un insieme di righe (il numero di righe è uguale al numero di parametri).

Il formato di ogni riga è "//| Parameter=<NameOfMethod>,<TypeOfParameter>,<DefaultValue> |".

Ecco il nostro set di parametri:

//| Parameter=PeriodMA,int,12                                        |
//| Parameter=ShiftMA,int,0                                          |
//| Parameter=MethodMA,ENUM_MA_METHOD,MODE_EMA                       |
//| Parameter=AppliedMA,ENUM_APPLIED_PRICE,PRICE_CLOSE               |
//| Parameter=Limit,double,0.0                                       |
//| Parameter=StopLoss,double,50.0                                   |
//| Parameter=TakeProfit,double,50.0                                 |
//| Parameter=Expiration,int,10                                      |

8. Il blocco di commento deve terminare con le seguenti righe:

//+------------------------------------------------------------------+
// wizard description end

Aggiungiamo il descrittore al codice sorgente.

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| include files                                                    |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signal on crossing of the price and the MA                 |
//| entering on the back movement                                    |
//| Type=Signal                                                      |
//| Name=Sample                                                      |
//| Class=CSampleSignal                                              |
//| Page=                                                            |
//| Parameter=PeriodMA,int,12                                        |
//| Parameter=ShiftMA,int,0                                          |
//| Parameter=MethodMA,ENUM_MA_METHOD,MODE_EMA                       |
//| Parameter=AppliedMA,ENUM_APPLIED_PRICE,PRICE_CLOSE               |
//| Parameter=Limit,double,0.0                                       |
//| Parameter=StopLoss,double,50.0                                   |
//| Parameter=TakeProfit,double,50.0                                 |
//| Parameter=Expiration,int,10                                      |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| CSampleSignal class.                                             |
//| Purpose: Class of trading signal generator when price            |
//|             crosses moving average,                              |
//|             entering on the subsequent back movement.            |
//|             It is derived from the CExpertSignal class.          |
//+------------------------------------------------------------------+
class CSampleSignal : public CExpertSignal
  {
protected:
   CiMA               m_MA;               // object to access the values of the moving average
   CiOpen             m_open;             // object to access the bar open prices
   CiClose            m_close;            // object to access the bar close prices
   //--- Setup parameters
   int                m_period_ma;        // averaging period of the MA
   int                m_shift_ma;         // shift of the MA along the time axis
   ENUM_MA_METHOD     m_method_ma;        // averaging method of the MA
   ENUM_APPLIED_PRICE m_applied_ma;       // averaging object of the MA
   double             m_limit;            // level to place a pending order relative to the MA
   double             m_stop_loss;        // level to place a stop loss order relative to the open price
   double             m_take_profit;      // level to place a take profit order relative to the open price
   int                m_expiration;       // lifetime of a pending order in bars

public:
                      CSampleSignal();
   //--- Methods to set the parameters
   void               PeriodMA(int value)                 { m_period_ma=value;              }
   void               ShiftMA(int value)                  { m_shift_ma=value;               }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;              }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;             }
   void               Limit(double value)                 { m_limit=value;                  }
   void               StopLoss(double value)              { m_stop_loss=value;              }
   void               TakeProfit(double value)            { m_take_profit=value;            }
   void               Expiration(int value)               { m_expiration=value;             }
   //---Method to validate the parameters
   virtual bool       ValidationSettings();
   //--- Method to validate the parameters
   virtual bool       InitIndicators(CIndicators* indicators);
   //--- Methods to generate signals to enter the market
   virtual bool      CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration);
   virtual bool      CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration);
   //--- Methods to generate signals of pending order modification
   virtual bool      CheckTrailingOrderLong(COrderInfo* order,double& price);
   virtual bool      CheckTrailingOrderShort(COrderInfo* order,double& price);

protected:
   //--- Object initialization method
   bool               InitMA(CIndicators* indicators);
   bool               InitOpen(CIndicators* indicators);
   bool               InitClose(CIndicators* indicators);
   //--- Methods to access object data
   double             MA(int index)                       { return(m_MA.Main(index));       }
   double             Open(int index)                     { return(m_open.GetData(index));  }
   double             Close(int index)                    { return(m_close.GetData(index)); }
  };
//+------------------------------------------------------------------+
//| CSampleSignal Constructor.                                       |
//| INPUT:  No.                                                      |
//| OUTPUT: No.                                                      |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
void CSampleSignal::CSampleSignal()
  {
//--- Setting the default values
   m_period_ma  =12;
   m_shift_ma   =0;
   m_method_ma  =MODE_EMA;
   m_applied_ma =PRICE_CLOSE;
   m_limit      =0.0;
   m_stop_loss  =50.0;
   m_take_profit=50.0;
   m_expiration =10;
  }
//+------------------------------------------------------------------+
//| Validation of parameters.                                        |
//| INPUT:  No.                                                      |
//| OUTPUT: true if the settings are correct, otherwise false.       |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::ValidationSettings()
  {
//--- Validation of parameters
   if(m_period_ma<=0)
     {
      printf(__FUNCTION__+": the MA period must be greater than zero");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of indicators and timeseries.                     |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitIndicators(CIndicators* indicators)
  {
//--- Validation of the pointer
   if(indicators==NULL)       return(false);
//--- Initialization of the moving average
   if(!InitMA(indicators))    return(false);
//--- Initialization of the timeseries of open prices
   if(!InitOpen(indicators))  return(false);
//--- Initialization of the timeseries of close prices
   if(!InitClose(indicators)) return(false);
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the moving average                             |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitMA(CIndicators* indicators)
  {
//--- Initialization of the MA object
   if(!m_MA.Create(m_symbol.Name(),m_period,m_period_ma,m_shift_ma,m_method_ma,m_applied_ma))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
   m_MA.BufferResize(3+m_shift_ma);
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_MA)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the timeseries of open prices.                 |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitOpen(CIndicators* indicators)
  {
//--- Initialization of the timeseries object
   if(!m_open.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_open)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the timeseries of close prices.                |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitClose(CIndicators* indicators)
  {
//--- Initialization of the timeseries object
   if(!m_close.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_close)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Check whether a Buy condition is fulfilled                       |
//| INPUT:  price      - variable for open price                     |
//|         sl         - variable for stop loss price,               |
//|         tp         - variable for take profit price              |
//|         expiration - variable for expiration time.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration)
  {
//--- Preparing the data
   double spread=m_symbol.Ask()-m_symbol.Bid();
   double ma    =MA(1);
   double unit  =PriceLevelUnit();
//--- Checking the condition
   if(Open(1)<ma && Close(1)>ma && ma>MA(2))
     {
      price=m_symbol.NormalizePrice(ma-m_limit*unit+spread);
      sl   =m_symbol.NormalizePrice(price-m_stop_loss*unit);
      tp   =m_symbol.NormalizePrice(price+m_take_profit*unit);
      expiration+=m_expiration*PeriodSeconds(m_period);
      //--- Condition is fulfilled
      return(true);
     }
//--- Condition is not fulfilled
   return(false);
  }
//+------------------------------------------------------------------+
//| Check whether a Sell condition is fulfilled.                     |
//| INPUT:  price      - variable for open price,                    |
//|         sl         - variable for stop loss,                     |
//|         tp         - variable for take profit                    |
//|         expiration - variable for expiration time.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration)
  {
//--- Preparing the data
   double ma  =MA(1);
   double unit=PriceLevelUnit();
//--- Checking the condition
   if(Open(1)>ma && Close(1)<ma && ma<MA(2))
     {
      price=m_symbol.NormalizePrice(ma+m_limit*unit);
      sl   =m_symbol.NormalizePrice(price+m_stop_loss*unit);
      tp   =m_symbol.NormalizePrice(price-m_take_profit*unit);
      expiration+=m_expiration*PeriodSeconds(m_period);
      //--- Condition is fulfilled
      return(true);
     }
//--- Condition is not fulfilled
   return(false);
  }
//+------------------------------------------------------------------+
//| Check whether the condition of modification                      |
//|  of a Buy order is fulfilled.                                    |
//| INPUT:  order - pointer at the object-order,                     |
//|         price - a variable for the new open price.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckTrailingOrderLong(COrderInfo* order,double& price)
  {
//--- Checking the pointer
   if(order==NULL) return(false);
//--- Preparing the data
   double spread   =m_symbol.Ask()-m_symbol.Bid();
   double ma       =MA(1);
   double unit     =PriceLevelUnit();
   double new_price=m_symbol.NormalizePrice(ma-m_limit*unit+spread);
//--- Checking the condition
   if(order.PriceOpen()==new_price) return(false);
   price=new_price;
//--- Condition is fulfilled
   return(true);
  }
//+------------------------------------------------------------------+
//| Check whether the condition of modification                      |
//| of a Sell order is fulfilled.                                    |
//| INPUT:  order - pointer at the object-order,                     |
//|         price - a variable for the new open price.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckTrailingOrderShort(COrderInfo* order,double& price)
  {
//--- Checking the pointer
   if(order==NULL) return(false);
//--- Preparing the data
   double ma  =MA(1);
   double unit=PriceLevelUnit();
   double new_price=m_symbol.NormalizePrice(ma+m_limit*unit);
//--- Checking the condition
   if(order.PriceOpen()==new_price) return(false);
   price=new_price;
//--- Condition is fulfilled
   return(true);
  }
//+------------------------------------------------------------------+

Bene, questo è tutto. Il segnale è pronto per l'uso.

Affinché il Wizard MQL5 generatore di strategie di trading sia in grado di utilizzare il nostro segnale, dobbiamo riavviare MetaEditor (la procedura guidata MQL5 esegue la scansione della cartella Include\Expert solo all'avvio).

Dopo aver riavviato MetaEditor, il modulo di segnali di trading creato può essere utilizzato nel Wizard MQL5:

Figura 5. Il generatore di segnali di trading creato nel Wizard MQL5

Figura 5. Il generatore di segnali di trading creato nel Wizard MQL5

Sono ora disponibili i parametri di input specificati nella sezione di descrizione dei parametri del generatore di segnali di trading:

Figura 6. Parametri di input del generatore di segnali di trading creato nel Wizard MQL5

Figura 6. Parametri di input del generatore di segnali di trading creato nel Wizard MQL5

I valori migliori dei parametri di input della strategia di trading implementata si possono trovare utilizzando lo Strategy Tester del MetaTrader 5 .


Conclusione

Il generatore di strategie di trading del Wizard MQL5 semplifica enormemente il test delle idee di trading. Il codice dell'expert generato si basa sulle classi di strategie di trading della Libreria Standard, le quali vengono utilizzate per creare determinate implementazioni di classi di segnali di trading, classi di gestione del denaro e del rischio e classi di supporto della posizione. 

L'articolo parla di come scrivere la propria classe di segnali di trading con l'implementazione di segnali sull'incrocio del prezzo e della media mobile e come includerla nel generatore di strategie di trading del Wizard MQL5, oltre a descrivere la struttura e il formato della descrizione della classe generata per la procedura guidata MQL5.

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

File allegati |
samplesignal.mqh (15.49 KB)
Approccio econometrico all'analisi dei grafici Approccio econometrico all'analisi dei grafici
Questo articolo descrive in particolare i metodi econometrici di analisi, l'analisi di autocorrelazione e l'analisi della varianza condizionale. Qual è il vantaggio dell'approccio qui descritto? L'uso dei modelli GARCH non lineari consente di rappresentare formalmente la serie analizzata dal punto di vista matematico e di creare una previsione per un numero specificato di passaggi.
Il Wizard MQL5: Come creare un modulo di gestione del rischio e del denaro Il Wizard MQL5: Come creare un modulo di gestione del rischio e del denaro
Il generatore di strategie di trading del Wizard MQL5 semplifica enormemente il test delle idee di trading. L'articolo descrive come sviluppare un modulo personalizzato di gestione del rischio e del denaro e abilitarlo nella procedura guidata MQL5. Ad esempio, abbiamo considerato un algoritmo di gestione del denaro in cui la dimensione del volume degli scambi è determinata dai risultati dell'operazione precedente. Nell'articolo sono discussi anche la struttura e il formato della descrizione della classe creata per la procedura guidata MQL5.
Le tabelle elettroniche in MQL5 Le tabelle elettroniche in MQL5
L'articolo descrive una classe di array bidimensionali e dinamici contenente dati di tipo diverso nella sua prima dimensione. La memorizzazione dei dati sotto forma di tabella è utile per risolvere un'ampia gamma di problemi di disposizione, memorizzazione e funzionamento con informazioni associate di diverso tipo. Il codice sorgente della classe che implementa la funzionalità di lavorare con le tabelle è allegato all'articolo.
Wizard MQL5: Come creare un modulo di trailing delle posizioni aperte Wizard MQL5: Come creare un modulo di trailing delle posizioni aperte
Il generatore di strategie di trading del Wizard MQL5 semplifica enormemente la verifica delle idee di trading. L'articolo parla di come scrivere e connettere al generatore di strategie di trading Wizard MQL5 la tua classe di gestione delle posizioni aperte spostando il livello di Stop Loss in una zona senza perdite quando il prezzo va nella direzione della posizione, consentendo di proteggere i tuoi drawdown di diminuzione del profitto quando fai trading. Descrive anche la struttura e il formato della descrizione della classe creata per il Wizard MQL5.