English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Une autre classe MQL5 OOP

Une autre classe MQL5 OOP

MetaTrader 5Exemples | 13 janvier 2022, 10:56
289 0
laplacianlab
[Supprimé]

Introduction

Construire un EA orientée objet complète qui fonctionne réellement est à mon humble avis une tâche difficile qui nécessite de nombreuses compétences réunies : raisonnement logique, pensée divergente, capacité d'analyse et de synthèse, imagination, etc. Disons que si le système de trading automatisé que nous devons résoudre était un jeu d'échecs, son idée de trading serait la stratégie d'échecs. Et l'exécution de la stratégie d'échecs par la tactique serait la programmation du robot à l'aide d'indicateurs techniques, de graphiques, d'idées économiques fondamentales et d'axiomes conceptuels.

Détail de l'École d'Athènes de Raffaello Sanzio

Figure 1. Détail de l'École d'Athènes de Raffaello Sanzio. Dans cette image, nous voyons les philosophes Platon et Aristote dans une discussion approfondie.
Platon représente ici le monde conceptuel et Aristote le monde empiriste.

Je suis conscient de la difficulté de cet exercice. Un EA OO n'est pas extrêmement difficile à programmer, mais il est vrai qu'il présente un certain degré de difficulté aux personnes ayant peu d'expérience dans le développement d'applications. Comme dans toute autre discipline, cela est, à son tour, dû au manque d'expérience lui-même, c'est pourquoi j'essaie de vous enseigner ce sujet à travers un exemple précis que je suis sûr que vous comprendrez. Ne vous découragez pas si vous ne vous sentez toujours pas en sécurité dans la gestion des concepts de POO, vous trouverez les choses beaucoup plus faciles une fois que vous aurez implémenté vos cinq premiers EA, disons. Vous n'avez pas besoin de construire quoi que ce soit à partir de zéro pour l'instant, comprenez simplement ce que j'explique ici !

L'ensemble du processus de conception et de mise en œuvre d'un système de trading peut être simplifié à bien des égards lorsqu'il est effectué par plusieurs personnes, bien que ce fait pose le problème de la communication. Je veux dire que la personne qui conçoit la stratégie d'investissement n'est pas obligée de gérer les concepts de programmation qui gère son interlocuteur, le programmeur. Et le développeur MQL5 peut ne pas comprendre au début certains aspects importants de la stratégie de trading de son client.

Il s'agit d'un problème classique en génie logiciel qui a conduit à la création de nombreuses méthodologies de développement logiciel telles que Scrum, Test Driven Development (TDD), Extreme programming (XP), etc. Il est crucial d'être conscient des pièges de la langue. Soit dit en passant, à votre connaissance, Wikipédia déclare : "la méthodologie de développement de logiciel ou la méthodologie de développement de système en génie logiciel est un cadre utilisé pour structurer, planifier et contrôler le processus de développement d'un système d'information".

Nous allons supposer que nous sommes capables à la fois de concevoir et de mettre en œuvre rapidement des idées de trading réussies. On peut aussi supposer que l'on est au terme d'un processus de développement itératif où le système de trading pensé par notre client est déjà bien défini et compris par tous. Comme vous préfèrez. D'ailleurs, je vais dorénavant me référer dans ce texte à quelques articles pédagogiques disponibles dans les articles de programmation MQL5 afin que vous puissiez rapidement vérifier et rappeler quelques idées, lorsque cela est nécessaire, pour réussir cet exercice. Êtes-vous prêts ?


1. Vos premiers pas pour adopter le nouveau paradigme


1.1. Pourquoi la POO est-elle bonne pour programmer vos EA Forex ?

Peut-être que vous vous demandez à ce stade pourquoi vous devez faire quelque chose comme ça. Laissez-moi vous dire tout d'abord que vous n'êtes pas obligé d'être POO. Quoi qu'il en soit, il est fortement recommandé d'être une personne de la POO afin que faire un pas de plus dans votre connaissance de la programmation des systèmes de trading automatisés.

La manière classique de développer des applications, la programmation dite procédurale, présente les inconvénients suivants :

  • Cela rend difficile la modélisation des problèmes. Sous ce vieux paradigme, la solution du problème principal est réduite à la division de celui-ci en sous-problèmes plus simples qui sont résolus par des modules fonctionnels, à savoir, des fonctions et des procédures.
  • Cela rend difficile la réutilisation du code, ce qui à son tour nuit au coût, à la fiabilité, à la flexibilité et à la maintenance.

