English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Un'altra classe OOP MQL5

Un'altra classe OOP MQL5

MetaTrader 5Esempi | 11 gennaio 2022, 17:02
178 0
laplacianlab
[Eliminato]

Introduzione

Costruire un EA completo orientato agli oggetti che funzioni davvero è a mio modesto parere un compito impegnativo che richiede molte abilità: ragionamento logico, pensiero divergente, capacità di analisi e sintesi, immaginazione, ecc. Diciamo che se il sistema di trading automatizzato che dobbiamo risolvere fosse una partita a scacchi, la sua idea di trading sarebbe la strategia degli scacchi. E l'esecuzione della strategia scacchistica attraverso le tattiche sarebbe la programmazione del robot con l'uso di indicatori tecnici, figure grafici, idee economiche fondamentali e assiomi concettuali.

Dettaglio della Scuola di Atene di Raffaello Sanzio

Figura 1. Particolare della Scuola di Atene di Raffaello Sanzio. In questa immagine vediamo i filosofi Platone e Aristotele impegnati in una profonda discussione.
Platone rappresenta qui il mondo concettuale e Aristotele il mondo empirista.

Sono consapevole della difficoltà di questo esercizio. Un OO EA non è estremamente difficile da programmare, ma è vero che presenta un certo grado di difficoltà per le persone con poca esperienza nello sviluppo di applicazioni. Come in ogni altra disciplina, questo è, a sua volta, dovuto alla mancanza di esperienza stessa, ecco perché cerco di insegnarti questo argomento attraverso un esempio specifico che sono sicuro che capirai. Non scoraggiarti se ti senti ancora insicuro nel gestire i concetti OOP, troverai le cose molto più facili una volta implementati i tuoi primi cinque EA, diciamo. Non devi costruire nulla da zero per ora, basta capire cosa spiego qui!

L'intero processo di ideazione e implementazione di un sistema di trading può essere semplificato in molti sensi quando viene eseguito da più persone, anche se questo fatto pone il problema della comunicazione. Voglio dire che la persona che concepisce la strategia di investimento non è tenuta a gestire i concetti di programmazione che gestisce il programmatore. E lo sviluppatore MQL5 potrebbe non capire all'inizio alcuni aspetti importanti della strategia di trading dei propri clienti.

Questo è un problema classico nell'ingegneria del software che ha portato alla creazione di molte metodologie di sviluppo software come Scrum, Test Driven Development (TDD), Extreme programming (XP), etc. È fondamentale essere consapevoli delle insidie del linguaggio. A proposito, per quanto ne sarà a tua conoscenza, Wikipedia afferma: "la metodologia di sviluppo del software o la metodologia di sviluppo del sistema nell'ingegneria del software è un quadro che viene utilizzato per strutturare, pianificare e controllare il processo di sviluppo di un sistema informativo".

Assumeremo di essere in grado di concepire e implementare rapidamente idee di trading di successo. Possiamo anche supporre di essere alla fine di un processo di sviluppo iterativo in cui il sistema di trading pensato dal nostro cliente è già stato ben definito e compreso da tutti. Come preferisci. A proposito, d'ora in poi farò riferimento in questo testo ad alcuni articoli educativi disponibili in ARTICOLI DI PROGRAMMAZIONE MQL5 in modo da poter controllare e ricordare rapidamente alcune idee, quando necessario, per eseguire con successo questo esercizio. Sei pronto?


1. I tuoi primi passi nell'adozione del nuovo paradigma


1.1. Perché OOP è buono per programmare i tuoi EA Forex?

Forse ti stai chiedendo a questo punto perché devi fare questa cosa. Lascia che ti dica prima di tutto che non sei costretto ad essere OOP. In ogni caso sarebbe bene essere un OOP per poter fare un ulteriore passo avanti nella tua conoscenza della programmazione dei sistemi di trading automatizzati.

Il modo classico di sviluppare applicazioni, la cosiddetta programmazione procedurale, presenta questi inconvenienti:

  • Rende difficile modellare i problemi. Sotto questo vecchio paradigma la soluzione del problema principale è ridotta e divisa in più semplici sottoproblemi risolti da moduli funzionali, vale a dire: funzioni e procedure.
  • Rende difficile il riutilizzo del codice, il che a sua volta ostacola i costi, l'affidabilità, la flessibilità e la manutenzione.

Il riutilizzo del codice è più semplice con il nuovo stile orientato agli oggetti. Questo è molto importante! Molti esperti ritengono che il riutilizzo del codice sia la vera soluzione alla maggior parte dei problemi di sviluppo software.

