English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
MQL pour "Nuls" : Comment Concevoir et Construire des Classes d'Objets

MQL pour "Nuls" : Comment Concevoir et Construire des Classes d'Objets

MetaTrader 5Expert Advisors | 16 novembre 2021, 15:19
306 0
Sergey Pavlov
Sergey Pavlov

Introduction à la Programmation Orientée-Objet (POO)

Question des "nuls": N'ayant qu'une vague compréhension de la programmation procédurale, est-il possible de maîtriser la POO et de l'utiliser pour rédiger des stratégies de trading automatisées ? Ou cette tâche est-elle au-delà d'un utilisateur commun ?

Dans l'ensemble, il est possible d'utiliser le langage de programmation orienté-objet pour écrire un Expert Advisor ou un indicateur MQL5, sans utiliser les principes de programmation orientée objet. L'utilisation de nouvelles technologies dans vos élaborations n'est pas obligatoire. Choisissez la manière qui vous semble la plus simple. De plus, l'application de la POO ne peut donc plus garantir la rentabilité des robots de trading que vous créez.

Cependant, la transition vers une nouvelle approche (orientée objet) ouvre la voie à l'application de modèles mathématiques adaptatifs plus complexes de stratégies de trading à leurs Expert Advisors, qui réagiront aux modifications externes et se synchroniseront avec le marché.

Jetons donc un coup d'œil aux technologies sur lesquelles la POO est basée :

  1. Événements
  2. Classes d'objets

Les événements sont la base principale de la POO. Toute la logique du programme repose sur le traitement des événements constamment entrants. Les réactions appropriées à ceux-ci sont définies et décrites dans les classes d'objets. En d'autres termes, un objet de classe fonctionne en interceptant et en traitant le flux d'événements.

La seconde base est la classe d'objets, qui à son tour repose sur les « trois piliers » :

  1. Encapsulation - Protection de classe basée sur un principe de "boîte noire" : l'objet réagit aux événements, mais son implémentation factuelle reste inconnue. 
  2. Legs - la possibilité de créer une nouvelle classe à partir d'une classe existante, tout en préservant toutes les propriétés et méthodes de la classe "ancêtre".
  3. Polymorphisme - la possibilité de modifier l'implémentation d'une méthode héritée dans une classe "descendante".

Les concepts de base sont mieux illustrés dans le code Expert Advisor.

Évènements:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()                        // OnInit event processing
  {
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)     // OnDeInit event processing
  {
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()                       // OnTick event processing
  {
  }
//+------------------------------------------------------------------+
//| Expert Timer function                                            |
//+------------------------------------------------------------------+
void OnTimer()                      // OnTimer event processing
  {
  }
//+------------------------------------------------------------------+
//| Expert Chart event function                                      |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,     // OnChartEvent event processing
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
  }

Classe d'objet :

class CNew:public CObject
  {
private:
   int               X,Y;
   void              EditXY();
protected:
   bool              on_event;      //events processing flag
public:
   // Class constructor
   void              CNew();
   // OnChart event processing method
   virtual void      OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam);
  };

Encapsulation:

private:
   int               X,Y;
   void              EditXY();

Legs:

class CNew: public CObject

Polymorphisme:

   // OnChart event processing method
   virtual void      OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam);

Le modificateur virtuel de cette méthode indique que le gestionnaire OnEvent peut être remplacé, mais le nom de la méthode dans ce cas reste le même que celui de la classe ancêtre.

2. Conception de cours

L'un des avantages clés de la POO est son évolutivité - ce qui indique que le système existant est en mesure de fonctionner avec de nouveaux composants, sans y apporter de modifications. De nouveaux composants peuvent être ajoutés à ce stade.

Examinez le processus de conception en créant un programme de conception visuelle des classes MasterWindows pour MQL5.

2.1. Je mets en scène : Ébauche de projet

Le processus de conception commence par un croquis, dessiné au crayon sur une feuille de papier. C'est l'un des moments les plus stimulants et passionnants de la programmation. Il faut tenir compte non seulement de dialogue entre le programme et l'utilisateur (l'interface), mais aussi l'organisation du traitement des données. Ce processus peut prendre plus d'une journée. Il est préférable de commencer par l'interface, car elle peut devenir (dans certains cas, comme dans notre exemple) déterminante lors de la structuration d'un algorithme.

Pour l'organisation du dialogue du programme créé, nous utiliserons le formulaire, similaire à la fenêtre de l'application Windows (voir schéma de la figure 1). Il comporte des lignes, et celles-ci sont à leur tour constituées de cellules et de cellules des objets graphiques. Et ainsi, dès l'étape du design conceptuel, on commence à voir la structure du programme et la classification des objets.

Figure 1. Forme du constructeur de classes (esquisse)

Figure 1. Forme du constructeur de classes (esquisse)