La réutilisation du code est plus facile avec le nouveau style orienté objet. C'est très important ! De nombreux experts pensent que la réutilisation du code est la vraie solution à la plupart des problèmes de développement de logiciels.

À ce stade, nous devons mentionner abstract data types (ADT). La POO permette la création d'ADT. Un ADT est une abstraction du concept traditionnel de type de données qui est présent dans tous les langages de programmation. Son utilisation principale est de définir confortablement le domaine de données des applications. Include\Arrays\Array.mqh, Include\Arrays\List.mqh et Include\Arrays\Tree.mqh sont quelques exemples de types de données abstraits MQL5.

En bref, le paradigme de la programmation orientée objet veut que vous conceviez vos applications à un niveau conceptuel afin de vous faire bénéficier de la réutilisation du code, de la fiabilité,de la flexibilité et de la facilité de maintenance.

1.2. Êtes-vous un raisonneur conceptuel ? UML vient à la rescousse

Avez-vous déjà entendu parler de UML ? UML est l'abréviation de Unified Modeling Language (langage de modélisation unifié). C'est un langage graphique pour la conception de systèmes orientés objet. Nous, les humains, sommes censés d'abord penser nos systèmes dans la phase d'analyse, puis les coder avec un langage de programmation. Aller de haut en bas est moins insensé pour les développeurs. Néanmoins, mon expérience d'analyste me dit que parfois ce n'est pas possible à cause de plusieurs choses : l'application doit être faite dans un temps très court, il n'y a personne dans l'équipe qui puisse appliquer rapidement ses connaissances d'UML, ou peut-être certaines personnes dans l'équipe ne connaissent pas certaines parties d'UML.

UML est à mon avis un bon outil d'analyse que vous pouvez utiliser si vous vous sentez à l'aise avec, et si les circonstances entourant le projet sont ok. Veuillez lire Comment développer un Expert Advisor à l'aide des outils UML si vous souhaitez explorer le sujet d'UML. Cet article est peut-être un peu accablant, mais il sert à avoir une vue d'ensemble sur la façon dont les ingénieurs logiciels professionnels travaillent leur analyse. Vous auriez besoin de suivre un cours de plusieurs semaines pour bien comprendre UML ! Pour l'instant, il est normal de savoir ce qu'est UML. D'après mon expérience, cet outil d'analyse n'est pas toujours utilisé dans tous les projets logiciels en raison de plusieurs circonstances présentes dans le monde réel.

Le logo UML

Figure 2. Le logo UML.


1.3. Bonjour tout le monde ! Votre première classe OO

Si vous êtes un débutant complet dans la programmation orientée objet, je vous recommande de lire d'abord la documentation officielle sur l’OO disponible dans la référence MQL5, puis de jeter un œil à la rédaction d'un Expert Advisor à l'aide de l'approche de programmation orientée objet MQL5 pour obtenir les bases. S'il vous plaît assurez-vous de compléter ces lectures avec d'autres matériaux. A partir de maintenant je suppose que vous connaissez déjà de la POO, vous comprendrez donc facilement l'exemple classique de la classe Person qui en MQL5 est le suivant :

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

Ce qui suit est destiné aux développeurs puristes obsédés par l'écriture de code de qualité. Contrairement à certains exemples disponibles dans les articles de programmation MQL5 et à de nombreux autres logiciels disponibles dans Code Base, la classe ci-dessus utilise les mêmes conventions de programmation appliquées par MetaQuotes Software Corp. pour coder son cadre MQL5. Je vous encourage à écrire votre code comme le fait MetaQuotes. Soit dit en passant, le fil intitulé À propos des conventions dans les programmes POO MQL5 couvre ce sujet.

En résumé, certaines conventions importantes appliquées à l'écriture de Person.mqh sont :

  • Le nom de classe CPerson commence par la lettre C majuscule.
  • Les noms de méthode sont en majuscules et commencent par une majuscule, par exemple, GetFirstName, SetSurname, etc.
  • Les noms des propriétés protégées sont précédés du préfixe m_, par exemple, m_first_name, m_surname et m_birth.
  • Le mot réservé this n'est pas utilisé pour référencer les membres de la classe à l'intérieur de la classe elle-même.

Veuillez jeter un œil à certains fichiers du cadre MQL5, par exemple, Include\Arrays\Array.mqh, Include\Arrays\List.mqh, Include\Trade\Trade.mqh, et voyez comment le code MQL5 d'origine est écrit.