A questo punto dobbiamo menzionare tipi di dati astratti (ADT). OOP consente la creazione di ADT. Un ADT è un'astrazione del concetto tradizionale di tipo di dati che è presente in tutti i linguaggi di programmazione. Il suo uso principale è quello di comodamente definire il dominio dati delle applicazioni. Include\Arrays\Array.mqh, Include\Arrays\List.mqh e Include\Arrays\Tree.mqh sono alcuni esempi di tipi di dati astratti MQL5.

In in breve, il paradigma di programmazione orientato agli oggetti vuole che tu progetti le applicazioni a livello concettuale per consentirti di trarre vantaggio dal riutilizzo del codice, dall’affidabilità, dalla flessibilità e dalla facilità di manutenzione.

1.2. Sei un ragionatore concettuale? UML viene in soccorso

Hai mai sentito parlare di UML? UML è l'acronimo di Unified Modeling Language. È un linguaggio grafico per la progettazione di sistemi orientati agli oggetti. Noi umani dovremmo prima pensare ai nostri sistemi nella fase di analisi e poi codificarli con un linguaggio di programmazione. Andare dall'alto verso il basso è meno folle per gli sviluppatori. Tuttavia, la mia esperienza come analista dice che a volte questo non è possibile a causa di diverse cose: l'app deve essere fatta in un tempo molto breve, non c'è nessuno nel team che possa applicare rapidamente la propria conoscenza di UML, o forse alcune persone del team non conoscono alcune parti di UML.

UML è a mio parere un buon strumento di analisi che puoi usare se ti senti a tuo agio con esso e se le circostanze che circondano il progetto sono ok. Per favore, leggi Come sviluppare un Expert Advisor utilizzando UML Tools se sei interessato ad esplorare l'argomento UML. Quell'articolo è forse un po 'travolgente, ma serve a ottenere un quadro generale su come gli ingegneri del software professionisti lavorano la loro analisi. Dovresti completare un corso di diverse settimane per comprendere appieno UML! Per ora va bene sapere cos'è UML. Secondo la mia esperienza questo strumento di analisi non viene sempre utilizzato in tutti i progetti software a causa di diverse circostanze presenti nel mondo reale.

UML logo

Figura 2. Logo UML.


1.3. Salve, mondo! La tua prima classe OO

Se sei un principiante completo della programmazione orientata agli oggetti, ti consiglio di leggere prima la documentazione ufficiale su OO disponibile in MQL5 Reference e quindi dare un'occhiata a Scrivere un expert advisor utilizzando l'approccio di programmazione orientato agli oggetti MQL5 per ottenere le basi. Assicurati di integrare queste letture con altri materiali. D'ora in poi presumo che tu conosca già qualche OOP, quindi capirai facilmente il classico esempio della classe Person che in MQL5 è il seguente:

//+------------------------------------------------------------------+
//| CPerson Class                                                    |
//+------------------------------------------------------------------+
class CPerson
  {
protected:
   string            m_first_name;
   string            m_surname;
   datetime          m_birth;

public:
   //--- Constructor and destructor methods
                     CPerson(void);
                    ~CPerson(void);
   //--- Getter methods
   string            GetFirstName(void);
   string            GetSurname(void);
   datetime          GetBirth(void);
   //--- Setter methods
   void              SetFirstName(string first_name);
   void              SetSurname(string surname);
   void              SetBirth(datetime birth);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CPerson::CPerson(void)
  {
   Alert("Hello world! I am run when an object of type CPerson is created!");
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CPerson::~CPerson(void)
  {
   Alert("Goodbye world! I am run when the object is destroyed!");
  }
//+------------------------------------------------------------------+
//| GetFirstName                                                     |
//+------------------------------------------------------------------+
string CPerson::GetFirstName(void)
  {
   return m_first_name;
  }
//+------------------------------------------------------------------+
//| GetSurname                                                       |
//+------------------------------------------------------------------+
string CPerson::GetSurname(void)
  {
   return m_surname;
  }
//+------------------------------------------------------------------+
//| GetBirth                                                         |
//+------------------------------------------------------------------+
datetime CPerson::GetBirth(void)
  {
   return m_birth;
  }
//+------------------------------------------------------------------+
//| SetFirstName                                                     |
//+------------------------------------------------------------------+
void CPerson::SetFirstName(string first_name)
  {
   m_first_name=first_name;
  }
//+------------------------------------------------------------------+
//| SetSurname                                                       |
//+------------------------------------------------------------------+
void CPerson::SetSurname(string surname)
  {
   m_surname=surname;
  }
//+------------------------------------------------------------------+
//| SetBirth                                                         |
//+------------------------------------------------------------------+
void CPerson::SetBirth(datetime birth)
  {
   m_birth=birth;
  }
//+------------------------------------------------------------------+

Quanto segue è per gli sviluppatori puristi ossessionati dalla scrittura di codice di qualità. A differenza di alcuni esempi disponibili in MQL5 Programming Articles e molti altri software disponibili in Code Base, la classe precedente utilizza le stesse convenzioni di programmazione applicate da MetaQuotes Software Corp. per codificare il loro framework MQL5. Ti incoraggio a scrivere il tuo codice proprio come fa MetaQuotes. A proposito, il thread intitolato Informazioni sulle convenzioni nei programmi OOP MQL5tratta di questo argomento.

In poche parole, alcune importanti convenzioni applicate nella scrittura person.mqh sono:

  • Il nome della classe CPerson inizia con la lettera C maiuscola.
  • I nomi dei metodi sono camel cased e iniziano con una lettera maiuscola, ad esempio, GetFirstName, SetSurname, ecc.
  • I nomi delle proprietà protette sono preceduti dal prefisso m_,, ad esempio m_first_name, m_surname e m_birth .
  • La parola riservata questo non viene utilizzata per fare riferimento ai membri della classe all'interno della classe stessa.

Per favore, dai un'occhiata ad alcuni file framework MQL5, ad esempio Include\Arrays\Array.mqh, Include\Arrays\List.mqh, Include\Trade\Trade.mqh, e guarda come viene scritto il codice MQL5 originale.


2. Programmiamo il nostro primo EA orientato agli oggetti


2.1. L'idea del sistema di trading

La nostra idea di trading è semplice: "Le tendenze brevi dei mercati volatili sono quasi casuali". Questo è tutto! Questo è stato osservato da diversi esperti in alcune circostanze. Se questa ipotesi è vera, il nostro robot Forex deve funzionare per necessità. Dato un punto casuale su un grafico il movimento successivo può ovviamente andare sia su che giù, non lo sappiamo. Il fatto è che se la differenza tra i livelli SL e TP stabiliti è sufficientemente piccola, allora quella differenza non è significativa in termini assoluti, e abbiamo quindi raggiunto l'aspettativa matematica. Questo sistema lascerà che funzioni l'aspettativa matematica. Una volta ottenuto il codice EA in questo articolo ed eseguito il backtest, vedrai che richiede una politica di gestione del denaro molto semplice.


2.2. Lo scheletro OOP del robot

In questa sezione stiamo sviluppando la strategia di cui sopra attraverso il ragionamento astratto richiesto dalla programmazione orientata agli oggetti. Allora perché non iniziamo a pensare al nostro EA come se fosse una creatura vivente? Sotto questa visione la nostra macchina Forex può essere composta da tre parti principali: un cervello, qualcosa che chiameremo evoluzione e un grafico.

Il cervello è la parte del robot che contiene i dati necessari per operare, qualcosa come una memoria di sola lettura (ROM). Il grafico è il pezzo di informazione che emula il grafico su cui opera il robot. Infine, la cosiddetta evoluzione è un dato contenente informazioni temporali come lo stato del robot in un dato momento, la storia delle operazioni eseguite, ecc. È come se stessimo progettando un essere umano attraverso i suoi organi, qualcosa come un Frankenstein, perché dobbiamo sviluppare un'app per il settore sanitario. Ogni organo è in questo contesto un concetto semantico unico associato ad alcune altre parti del tutto.

Prima di tutto creiamo la cartella MQL5\Include\Mine per memorizzare le nostre cose personalizzate. Questa è solo un'idea per organizzare il tuo codice. È bene sapere che puoi farlo nei tuoi sviluppi, ma ovviamente non sei costretto a farlo. Creeremo quindi il file MQL5\Include\Mine\Enums.mqh per memorizzare gli enum creati da noi:

//+------------------------------------------------------------------+
//| Status enumeration                                               |
//+------------------------------------------------------------------+
enum ENUM_STATUS_EA
  {
   BUY,
   SELL,
   DO_NOTHING
  };
//+------------------------------------------------------------------+
//| Lifetime enumeration                                             |
//+------------------------------------------------------------------+
enum ENUM_LIFE_EA
  {
   HOUR,
   DAY,
   WEEK,
   MONTH,
   YEAR
  };
//+------------------------------------------------------------------+

Successivamente, è il momento di creare l'embrione del nostro EA che si chiamerà ExpertSimpleRandom.mq5! Quindi, per favore, crea la cartella MQL5\Experts\SimpleRandom e poi crea all'interno il file ExpertSimpleRandom.mq5 con questo codice:

//+------------------------------------------------------------------+
//|                                           ExpertSimpleRandom.mq5 |
//|                               Copyright © 2013, Jordi Bassagañas |
//+------------------------------------------------------------------+

#property copyright     "Copyright © 2013, laplacianlab"
#property link          "https://www.mql5.com/it/articles"
#property version       "1.00"

#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Trade\PositionInfo.mqh>
#include <Indicators\Indicators.mqh>
#include <Mine\Enums.mqh>
#include <..\Experts\SimpleRandom\CSimpleRandom.mqh>

input int               StopLoss;
input int               TakeProfit;
input double            LotSize;
input ENUM_LIFE_EA      TimeLife;

MqlTick tick;
CSimpleRandom *SR=new CSimpleRandom(StopLoss,TakeProfit,LotSize,TimeLife);
//+------------------------------------------------------------------+
//| Initialization function                                          |
//+------------------------------------------------------------------+
int OnInit(void)
  {
   SR.Init();
   return(0);
  }
//+------------------------------------------------------------------+
//| Deinitialization function                                        |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   SR.Deinit();
   delete(SR);
  }
//+------------------------------------------------------------------+
//| OnTick event function                                            |
//+------------------------------------------------------------------+
void OnTick()
  {
   SymbolInfoTick(_Symbol,tick);
   SR.Go(tick.ask,tick.bid);
  }
//+------------------------------------------------------------------+

Questo è solo uno dei tanti approcci possibili. Tutto questo è fondamentalmente per illustrare come funziona OOP in MQL5. Come vedi, la classe principale di Expert Advisor si chiama CSimpleRandom.mqh, per favore, salvala in MQL5\Experts\SimpleRandom\CSimpleRandom.mqh:

//+------------------------------------------------------------------+
//|                                           ExpertSimpleRandom.mq5 |
//|                               Copyright © 2013, Jordi Bassagañas |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
#include <Mine\Enums.mqh>
#include <..\Experts\SimpleRandom\CBrain.mqh>
#include <..\Experts\SimpleRandom\CEvolution.mqh>
#include <..\Experts\SimpleRandom\CGraphic.mqh>
//+------------------------------------------------------------------+
//| CSimpleRandom Class                                              |
//+------------------------------------------------------------------+
class CSimpleRandom
  {
protected:
   CBrain           *m_brain;
   CEvolution       *m_evolution;
   CGraphic         *m_graphic;
   CTrade           *m_trade;
   CPositionInfo    *m_positionInfo;
public:
   //--- Constructor and destructor methods
                     CSimpleRandom(int stop_loss,int take_profit,double lot_size,ENUM_LIFE_EA time_life);
                    ~CSimpleRandom(void);
   //--- Getter methods
   CBrain           *GetBrain(void);
   CEvolution       *GetEvolution(void);
   CGraphic         *GetGraphic(void);
   CTrade           *GetTrade(void);
   CPositionInfo    *GetPositionInfo(void);
   //--- Specific methods of CSimpleRandom
   bool              Init();
   void              Deinit(void);
   bool              Go(double ask,double bid);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CSimpleRandom::CSimpleRandom(int stop_loss,int take_profit,double lot_size,ENUM_LIFE_EA time_life)
  {
   int lifeInSeconds;

   switch(time_life)
     {
      case HOUR:

         lifeInSeconds=3600;

         break;

      case DAY:

         lifeInSeconds=86400;

         break;

      case WEEK:

         lifeInSeconds=604800;

         break;

      case MONTH:

         lifeInSeconds=2592000;

         break;

         // One year

      default:

         lifeInSeconds=31536000;

         break;
     }

   m_brain=new CBrain(TimeLocal(),TimeLocal()+lifeInSeconds,lot_size,stop_loss,take_profit);
   m_evolution=new CEvolution(DO_NOTHING);
   m_graphic=new CGraphic(_Symbol);
   m_trade=new CTrade();
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CSimpleRandom::~CSimpleRandom(void)
  {
   delete(m_brain);
   delete(m_evolution);
   delete(m_graphic);
   delete(m_trade);
  }
//+------------------------------------------------------------------+
//| GetBrain                                                         |
//+------------------------------------------------------------------+
CBrain *CSimpleRandom::GetBrain(void)
  {
   return m_brain;
  }
//+------------------------------------------------------------------+
//| GetBrain                                                         |
//+------------------------------------------------------------------+
CEvolution *CSimpleRandom::GetEvolution(void)
  {
   return m_evolution;
  }
//+------------------------------------------------------------------+
//| GetGraphic                                                       |
//+------------------------------------------------------------------+
CGraphic *CSimpleRandom::GetGraphic(void)
  {
   return m_graphic;
  }
//+------------------------------------------------------------------+
//| GetTrade                                                         |
//+------------------------------------------------------------------+
CTrade *CSimpleRandom::GetTrade(void)
  {
   return m_trade;
  }
//+------------------------------------------------------------------+
//| GetPositionInfo                                                  |
//+------------------------------------------------------------------+
CPositionInfo *CSimpleRandom::GetPositionInfo(void)
  {
   return m_positionInfo;
  }
//+------------------------------------------------------------------+
//| CSimpleRandom initialization                                     |
//+------------------------------------------------------------------+
bool CSimpleRandom::Init(void)
  {
// Initialization logic here...
   return true;
  }
//+------------------------------------------------------------------+
//| CSimpleRandom deinitialization                                   |
//+------------------------------------------------------------------+
void CSimpleRandom::Deinit(void)
  {
// Deinitialization logic here...
   delete(m_brain);
   delete(m_evolution);
   delete(m_graphic);
   delete(m_trade);
  }
//+------------------------------------------------------------------+
//| CSimpleRandom Go                                                 |
//+------------------------------------------------------------------+
bool CSimpleRandom::Go(double ask,double bid)
  {
   double tp;
   double sl;

   int coin=m_brain.GetRandomNumber(0,1);

// Is there any open position?     

   if(!m_positionInfo.Select(_Symbol))
     {
      // If not, we open one

      if(coin==0)
        {
         GetEvolution().SetStatus(BUY);
        }
      else
        {
         GetEvolution().SetStatus(SELL);
        }
     }

// If so, let it work the mathematical expectation.

   else GetEvolution().SetStatus(DO_NOTHING);

   switch(GetEvolution().GetStatus())
     {
      case BUY:

         tp = ask + m_brain.GetTakeProfit() * _Point;
         sl = bid - m_brain.GetStopLoss() * _Point;

         GetTrade().PositionOpen(_Symbol,ORDER_TYPE_BUY,m_brain.GetSize(),ask,sl,tp);

         break;

      case SELL:

         sl = ask + m_brain.GetStopLoss() * _Point;
         tp = bid - m_brain.GetTakeProfit() * _Point;

         GetTrade().PositionOpen(_Symbol,ORDER_TYPE_SELL,m_brain.GetSize(),bid,sl,tp);

         break;

      case DO_NOTHING:

         // Nothing...

         break;
     }

// If there is some error we return false, for now we always return true  

   return(true);
  }
//+------------------------------------------------------------------+


2.3. Associazione di CSimpleRandom a oggetti di tipo complesso

Si noti come gli oggetti personalizzati di tipo CBrain, CEvolution e CGraphic siano collegati a CSimpleRandom.

Per prima cosa definiamo le proprietà protette corrispondenti:

protected:
   CBrain           *m_brain;
   CEvolution       *m_evolution;
   CGraphic         *m_graphic; 

E subito dopo instanziamo quegli oggetti all'interno del costruttore:

m_brain=new CBrain(TimeLocal(), TimeLocal() + lifeInSeconds, lot_size, stop_loss, take_profit);         
m_evolution=new CEvolution(DO_NOTHING);      
m_graphic=new CGraphic(_Symbol);

Quello che facciamo è creare dinamicamente oggetti di tipo complesso proprio come spiegano i documenti ufficiali in Object Pointers. Con questo schema possiamo accedere alle funzionalità di CBrain, CEvolution and CGraphic direttamente da CSimpleRandom. Potremmo eseguire ad esempio il seguente codice in ExpertSimpleRandom.mq5:

//+------------------------------------------------------------------+
//| OnTick event function                                            |
//+------------------------------------------------------------------+
void OnTick()
   {              
      // ...
      
      int randNumber=SR.GetBrain().GetRandomNumber(4, 8);

      // ...          
  }

Scrivo ora il codice di CBrain,, CEvolution e CGraphic per concludere questa sezione. Si prega di notare che ci sono alcune parti che non sono codificate perché non sono strettamente necessarie per eseguire il backtest di SimpleRandom. È lasciato come esercizio per te per codificare le parti mancanti di queste classi, sentiti libero di svilupparle come vuoi.  Ad esempio, m_death non viene effettivamente utilizzato, anche se l'idea alla base è quella di sapere fin dall'inizio la data in cui il robot terminerà la sua attività.

//+------------------------------------------------------------------+
//|                                               ExpertSimpleRandom |
//|                               Copyright © 2013, Jordi Bassagaсas |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| CBrain Class                                                     |
//+------------------------------------------------------------------+
class CBrain
  {
protected:
   ENUM_TIMEFRAMES   m_period;               // period must always be initialized to PERIOD_M1 to fit the system's idea
   datetime          m_birth;               // The datetime in which the robot is initialized for the first time
   datetime          m_death;               // The datetime in which the robot will die
   double            m_size;                // The size of the positions
   int               m_stopLoss;            // Stop loss
   int               m_takeProfit;          // Take profit

public:
   //--- Constructor and destructor methods
                     CBrain(datetime birth,datetime death,double size,int stopLoss,int takeProfit);
                    ~CBrain(void);
   //--- Getter methods
   datetime          GetBirth(void);
   datetime          GetDeath(void);
   double            GetSize(void);
   int               GetStopLoss(void);
   int               GetTakeProfit(void);
   //--- Setter methods
   void              SetBirth(datetime birth);
   void              SetDeath(datetime death);
   void              SetSize(double size);
   void              SetStopLoss(int stopLoss);
   void              SetTakeProfit(int takeProfit);
   //--- Brain specific logic
   int               GetRandomNumber(int a,int b);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CBrain::CBrain(datetime birth,datetime death,double size,int stopLoss,int takeProfit)
  {
   MathSrand(GetTickCount());

   m_period=PERIOD_M1;
   m_birth=birth;
   m_death=death;
   m_size=size;
   m_stopLoss=stopLoss;
   m_takeProfit=takeProfit;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CBrain::~CBrain(void)
  {
  }
//+------------------------------------------------------------------+
//| GetBirth                                                         |
//+------------------------------------------------------------------+
datetime CBrain::GetBirth(void)
  {
   return m_birth;
  }
//+------------------------------------------------------------------+
//| GetDeath                                                         |
//+------------------------------------------------------------------+
datetime CBrain::GetDeath(void)
  {
   return m_death;
  }
//+------------------------------------------------------------------+
//| GetSize                                                          |
//+------------------------------------------------------------------+
double CBrain::GetSize(void)
  {
   return m_size;
  }
//+------------------------------------------------------------------+
//| GetStopLoss                                                      |
//+------------------------------------------------------------------+
int CBrain::GetStopLoss(void)
  {
   return m_stopLoss;
  }
//+------------------------------------------------------------------+
//| GetTakeProfit                                                    |
//+------------------------------------------------------------------+
int CBrain::GetTakeProfit(void)
  {
   return m_takeProfit;
  }
//+------------------------------------------------------------------+
//| SetBirth                                                         |
//+------------------------------------------------------------------+
void CBrain::SetBirth(datetime birth)
  {
   m_birth=birth;
  }
//+------------------------------------------------------------------+
//| SetDeath                                                         |
//+------------------------------------------------------------------+
void CBrain::SetDeath(datetime death)
  {
   m_death=death;
  }
//+------------------------------------------------------------------+
//| SetSize                                                          |
//+------------------------------------------------------------------+
void CBrain::SetSize(double size)
  {
   m_size=size;
  }
//+------------------------------------------------------------------+
//| SetStopLoss                                                      |
//+------------------------------------------------------------------+
void CBrain::SetStopLoss(int stopLoss)
  {
   m_stopLoss=stopLoss;
  }
//+------------------------------------------------------------------+
//| SetTakeProfit                                                    |
//+------------------------------------------------------------------+
void CBrain::SetTakeProfit(int takeProfit)
  {
   m_takeProfit=takeProfit;
  }
//+------------------------------------------------------------------+
//| GetRandomNumber                                                  |
//+------------------------------------------------------------------+
int CBrain::GetRandomNumber(int a,int b)
  {
   return(a+(MathRand()%(b-a+1)));
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|                                               ExpertSimpleRandom |
//|                               Copyright © 2013, Jordi Bassagaсas |
//+------------------------------------------------------------------+
#include <Indicators\Indicators.mqh>
#include <Mine\Enums.mqh>
//+------------------------------------------------------------------+
//| CEvolution Class                                                 |
//+------------------------------------------------------------------+
class CEvolution
  {
protected:
   ENUM_STATUS_EA    m_status;            // The current EA's status
   CArrayObj*        m_operations;        // History of the operations performed by the EA

public:
   //--- Constructor and destructor methods
                     CEvolution(ENUM_STATUS_EA status);
                    ~CEvolution(void);
   //--- Getter methods
   ENUM_STATUS_EA    GetStatus(void);
   CArrayObj        *GetOperations(void);
   //--- Setter methods
   void              SetStatus(ENUM_STATUS_EA status);
   void              SetOperation(CObject *operation);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CEvolution::CEvolution(ENUM_STATUS_EA status)
  {
   m_status=status;
   m_operations=new CArrayObj;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CEvolution::~CEvolution(void)
  {
   delete(m_operations);
  }
//+------------------------------------------------------------------+
//| GetStatus                                                        |
//+------------------------------------------------------------------+
ENUM_STATUS_EA CEvolution::GetStatus(void)
  {
   return m_status;
  }
//+------------------------------------------------------------------+
//| GetOperations                                                    |
//+------------------------------------------------------------------+
CArrayObj *CEvolution::GetOperations(void)
  {
   return m_operations;
  }
//+------------------------------------------------------------------+
//| SetStatus                                                        |
//+------------------------------------------------------------------+
void CEvolution::SetStatus(ENUM_STATUS_EA status)
  {
   m_status=status;
  }
//+------------------------------------------------------------------+
//| SetOperation                                                     |
//+------------------------------------------------------------------+
void CEvolution::SetOperation(CObject *operation)
  {
   m_operations.Add(operation);
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|                                           ExpertSimpleRandom.mq5 |
//|                               Copyright © 2013, Jordi Bassagaсas |
//+------------------------------------------------------------------+
#include <Trade\SymbolInfo.mqh>
#include <Arrays\ArrayObj.mqh>
//+------------------------------------------------------------------+
//| CGrapic Class                                                    |
//+------------------------------------------------------------------+
class CGraphic
  {
protected:
   ENUM_TIMEFRAMES   m_period;            // Graphic's timeframe
   string            m_pair;              // Graphic's pair
   CSymbolInfo*      m_symbol;            // CSymbolInfo object
   CArrayObj*        m_bars;              // Array of bars

public:
   //--- Constructor and destructor methods
                     CGraphic(string pair);
                    ~CGraphic(void);
   //--- Getter methods
   string            GetPair(void);
   CSymbolInfo      *GetSymbol(void);
   CArrayObj        *GetBars(void);
   //--- Setter methods
   void              SetPair(string pair);
   void              SetSymbol(CSymbolInfo *symbol);
   void              SetBar(CObject *bar);
  };
//+------------------------------------------------------------------+
//| Constuctor                                                       |
//+------------------------------------------------------------------+
CGraphic::CGraphic(string pair)
  {
   m_period=PERIOD_M1;
   m_pair=pair;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CGraphic::~CGraphic(void)
  {
  }
//+------------------------------------------------------------------+
//| GetPair                                                          |
//+------------------------------------------------------------------+
string CGraphic::GetPair(void)
  {
   return m_pair;
  }
//+------------------------------------------------------------------+
//| GetSymbol                                                        |
//+------------------------------------------------------------------+
CSymbolInfo *CGraphic::GetSymbol(void)
  {
   return m_symbol;
  }
//+------------------------------------------------------------------+
//| GetBars                                                          |
//+------------------------------------------------------------------+
CArrayObj *CGraphic::GetBars(void)
  {
   return m_bars;
  }
//+------------------------------------------------------------------+
//| SetPair                                                          |
//+------------------------------------------------------------------+
void CGraphic::SetPair(string pair)
  {
   m_pair=pair;
  }
//+------------------------------------------------------------------+
//| SetSymbol                                                        |
//+------------------------------------------------------------------+
void CGraphic::SetSymbol(CSymbolInfo *symbol)
  {
   m_symbol=symbol;
  }
//+------------------------------------------------------------------+
//| SetBar                                                           |
//+------------------------------------------------------------------+
void CGraphic::SetBar(CObject *bar)
  {
   m_bars.Add(bar);
  }
//+------------------------------------------------------------------+

3. Backtesting ExpertSimpleRandom.mq5

Questo sistema di trading casuale ha dimostrato di essere valido solo per determinati livelli di stop loss e take profit, come previsto. Naturalmente, questi intervalli SL/TP vincitori non sono gli stessi per tutti i simboli. Questo perché ogni simbolo mostra la propria personalità in un dato momento, o in altre parole, tutte le coppie di valute si muovono in modo diverso rispetto al resto. Quindi si prega di identificare prima questi livelli nel backtesting prima di eseguire ExpertSimpleRandom.mq5 in un ambiente reale.

Condivido qui alcuni dati di esempio per i quali l'idea esposta in questo articolo sembra essere vincente. Questo può essere dedotto dopo aver eseguito molte volte ExpertSimpleRandom.mq5 in MetaTrader 5 Strategy Tester.

Alcuni input dei vincitori per EURUSD, gennaio 2012, sono:

  • StopLoss: 400
  • TakeProfit: 600
  • LotSize: 0.01
  • TimeLife: MONTH

Corsa numero 1:

EURUSD, gennaio 2012

Corsa numero 2:

EURUSD, gennaio 2012

Corsa numero 3:

EURUSD, gennaio 2012


Conclusione

Abbiamo imparato ad applicare la programmazione orientata agli oggetti nei nostri sistemi di trading automatizzati. Per fare questo abbiamo dovuto prima definire una strategia di trading meccanico. La nostra idea di trading è stata molto semplice: "Le tendenze brevi dei mercati volatili sono quasi casuali". Questo è stato osservato da diversi esperti in alcune circostanze.

Subito dopo abbiamo pensato al nostro EA in termini reali come se fosse una creatura vivente. Grazie a questa visione abbiamo visto che la nostra macchina Forex può essere composta da tre parti principali: un cervello, qualcosa che abbiamo chiamato evoluzione e un grafico.

E infine abbiamo programmato l'expert advisor del sistema che incorpora la logica necessaria per eseguire il backtest, abbiamo eseguito molte volte il robot nel gennaio 2012 e abbiamo scoperto che la maggior parte delle volte il sistema vince. L'idea alla base di questo sistema si è dimostrata vera, ma la sua efficacia non è molto elevata a causa della sua semplicità.


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

File allegati |
cbrain.mqh (5.64 KB)
cevolution.mqh (2.97 KB)
cgraphic.mqh (3.55 KB)
enums.mqh (0.92 KB)
csimplerandom.mqh (12.79 KB)
Creazione di EA di reti neurali utilizzando MQL5 Wizard e Hlaiman EA Generator Creazione di EA di reti neurali utilizzando MQL5 Wizard e Hlaiman EA Generator
L'articolo descrive un metodo di creazione automatizzata di EA di reti neurali utilizzando MQL5 Wizard e Hlaiman EA Generator. Ti mostra come puoi facilmente iniziare a lavorare con le reti neurali, senza dover imparare l'intero corpo di informazioni teoriche e ti mostra come scrivere il tuo codice.
Come installare e utilizzare OpenCL per i calcoli Come installare e utilizzare OpenCL per i calcoli
È passato più di un anno da quando MQL5 ha iniziato a fornire supporto nativo per OpenCL. Tuttavia, non molti utenti hanno capito il vero valore nell'utilizzo del calcolo parallelo nei loro Expert Advisor, indicatori o script. Questo articolo ti aiuta a installare e configurare OpenCL sul tuo computer in modo che tu possa provare a utilizzare questa tecnologia nel terminale di trading MetaTrader 5.
Costruire un trader automatico di notizie Costruire un trader automatico di notizie
Questa è la continuazione di un altro articolo sulla classe OOP MQL5 che ha mostrato come costruire un semplice EA OO da zero, dando alcuni suggerimenti sulla programmazione orientata agli oggetti. Oggi vi mostro le basi tecniche necessarie per sviluppare un EA in grado di scambiare le notizie. Il mio obiettivo è quello di continuare a darti idee su OOP e anche coprire un nuovo argomento in questa serie di articoli, lavorando con il file system.
Manuale MQL5: Gestire gli eventi tipici dei grafici Manuale MQL5: Gestire gli eventi tipici dei grafici
Questo articolo prende in considerazione gli eventi tipici dei grafici e include esempi della loro elaborazione. Ci concentreremo su eventi del mouse, sequenze di tasti, creazione/modifica/rimozione di un oggetto grafico, clic del mouse su un grafico e su un oggetto grafico, spostamento di un oggetto grafico con il mouse, completamento della modifica del testo in un campo di testo, nonché sugli eventi di modifica del grafico. Viene fornito un campione di un programma MQL5 per ogni tipo di evento considerato.