Avec un nombre assez considérable de lignes et de cellules (champs) dans le formulaire, elles sont construites à partir de seulement deux types d'objets graphiques : OBJ_EDIT and OBJ_BUTTON Ainsi, une fois que nous avons déterminé l'apparence visuelle, la structure et les objets de base créés par le programme, nous pouvons supposer que le projet de conception est prêt et qu'il est temps de passer à l'étape suivante.

2.2 Étape II : Conception de la Classe de Base

Il existe trois classes de ce type jusqu'à présent, et d'autres peuvent être ajoutées plus tard (si nécessaire) :

  • cellule de classe CCell;
  • classe ligne CRow, se compose de cellules de classe CCell;
  • fenêtre de classe CWin, se compose de lignes de classe CRow.

Nous pouvons maintenant passer directement à la programmation des classes, mais ... nous devons encore résoudre une tâche très importante - l'échange de données entre les objets des classes. A ces fins, le langage de MQL5 comporte, outre les variables habituelles, une nouvelle structure type. Bien sûr, à ce stade de la conception, on ne peut pas voir toutes les connexions et il est difficile de les calculer. Par conséquent, nous remplirons progressivement la description des classes et des structures au fur et à mesure de l'avancement du projet. De plus, les principes de la POO non seulement n'entravent pas cela, mais en fait le contraire - encouragent la technologie ou la programmation.

Structure WinCell :

struct WinCell
  {
   color             TextColor;     // text color
   color             BGColor;       // background color
   color             BGEditColor;   // background color while editing
   ENUM_BASE_CORNER  Corner;         // anchor corner
   int               H;            // cell height
   int               Corn;         // displacement direction (1;-1)
  };

Les structures qui ne comportent pas de chaînes et d'objets de tableaux dynamiques sont appelées structure simple. Les variables de telles structures peuvent être librement copiées les unes dans les autres, même s'il s'agit de structures différentes. La structure établie est exactement de ce type. Nous évaluerons plus tard son efficacité.

Classe de base CCell :

//+------------------------------------------------------------------+
//| CCell base class                                                 |
//+------------------------------------------------------------------+
class CCell
  {
private:
protected:
   bool              on_event;      // event processing flag
   ENUM_OBJECT       type;           // cell type
public:
   WinCell           Property;     // cell property
   string            name;          // cell name
   //+---------------------------------------------------------------+
   // Class constructor
   void              CCell();
   virtual     // Draw method
   void              Draw(string m_name,
                          int m_xdelta,
                          int m_ydelta,
                          int m_bsize);
   virtual     // Event processing method
   void              OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam);
  };

Classe de base CRow :

//+------------------------------------------------------------------+
//| CRow base class                                                  |
//+------------------------------------------------------------------+
class CRow
  {
protected:
   bool              on_event;      // event processing flag
public:
   string            name;          // row name
   WinCell           Property;     // row property
   //+---------------------------------------------------------------+
   // Class constructor
   void              CRow();
   virtual     // Draw method
   void              Draw(string m_name,
                          int m_xdelta,
                          int m_ydelta,
                          int m_bsize);
   virtual     // Event processing method
   void              OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam);
  };

Classe de base CWin :

//+------------------------------------------------------------------+
//| Base CWin class (WINDOW)                                         |
//+------------------------------------------------------------------+
class CWin
  {
private:
   void              SetXY(int m_corner); //Coordinates
protected:
   bool              on_event;   // event processing flag
public:
   string            name;       // window name
   int               w_corner;   // window corner
   int               w_xdelta;   // vertical delta
   int               w_ydelta;   // horizontal detla
   int               w_xpos;     // X coordinate
   int               w_ypos;     // Y coordinate
   int               w_bsize;    // Window width
   int               w_hsize;    // Window height
   int               w_h_corner; // hide mode corner
   WinCell           Property;   // Property
   //---
   CRowType1         STR1;       // CRowType1
   CRowType2         STR2;       // CRowType2
   CRowType3         STR3;       // CRowType3
   CRowType4         STR4;       // CRowType4
   CRowType5         STR5;       // CRowType5
   CRowType6         STR6;       // CRowType6
   //+---------------------------------------------------------------+
   // Class constructor
   void              CWin();
   // Set window properties
   void              SetWin(string m_name,
                            int m_xdelta,
                            int m_ydelta,
                            int m_bsize,
                            int m_corner);
   virtual     // Draw window method
   void              Draw(int &MMint[][3],
                          string &MMstr[][3],
                          int count);
   virtual     // OnEventTick handler
   void              OnEventTick();
   virtual     // OnChart event handler method
   void              OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam);
  };

Explications et recommandations :

  • Toutes les classes de base (dans ce projet) comportent des méthodes de traitement des événements. elles sont nécessaires pour intercepter et transmettre des événements plus loin dans la chaîne. Sans mécanisme de réception et d'envoi d'événements, le programme (ou module) perd son interactivité.
  • Lors de l’élaboration d'une classe de base, essayez de la construire avec un nombre réduit de méthodes. Ensuite, implémentez diverses extensions de cette classe dans les classes « descendantes », ce qui va booster la fonctionnalité des objets créés.
  • N'utilisez pas un appel direct aux données internes d'une autre classe !