2. Programmons notre première EA orientée objet


2.1. L'idée du système de trading

Notre idée de trading est simple : "Les tendances courtes des marchés volatils sont presque aléatoires". C'est ça ! Cela a été observé par plusieurs experts dans certaines circonstances. Si cette hypothèse est vraie, notre robot Forex doit fonctionner par nécessité. Étant donné un point aléatoire sur un graphique, le prochain mouvement peut évidemment monter et descendre, nous ne savons pas. Le fait est que si la différence entre les niveaux SL et TP établis est suffisamment petite, alors cette différence n'est pas significative en termes absolus, et nous avons donc atteint l'espérance mathématique. Ce système va juste laisser fonctionner l'espérance mathématique. Une fois que vous aurez obtenu le code de l'EA dans cet article et exécuté le backtest, vous verrez qu'il nécessite une politique de gestion de l'argent très simple.


2.2. Le squelette de la POO du robot

Dans cette section, nous développons la stratégie ci-dessus à travers le raisonnement abstrait requis par la programmation orientée objet. Alors pourquoi ne commençons-nous pas à penser à notre EA comme s'il s'agissait d'une créature vivante ? Selon cette vision, notre machine Forex peut être composée de trois parties principales : un cerveau, quelque chose que nous appellerons évolution et un graphique.

Le cerveau est la partie du robot qui contient les données nécessaires à son fonctionnement, quelque chose comme une mémoire morte (ROM). Le graphique est la pièce d'information émulant le graphique sur lequel le robot opère. Enfin, l'évolution dite est une donnée contenant des informations temporelles telles que l'état du robot à un instant donné, l'historique des opérations effectuées, etc. C'est comme si on concevait un être humain à travers ses organes, quelque chose comme un Frankenstein, car il faut développer une application pour le secteur de la santé. Chaque organe est dans ce contexte un concept sémantique unique associé à d'autres parties de l'ensemble.

Tout d'abord, créons le dossier MQL5\Include\Mine pour stocker nos éléments personnalisés. C'est juste une idée pour organiser votre code. Il est bon de savoir que vous pouvez le faire dans vos développements mais bien sûr vous n'êtes pas obligé de le faire. Nous allons ensuite créer le fichier MQL5\Include\Mine\Enums.mqh afin de stocker les enums créés par nos soins :

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

Ensuite, il est temps de créer l'embryon de notre EA qui s'appellera ExpertSimpleRandom.mq5 ! Alors, s'il vous plaît, créez le dossier MQL5\Experts\SimpleRandom puis créez à l'intérieur du fichier ExpertSimpleRandom.mq5 avec ce code :

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

#property copyright     "Copyright © 2013, laplacianlab"
#property link          "https://www.mql5.com/fr/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);
  }
//+------------------------------------------------------------------+

Ce n'est qu'une approche parmi les nombreuses possibles. Tout cela sert essentiellement à illustrer le fonctionnement de la POO dans MQL5. Comme vous le voyez, la classe principale de l'Expert Advisor est nommée CSimpleRandom.mqh, s'il vous plaît, enregistrez-la dans 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. Liaison de CSimpleRandom à des objets de type complexe

Notez comment les objets personnalisés de type CBrain, CEvolution et CGraphic sont liés à CSimpleRandom.

Nous définissons d'abord les propriétés protégées correspondantes :

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

Et juste après avoir instancié ces objets dans le constructeur :

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

Ce que nous faisons, c'est créer dynamiquement des objets de type complexe, comme l'expliquent les documents officiels dans Object Pointers. Avec ce schéma, nous pouvons accéder aux fonctionnalités de CBrain, CEvolution et CGraphic directement depuis CSimpleRandom. Nous pourrions exécuter par exemple le code suivant dans ExpertSimpleRandom.mq5 :

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

      // ...          
  }

J'écris maintenant le code de CBrain, CEvolution et CGraphic pour conclure cette section. Veuillez noter qu'il y a certaines parties qui ne sont pas codées car elles ne sont pas strictement nécessaires pour backtester SimpleRandom. Il vous est laissé en exercice de coder les parties manquantes de ces cours, n'hésitez pas à les développer comme vous le souhaitez.  Par exemple, m_death n'est pas réellement utilisé, bien que l'idée sous-jacente soit de savoir dès le début la date à laquelle le robot finira son activité.

//+------------------------------------------------------------------+
//|                                               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