2.3. Stade III : Projet de travail

À ce stade, nous entamons la création du programme étape par étape En commençant par le cadre de support, nous augmenterons ses composants fonctionnels et le remplirons de contenu. Pendant cela, nous observerons l'exactitude du travail, appliquerons le débogage avec un code optimisé et suivrons les erreurs qui apparaissent.

Arrêtons-nous ici et examinerons la technologie de création du cadre, qui fonctionnera pour presque tous les programmes. La principale exigence pour cela - il doit être immédiatement opérationnel (compiler sans erreurs et faire fonctionner lors de l'exécution). Les concepteurs du langage ont pris soin de cela et conseillent d'utiliser le modèle Expert Advisor, qui est généré par l'assistant MQL5, comme cadre.

À titre d'exemple, examinons notre propre version de ce modèle :

1) Programme = Expert Advisor

//+------------------------------------------------------------------+
//|                                                MasterWindows.mq5 |
//|                                                 Copyright DC2008 |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "DC2008"
#property link      "http://www.mql5.com"
#property version   "1.00"
//--- include files with classes
#include <ClassMasterWindows.mqh>
//--- Main module declaration
CMasterWindows    MasterWin;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Launch of the main module
   MasterWin.Run();
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Deinitialization of the main module
   MasterWin.Deinit();
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- call OnTick event handler of main module
   MasterWin.OnEventTick();
  }
//+------------------------------------------------------------------+
//| Expert Event function                                            |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- call OnChartEvent handler of main module
   MasterWin.OnEvent(id,lparam,dparam,sparam);
  }

Ceci est le code complété de l'Expert Advisor. Aucune modification supplémentaire ne doit être apportée tout au long du projet !

2) Le module principal = classe

Tous les modules principaux et auxiliaires du projet commenceront leur élaboration à partir d'ici. Cette approche facilite la programmation de projets multi-modulaires complexes et facilite la recherche d'éventuelles erreurs. Mais les trouver est très difficile. Parfois, il est plus facile et plus rapide d'écrire un nouveau projet plutôt que de rechercher les "bugs" insaisissables.

//+------------------------------------------------------------------+
//|                                           ClassMasterWindows.mqh |
//|                                                 Copyright DC2008 |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "DC2008"
#property link      "http://www.mql5.com"
//+------------------------------------------------------------------+
//| Main module: CMasterWindows class                                |
//+------------------------------------------------------------------+
class CMasterWindows
  {
protected:
   bool              on_event;   // event processing flag
public:
   // Class constructor
   void              CMasterWindows();
   // Method of launching the main module (core algorithm)
   void              Run();
   // Deinitialization method
   void              Deinit();
   // OnTick event processing method
   void              OnEventTick();
   // OnChartEvent event processing method
   void              OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam);
  };

Vous trouverez ci-dessous une première description approximative des principales méthodes de la classe.

//+------------------------------------------------------------------+
//| CMasterWindows class constructor                                 |
//+------------------------------------------------------------------+
void CMasterWindows::CMasterWindows()
   {
//--- class members initialization
   on_event=false;   // disable events processing
   }
//+------------------------------------------------------------------+
//| Метод запуска главного модуля (основной алгоритм)                |
//+------------------------------------------------------------------+
void CMasterWindows::Run()
   {
//--- Main functional of the class: runs additional modules
   ObjectsDeleteAll(0,0,-1);
   Comment("MasterWindows for MQL5     © DC2008");
//---
   on_event=true;   // enable events processing
   }
//+------------------------------------------------------------------+
//| Deinitialization method                                          |
//+------------------------------------------------------------------+
void CMasterWindows::Deinit()
   {
//--- 
   ObjectsDeleteAll(0,0,-1);
   Comment("");
   }
//+------------------------------------------------------------------+
//| OnTick() event processing method                                 |
//+------------------------------------------------------------------+
void CMasterWindows::OnEventTick()
   {
   if(on_event) // event processing is enabled
     {
     //---
     }
   }
//+------------------------------------------------------------------+
//| OnChartEvent() event processing method                           |
//+------------------------------------------------------------------+
void CMasterWindows::OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam)
  {
   if(on_event) // event processing is enabled
     {
     //---
     }
  }

3) La bibliothèque des classes de base et dérivées

La bibliothèque peut comporter n'importe quel nombre de classes dérivées et il est préférable de les regrouper dans des fichiers séparés, qui sont inclus avec la classe de base (le cas échéant). De cette façon, il sera plus facile d'apporter les modifications et ajouts nécessaires, ainsi que - la recherche d'erreurs.

Et donc, nous avons maintenant le cadre du programme. Testons-le et voyons s'il fonctionne correctement : compilez et exécutez. Si le test est réussi, nous pouvons alors commencer à remplir le projet avec des modules supplémentaires.

Commençons par la connexion des classes dérivées, et démarrons par les cellules :

Classe de nom
Image
 Class CCellText

 Class CCellEdit

 Class CCellButton

 Class CCellButtonType

Tableau 1. Bibliothèque de classes de cellules

Examinons en détail la création d'une seule classe dérivée de CCellButtonType. Cette classe crée des boutons de différents types.

//+------------------------------------------------------------------+
//| CCellButtonType class                                            |
//+------------------------------------------------------------------+
class CCellButtonType:public CCell
  {
public:
   ///Class constructor
   void              CCellButtonType();
   virtual     ///Draw method
   void              Draw(string m_name,
                          int m_xdelta,
                          int m_ydelta,
                          int m_type);
  };
//+------------------------------------------------------------------+
//| CCellButtonType class constructor                                |
//+------------------------------------------------------------------+
void CCellButtonType::CCellButtonType()
  {
   type=OBJ_BUTTON;
   on_event=false;   //disable events processing
  }
//+------------------------------------------------------------------+
//| CCellButtonType class Draw method                                |
//+------------------------------------------------------------------+
void CCellButtonType::Draw(string m_name,
                           int m_xdelta,
                           int m_ydelta,
                           int m_type)
  {
//--- creating an object with specified name
   if(m_type<=0) m_type=0;
   name=m_name+".Button"+(string)m_type;
   if(ObjectCreate(0,name,type,0,0,0,0,0)==false)
      Print("Function ",__FUNCTION__," error ",GetLastError());
//--- object properties initializartion
   ObjectSetInteger(0,name,OBJPROP_COLOR,Property.TextColor);
   ObjectSetInteger(0,name,OBJPROP_BGCOLOR,Property.BGColor);
   ObjectSetInteger(0,name,OBJPROP_CORNER,Property.Corner);
   ObjectSetInteger(0,name,OBJPROP_XDISTANCE,m_xdelta);
   ObjectSetInteger(0,name,OBJPROP_YDISTANCE,m_ydelta);
   ObjectSetInteger(0,name,OBJPROP_XSIZE,Property.H);
   ObjectSetInteger(0,name,OBJPROP_YSIZE,Property.H);
   ObjectSetInteger(0,name,OBJPROP_SELECTABLE,0);
   if(m_type==0) // Hide button
     {
      ObjectSetString(0,name,OBJPROP_TEXT,CharToString(MIN_WIN));
      ObjectSetString(0,name,OBJPROP_FONT,"Webdings");
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,12);
     }
   if(m_type==1) // Close button
     {
      ObjectSetString(0,name,OBJPROP_TEXT,CharToString(CLOSE_WIN));
      ObjectSetString(0,name,OBJPROP_FONT,"Wingdings 2");
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,8);
     }
   if(m_type==2) // Return button
     {
      ObjectSetString(0,name,OBJPROP_TEXT,CharToString(MAX_WIN));
      ObjectSetString(0,name,OBJPROP_FONT,"Webdings");
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,12);
     }
   if(m_type==3) // Plus button
     {
      ObjectSetString(0,name,OBJPROP_TEXT,"+");
      ObjectSetString(0,name,OBJPROP_FONT,"Arial");
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,10);
     }
   if(m_type==4) // Minus button
     {
      ObjectSetString(0,name,OBJPROP_TEXT,"-");
      ObjectSetString(0,name,OBJPROP_FONT,"Arial");
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,13);
     }
   if(m_type==5) // PageUp button
     {
      ObjectSetString(0,name,OBJPROP_TEXT,CharToString(PAGE_UP));
      ObjectSetString(0,name,OBJPROP_FONT,"Wingdings 3");
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,8);
     }
   if(m_type==6) // PageDown button
     {
      ObjectSetString(0,name,OBJPROP_TEXT,CharToString(PAGE_DOWN));
      ObjectSetString(0,name,OBJPROP_FONT,"Wingdings 3");
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,8);
     }
   if(m_type>6) // empty button
     {
      ObjectSetString(0,name,OBJPROP_TEXT,"");
      ObjectSetString(0,name,OBJPROP_FONT,"Arial");
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,13);
     }
   on_event=true;   //enable events processing
  }
//+------------------------------------------------------------------+

Explications nécessaires :

  • Nous introduisons une interdiction sur le traitement des événements dans le constructeur de classe. Cela est nécessaire pour préparer l'objet au travail et éliminer les distractions des événements entrants. Une fois toutes les opérations nécessaires terminées, nous autoriserons un tel traitement et l'objet commencera à fonctionner pleinement.
  • La méthode draw utilise des données internes et reçoit des données externes. Par conséquent, les données doivent d'abord être testées pour la conformité, et ensuite seulement traitées, afin d'éviter des situations exceptionnelles. Mais nous n'effectuerons pas ce test dans ce cas particulier. Pourquoi Imaginez que l'objet de classe est un soldat, et les soldats n'ont pas nécessairement besoin de connaître les plans des généraux. Leur travail consiste à suivre clairement, rapidement et rigoureusement les ordres de leurs commandants, au lieu d'analyser les ordres reçus et de prendre des décisions indépendantes. Par conséquent, toutes les données externes doivent être acquittées avant de commencer à travailler avec sa classe.