Ce système de trading aléatoire s'est avéré valable uniquement pour certains niveaux de stop loss et take profit, comme prévu. Bien entendu, ces intervalles SL/TP gagnants ne sont pas les mêmes pour tous les symboles. En effet, chaque symbole montre sa propre personnalité à un moment donné, ou en d'autres termes, toutes les paires de devises évoluent différemment par rapport aux autres. Veuillez donc identifier d'abord ces niveaux dans le backtesting avant d'exécuter ExpertSimpleRandom.mq5 dans un environnement réel.

Je partage ici quelques exemples de données pour lesquelles l'idée exposée dans cet article semble être gagnante. Cela peut être déduit après avoir exécuté plusieurs fois ExpertSimpleRandom.mq5 dans MetaTrader 5 Strategy Tester.

Certaines entrées gagnantes pour EURUSD, janvier 2012, sont :

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

Exécution numéro 1 :

EURUSD, janvier 2012

Exécution numéro 2 :

EURUSD, janvier 2012

Exécution numéro 3 :

EURUSD, janvier 2012


Conclusion

Nous avons appris à appliquer la programmation orientée objet dans nos systèmes de trading automatisés. Pour ce faire, nous avons d'abord dû définir une stratégie de trading mécanique. Notre idée de trading a été très simple : "Les tendances courtes des marchés volatils sont presque aléatoires". Cela a été observé par plusieurs experts dans certaines circonstances.

Juste après avoir pensé à notre EA en termes réels comme s'il s'agissait d'une créature vivante. Grâce à cette vision, nous avons vu que notre machine Forex peut être composée de trois parties principales : un cerveau, quelque chose que nous avons appelé évolution et un graphique.

Et enfin, nous avons programmé l'expert advisor du système qui intègre la logique nécessaire pour exécuter le backtest, avons exécuté plusieurs fois le robot en janvier 2012, et nous avons constaté que la plupart du temps, le système est gagnant. L'idée derrière ce système s'est avérée vraie mais son efficacité n'est pas très élevée en raison de sa simplicité.


Traduit de l’anglais par MetaQuotes Ltd.
Article original : https://www.mql5.com/en/articles/703

Fichiers joints |
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)
Création d’EA de réseau de neurones en utilisant MQL5 Wizard et Hlaiman EA Generator Création d’EA de réseau de neurones en utilisant MQL5 Wizard et Hlaiman EA Generator
L’article décrit une méthode de création automatisée d’EA de réseau de neurones en utilisant MQL5 Wizard et Hlaiman EA Generator. Il vous montre comment vous pouvez facilement commencer à travailler avec des réseaux de neurones, sans avoir à apprendre tout le corps des informations théoriques et à écrire votre propre code.
Comment installer et utiliser OpenCL pour les calculs Comment installer et utiliser OpenCL pour les calculs
Cela fait plus d'un an que MQL5 a commencé à fournir un support natif pour OpenCL. Cependant, peu d'utilisateurs ont vu la vraie valeur de l'utilisation du calcul parallèle dans leurs Expert Advisors, indicateurs ou scripts. Cet article sert à vous aider à installer et à configurer OpenCL sur votre ordinateur afin que vous puissiez essayer d'utiliser cette technologie dans le terminal de trading MetaTrader 5.
Construire un trader automatique de nouvelles Construire un trader automatique de nouvelles
Ceci est la suite d’un autre article sur la classe MQL5 POO qui vous a montré comment créer un simple EA OO à partir de zéro et vous a donné quelques conseils sur la programmation orientée objet. Aujourd’hui, je vous montre les bases techniques nécessaires pour développer un EA capable d’échanger les nouvelles. Mon objectif est de continuer à vous donner des idées sur la POO et de couvrir également un nouveau sujet dans cette série d’articles, en travaillant avec le système de fichiers.
MQL5 Cookbook : Gestion des événements du graphique typiques MQL5 Cookbook : Gestion des événements du graphique typiques
Cet article examine les événements du graphique typiques et inclut des exemples de leur traitement. Nous nous concentrerons sur les événements de souris, les frappes au clavier, la création/modification/suppression d'un objet graphique, le clic de souris sur un graphique et sur un objet graphique, le déplacement d'un objet graphique avec une souris, la finition de l'édition de texte dans un champ de texte, ainsi que sur les événements de modification de graphique. Un exemple de programme MQL5 est fourni pour chaque type d'événement considéré.