Maintenant, nous devons tester toute la bibliothèque de cellules. Pour se faire, nous allons insérer le code suivant dans le module principal (provisoirement à des fins de test) et exécuter l'Expert Advisor.

//--- include file with classes
#include <ClassUnit.mqh>
//+------------------------------------------------------------------+
//| Main module: CMasterWindows class                                |
//+------------------------------------------------------------------+
class CMasterWindows
  {
protected:
   bool              on_event;   // events processing flag
   WinCell           Property;   // cell property
   CCellText         Text;
   CCellEdit         Edit;
   CCellButton       Button;
   CCellButtonType   ButtonType;
public:
   // Class constructor
   void              CMasterWindows();
   // Main module run method (core algorithm)
   void              Run();
   // Deinitialization method
   void              Deinit();
   // OnTick event processing method
   void              OnEventTick();
   // OnChart event processing method
   void              OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam);
  };
//+------------------------------------------------------------------+
//| Main module run method (core algorithm)                          |
//+------------------------------------------------------------------+
void CMasterWindows::Run()
  {
//--- core algorithm - it launches additional modules
   ObjectsDeleteAll(0,0,-1);
   Comment("MasterWindows for MQL5     © DC2008");
//--- Text field
   Text.Draw("Text",50,50,150,"Text field");
//--- Edit field
   Edit.Draw("Edit",205,50,150,"default value",true);
//--- LARGE BUTTON
   Button.Draw("Button",50,80,200,"LARGE BUTTON");
//--- Hide button
   ButtonType.Draw("type0",50,100,0);
//--- Close button
   ButtonType.Draw("type1",70,100,1);
//--- Return  button
   ButtonType.Draw("type2",90,100,2);
//--- Plus button
   ButtonType.Draw("type3",110,100,3);
//--- Minus button
   ButtonType.Draw("type4",130,100,4);
//--- None button
   ButtonType.Draw("type5",150,100,5);
//--- None button
   ButtonType.Draw("type6",170,100,6);
//--- None button
   ButtonType.Draw("type7",190,100,7);
//---
   on_event=true;   // enable events processing
  }

Et il ne faut pas oublier de transférer les événements pour les classes résultantes ! Si cela n'est pas fait, la gestion des projets peut devenir très difficile, voire impossible.

//+------------------------------------------------------------------+
//| CMasterWindows class OnChart event processing method             |
//+------------------------------------------------------------------+
void CMasterWindows::OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam)
  {
   if(on_event) // event processing is enabled
     {
      //--- process events for the cell class objects
      Text.OnEvent(id,lparam,dparam,sparam);
      Edit.OnEvent(id,lparam,dparam,sparam);
      Button.OnEvent(id,lparam,dparam,sparam);
      ButtonType.OnEvent(id,lparam,dparam,sparam);
     }
  }

En conséquence, nous voyons toutes les options disponibles pour les objets de la bibliothèque de classes de cellules.

Figure 2. Bibliothèque de classes de cellules

Figure 2. Bibliothèque de cellule classes

Testons l'efficacité opérationnelle et les réactions des objets aux événements :

  • Nous entrons dans le champ d'édition différentes variables, au lieu de "default". Si les valeurs varient, le test a réussi.
  • Nous appuyons sur les boutons, ils restent dans l'état enfoncé jusqu'à ce qu'ils soient à nouveau enfoncés. Ce n'est cependant pas une réaction satisfaisante. Nous avons besoin que le bouton revienne automatiquement à son état d'origine, après avoir appuyé une fois dessus. Et c'est là que nous pouvons démontrer la puissance de la POO - la possibilité de legs. Notre programme peut utiliser plus d'une douzaine de boutons et il n'est pas nécessaire d'ajouter la fonctionnalité souhaitée pour chacun d'eux séparément. Il suffit de modifier la classe de base CCell, et tous les objets des classes dérivées commenceront miraculeusement à fonctionner correctement !
//+------------------------------------------------------------------+
//| CCell class OnChart event processing method                      |
//+------------------------------------------------------------------+
void CCell::OnEvent(const int id,
                    const long &lparam,
                    const double &dparam,
                    const string &sparam)
  {
   if(on_event) // event processing is enabled
     {
      //--- button click event
      if(id==CHARTEVENT_OBJECT_CLICK && StringFind(sparam,".Button",0)>0)
        {
         if(ObjectGetInteger(0,sparam,OBJPROP_STATE)==1)
           {
            //--- if button stays pressed
            Sleep(TIME_SLEEP);
            ObjectSetInteger(0,sparam,OBJPROP_STATE,0);
            ChartRedraw();
           }
        }
     }
  }

Ainsi, la bibliothèque de cellules de classe est testée et liée au projet.

L'étape suivante consiste à ajouter une bibliothèque de lignes :

 Classe de nom
Image
 Classe CRowType1 (0)

 Classe CRowType1 (1)

 Classe CRowType1 (2)

 Classe CRowType1 (3)

 Classe CRowType2

 Classe CRowType3

 Classe CRowType4

 Classe CRowType5

 Classe CRowType6

Tableau2. Bibliothèque de classes de lignes

et nous le testons de la même manière. Après tous les tests, nous passons à l'étape suivante.

2.4 Étape IV : Construire le projet

À ce stade, tous les modules nécessaires ont été créés et testés. Nous procédons maintenant à la construction du projet. Nous créons d'abord une cascade : la forme de la fenêtre comme dans la figure 1 et la remplissons de fonctionnalités, c'est-à-dire des réactions programmées de tous les éléments et modules aux événements entrants.

Pour ce faire, nous avons un cadre prêt du programme et la préparation du module principal. Commençons par ceci. C'est l'une des classes "descendantes", de la classe de base CWin, par conséquent, toutes les méthodes et champs publics de la classe "ancêtre" lui ont été transmis par legs. Par conséquent, nous devons simplement surcharger quelques méthodes et une nouvelle classe CMasterWindows est prête :

//--- include files with classes
#include <ClassWin.mqh>
#include <InitMasterWindows.mqh>
#include <ClassMasterWindowsEXE.mqh>
//+------------------------------------------------------------------+
//| CMasterWindows class                                             |
//+------------------------------------------------------------------+
class CMasterWindows:public CWin
  {
protected:
   CMasterWindowsEXE WinEXE;     // executable module
public:
   void              Run();      // Run method
   void              Deinit();   // Deinitialization method
   virtual                       // OnChart event processing method
   void              OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam);
  };
//+------------------------------------------------------------------+
//| CMasterWindows class deinitialization method                     |
//+------------------------------------------------------------------+
void CMasterWindows::Deinit()
  {
//---(delete all objects)
   ObjectsDeleteAll(0,0,-1);
   Comment("");
  }
//+------------------------------------------------------------------+
//| CMasterWindows class Run method                                  |
//+------------------------------------------------------------------+
void CMasterWindows::Run()
  {
   ObjectsDeleteAll(0,0,-1);
   Comment("MasterWindows for MQL5     © DC2008");
//--- creating designer window and launch executable object
   SetWin("CWin1",1,30,250,CORNER_RIGHT_UPPER);
   Draw(Mint,Mstr,21);
   WinEXE.Init("CWinNew",30,18);
   WinEXE.Run();
  }
//+------------------------------------------------------------------+
//| CMasterWindows class event processing method                     |
//+------------------------------------------------------------------+
void CMasterWindows::OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam)
  {
   if(on_event) // event processing is enabled
     {
      //--- Close button click in the main window
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,"CWin1",0)>=0
         && StringFind(sparam,".Button1",0)>0)
        {
         ExpertRemove();
        }
      //--- OnChart event processing for all objects
      STR1.OnEvent(id,lparam,dparam,sparam);
      STR2.OnEvent(id,lparam,dparam,sparam);
      STR3.OnEvent(id,lparam,dparam,sparam);
      STR4.OnEvent(id,lparam,dparam,sparam);
      STR5.OnEvent(id,lparam,dparam,sparam);
      STR6.OnEvent(id,lparam,dparam,sparam);
      WinEXE.OnEvent(id,lparam,dparam,sparam);
     }
  }

En lui-même, le module principal est assez petit, puisqu'il n'est responsable que de la création de la fenêtre de l'application. Ensuite, il passe le contrôle au module exécutable WinEXE, où se déroule la chose la plus intéressante - la réaction aux événements entrants.

Auparavant, nous avons créé une structure WinCell simple pour l'échange de données entre objets, et maintenant, tous les avantages de cette approche deviennent manifestes. Le processus de copie de tous les membres de la structure est très rationnel et compact :

   STR1.Property = Property;
   STR2.Property = Property;
   STR3.Property = Property;
   STR4.Property = Property;
   STR5.Property = Property;
   STR6.Property = Property;

A ce stade, nous pouvons terminer l'examen détaillé de la conception des classes et passer à la technologie visuelle de leur construction, ce qui accélère considérablement le processus de création de nouvelles classes.

3. Conception visuelle des classes

Une classe peut être construite beaucoup plus rapidement, et peut être visualisée plus facilement, dans le mode de conception visuelle MasterWindows pour MQL5 :


Figure 3. Le processus de conception visuelle

Figure 3. Le processus de conception visuelle

Tout ce qui est requis du développeur - c'est de dessiner le formulaire de la fenêtre, en utilisant les moyens du formulaire MasterWindows, puis de déterminer simplement la réaction à l'événement prévu. Le code lui-même est créé automatiquement. Et c'est tout! Le projet est terminé.

Un exemple de code généré de la classe CMasterWindows, ainsi que de l'Expert Advisor, est illustré à la Figure 4 (un fichier est créé dans le dossier ...\MQL5\Files) :

//****** Project (Expert Advisor): project1.mq5
//+------------------------------------------------------------------+
//|        Code has been generated by MasterWindows Copyright DC2008 |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "DC2008"
//--- include files with classes
#include <ClassWin.mqh>
int Mint[][3]=
  {
     {1,0,0},
     {2,100,0},
     {1,100,0},
     {3,100,0},
     {4,100,0},
     {5,100,0},
     {6,100,50},
     {}
  };
string Mstr[][3]=
  {
     {"New window","",""},
     {"NEW1","new1",""},
     {"NEW2","new2",""},
     {"NEW3","new3",""},
     {"NEW4","new4",""},
     {"NEW5","new5",""},
     {"NEW6","new6",""},
     {}
  };
//+------------------------------------------------------------------+
//| CMasterWindows class (main unit)                                 |
//+------------------------------------------------------------------+
class CMasterWindows:public CWin
  {
private:
   long              Y_hide;          // Window shift vertical in hide mode
   long              Y_obj;           // Window shift vertical
   long              H_obj;           // Window shift horizontal
public:
   bool              on_hide;         // HIDE mode flag
   CArrayString      units;           // Main window lines
   void              CMasterWindows() {on_event=false; on_hide=false;}
   void              Run();           // Run method
   void              Hide();          // Hide method
   void              Deinit()         {ObjectsDeleteAll(0,0,-1); Comment("");}
   virtual void      OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam);
  };
//+------------------------------------------------------------------+
//| CMasterWindows class Run method                                  |
//+------------------------------------------------------------------+
void CMasterWindows::Run()
  {
   ObjectsDeleteAll(0,0,-1);
   Comment("Code has been generated by MasterWindows for MQL5 © DC2008");
//--- creating main window and launch executable module
   SetWin("project1.Exp",50,100,250,CORNER_LEFT_UPPER);
   Draw(Mint,Mstr,7);
  }
//+------------------------------------------------------------------+
//| CMasterWindows class Hide method                                 |
//+------------------------------------------------------------------+
void CMasterWindows::Hide()
  {
   Y_obj=w_ydelta;
   H_obj=Property.H;
   Y_hide=ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS,0)-Y_obj-H_obj;;
//---
   if(on_hide==false)
     {
      int n_str=units.Total();
      for(int i=0; i<n_str; i++)
        {
         long y_obj=ObjectGetInteger(0,units.At(i),OBJPROP_YDISTANCE);
         ObjectSetInteger(0,units.At(i),OBJPROP_YDISTANCE,(int)y_obj+(int)Y_hide);
         if(StringFind(units.At(i),".Button0",0)>0)
            ObjectSetString(0,units.At(i),OBJPROP_TEXT,CharToString(MAX_WIN));
        }
     }
   else
     {
      int n_str=units.Total();
      for(int i=0; i<n_str; i++)
        {
         long y_obj=ObjectGetInteger(0,units.At(i),OBJPROP_YDISTANCE);
         ObjectSetInteger(0,units.At(i),OBJPROP_YDISTANCE,(int)y_obj-(int)Y_hide);
         if(StringFind(units.At(i),".Button0",0)>0)
            ObjectSetString(0,units.At(i),OBJPROP_TEXT,CharToString(MIN_WIN));
        }
     }
//---
   ChartRedraw();
   on_hide=!on_hide;
  }
//+------------------------------------------------------------------+
//| CMasterWindows class OnChartEvent event processing method        |
//+------------------------------------------------------------------+
void CMasterWindows::OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam)
  {
   if(on_event // event handling is enabled
      && StringFind(sparam,"project1.Exp",0)>=0)
     {
      //--- call of OnChartEvent handlers
      STR1.OnEvent(id,lparam,dparam,sparam);
      STR2.OnEvent(id,lparam,dparam,sparam);
      STR3.OnEvent(id,lparam,dparam,sparam);
      STR4.OnEvent(id,lparam,dparam,sparam);
      STR5.OnEvent(id,lparam,dparam,sparam);
      STR6.OnEvent(id,lparam,dparam,sparam);
      //--- creating graphic object
      if(id==CHARTEVENT_OBJECT_CREATE)
        {
         if(StringFind(sparam,"project1.Exp",0)>=0) units.Add(sparam);
        }
      //--- edit [NEW1] in Edit STR1
      if(id==CHARTEVENT_OBJECT_ENDEDIT
         && StringFind(sparam,".STR1",0)>0)
        {
        //--- event processing code
        }
      //--- edit [NEW3] : Plus button STR3
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".STR3",0)>0
         && StringFind(sparam,".Button3",0)>0)
        {
        //--- event processing code
        }
      //--- edit [NEW3] : Minus button STR3
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".STR3",0)>0
         && StringFind(sparam,".Button4",0)>0)
        {
        //--- event processing code
        }
      //--- edit [NEW4] : Plus button STR4
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".STR4",0)>0
         && StringFind(sparam,".Button3",0)>0)
        {
        //--- event processing code
        }
      //--- edit [NEW4] : Minus button STR4
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".STR4",0)>0
         && StringFind(sparam,".Button4",0)>0)
        {
        //--- event processing code
        }
      //--- edit [NEW4] : Up button STR4
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".STR4",0)>0
         && StringFind(sparam,".Button5",0)>0)
        {
        //--- event processing code
        }
      //--- edit [NEW4] : Down button STR4
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".STR4",0)>0
         && StringFind(sparam,".Button6",0)>0)
        {
        //--- event processing code
        }
      //--- [new5] button click STR5
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".STR5",0)>0
         && StringFind(sparam,".Button",0)>0)
        {
        //--- event processing code
        }
      //--- [NEW6] button click STR6
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".STR6",0)>0
         && StringFind(sparam,"(1)",0)>0)
        {
        //--- event processing code
        }
      //--- [new6] button click STR6
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".STR6",0)>0
         && StringFind(sparam,"(2)",0)>0)
        {
        //--- event processing code
        }
      //--- button click [] STR6
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".STR6",0)>0
         && StringFind(sparam,"(3)",0)>0)
        {
        //--- event processing code
        }
      //--- Close button click in the main window
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".Button1",0)>0)
        {
         ExpertRemove();
        }
      //--- Hide button click in the main window
      if(id==CHARTEVENT_OBJECT_CLICK
         && StringFind(sparam,".Button0",0)>0)
        {
         Hide();
        }
     }
  }
//--- Main module declaration
CMasterWindows MasterWin;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- launch main module
   MasterWin.Run();
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- main module deinitialization
   MasterWin.Deinit();
  }
//+------------------------------------------------------------------+
//| Expert Event function                                            |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- call OnChartEvent event handler
   MasterWin.OnEvent(id,lparam,dparam,sparam);
  }

Avec le lancement de ceci, nous constatons la fenêtre conçue suivante:

Figure 4. Projet Advisor1 - le résultat de la conception visuelle des classes

Figure 4.4. Expert Advisor project1 - le résultat de la conception visuelle des classes

Conclusion

  1. Les classes doivent être conçues étape par étape. En décomposant la tâche en modules, une classe distincte est créée pour chacun d'eux. Les modules, à leur tour, sont décomposés en micro-modules de classes dérivées ou de base.
  2. Essayez de ne pas surcharger les classes de base avec des méthodes intégrées - leur nombre doit être réduit au minimum.
  3. La conception des classes avec l'utilisation de l'environnement de conception visuelle est très simple, même pour un « nul », car le code est généré automatiquement.

Emplacement des pièces jointes :

  • masterwindows.mq5 - ...\MQL5\Experts\
  • restant dans le dossier - ...\MQL5\Include\

Traduit du russe par MetaQuotes Ltd.
Article original : https://www.mql5.com/ru/articles/53

Fichiers joints |
Algorithmes Génétiques - C'est Facile ! Algorithmes Génétiques - C'est Facile !
Dans cet article, l'auteur parle de calculs évolutifs à l'aide d'un algorithme génétique personnellement élaboré . Il démontre le fonctionnement de l'algorithme, à l'aide d'exemples, et fournit des recommandations pratiques pour son utilisation.
Création d'un indicateur avec plusieurs tampons d'indicateurs pour les débutants Création d'un indicateur avec plusieurs tampons d'indicateurs pour les débutants
Les codes complexes sont constitués d’un ensemble de codes simples. Si vous les connaissez, cela n’a pas l’air si compliqué. Dans cet article, nous allons examiner comment créer un indicateur avec plusieurs tampons d’indicateurs. À titre d’exemple, l’indicateur Aroon est analysé en détail et deux versions différentes du code sont présentées.
Un Exemple de Stratégie de Trading Axée sur les Différences de Fuseau Horaire sur Différents Continents Un Exemple de Stratégie de Trading Axée sur les Différences de Fuseau Horaire sur Différents Continents
En surfant sur Internet, il est facile de trouver de nombreuses stratégies, qui vous donneront un certain nombre de recommandations diverses. Adoptons une approche d'initié et examinons le processus de création d'une stratégie, axée sur les différences de fuseaux horaires sur les différents continents.
Interaction MetaTrader 5 et MATLAB Interaction MetaTrader 5 et MATLAB
Cet article couvre les détails de l'interaction entre MetaTrader 5 et le package mathématique MatLab. Il indique le mécanisme de conversion des données, le processus d’élaboration d'une bibliothèque universelle pour interagir avec le bureau MatLab. Il couvre également l'utilisation des DLL générées par l'environnement MatLab. Cet article est destiné aux lecteurs expérimentés, connaissant C++ et MQL5.