English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
MQL5 Cookbook : Propriétés de position dans le panneau d'informations personnalisé

MQL5 Cookbook : Propriétés de position dans le panneau d'informations personnalisé

MetaTrader 5Exemples | 13 janvier 2022, 09:42
112 0
Anatoli Kazharski
Anatoli Kazharski

Introduction

Cette fois, nous allons créer un simple Expert Advisor qui obtiendra les propriétés de position sur le symbole actuel et les affichera sur le panneau d'informations personnalisé pendant le trading manuel. Le panneau d'informations sera créé à l'aide d'objets graphiques et les informations affichées seront actualisées à chaque tick. Cela va être beaucoup plus pratique que d'avoir tout le temps à exécuter manuellement le script décrit dans l'article précédent de la série intitulé "MQL5 Cookbook : Getting Position Properties".

 

Développer un Expert Advisor

Commençons par les objets graphiques. Pour créer le panneau d'informations, nous avons besoin d'objets pour l'arrière-plan, l'en-tête, les noms et les valeurs des propriétés de position. L'arrière-plan et l'en-tête nécessiteront un rectangle qui ne bouge pas avec le prix. Le rectangle peut être créé à l'aide d'objets graphiques tels que Rectangle Label ou Edit, tandis que les noms et les valeurs des propriétés de l'objet seront créés à l'aide de Text Labels.

Avant de passer au code, nous allons d'abord préparer une mise en page pour le panneau d'informations. Sa commodité réside dans le fait que nous pouvons modifier rapidement n'importe quelle propriété dans la fenêtre des paramètres et personnaliser l'apparence du panneau d'informations.

Chaque objet a une fenêtre de paramètres qui peut être ouverte à partir du menu contextuel d'un objet sélectionné. La fenêtre des paramètres peut également être ouverte à partir de la liste d'objets (Ctrl+B) en sélectionnant l'objet requis et en cliquant sur Propriétés. La disposition du panneau d'informations est illustrée ci-dessous. Il peut également être utilisé pour estimer les tailles et les coordonnées lors de l'écriture d'un code. Lorsque le code du panneau d'informations sera prêt, vous devrez supprimer les objets de mise en page manuellement car l'Expert Advisor ne pourra pas les 'voir' et ne les supprimera donc pas du graphique.

Fig. 1. Préparation de la mise en page pour le panneau d'information.

Fig. 1. Préparation de la mise en page pour le panneau d'information.

Nous devons maintenant créer un modèle pour l'Expert Advisor. Cela peut être fait aussi rapidement que pour le script. Dans l'assistant MQL5, l'option Expert Advisor (modèle) est sélectionnée par défaut. Nous passons aux étapes suivantes sans apporter de modifications aux options car elles ne sont pas nécessaires cette fois. Cliquez ensuite sur Terminer et vous verrez un modèle comme ci-dessous :

//+------------------------------------------------------------------+
//|                                      PositionPropertiesPanel.mq5 |
//|                        Copyright 2012, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2012, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
  }
//+------------------------------------------------------------------+

On remarque tout de suite que le modèle Expert Advisor est différent du modèle de script. Outre les propriétés du programme (#property), il existe trois fonctions principales : OnInit(), OnDeinit() et OnTick().

La fonction OnInit () est appelée lors du chargement du programme, de la modification des paramètres externes, de la compilation du programme, à condition que le programme soit à ce moment-là ajouté au graphique, et lors du changement de symbole ou de période. Si nécessaire, vous pouvez initialiser certaines variables ou tableaux dans cette fonction pour pouvoir les utiliser ultérieurement.

La fonction OnDeinit() est appelée lorsque vous supprimez le programme du graphique, modifiez le compte, le symbole ou la période. Toutes les raisons de désinitialisation possibles sont fournies dans MQL5 Reference. Cet Expert Advisor emploiera une fonction définie par l'utilisateur, GetDeinitReasonText(), qui convertit l'identifiant de motif de désinitialisation (le paramètre de fonction OnDeinit()) en texte.

Et enfin, la fonction OnTick(). Il est appelé à chaque fois qu'il y a une nouvelle coche sur le symbole sur le graphique duquel l'Expert Advisor opère actuellement.

Préparons maintenant toutes les constantes, variables et tableaux que nous allons utiliser dans l'Expert Advisor. Nous les placerons au tout début du programme. Tout d'abord, définissez les variables dont les valeurs restent inchangées tout au long du programme :

//---
#define INFOPANEL_SIZE 14 // Size of the array for info panel objects
#define EXPERT_NAME MQL5InfoString(MQL5_PROGRAM_NAME) // Name of the Expert Advisor
//---

Ceci est suivi par des variables globales pour les propriétés de position :

//--- GLOBAL VARIABLES
bool                 pos_open=false;         // Flag of presence/absence of an open position
string               pos_symbol="";          // Symbol
long                 pos_magic=0;            // Magic number
string               pos_comment="";         // Comment
double               pos_swap=0.0;           // Swap
double               pos_commission=0.0;     // Commission
double               pos_price=0.0;          // Position price
double               pos_cprice=0.0;         // Current price of the position
double               pos_profit=0.0;         // Profit/Loss of the position
double               pos_volume=0.0;         // Position volume
double               pos_sl=0.0;             // Stop Loss of the position
double               pos_tp=0.0;             // Take Profit of the position
datetime             pos_time=NULL;          // Position opening time
long                 pos_id=0;               // Position identifier
ENUM_POSITION_TYPE   pos_type=WRONG_VALUE;   // Position type

Après les variables, nous allons déclarer des tableaux de noms d'objets graphiques. Ces objets afficheront les propriétés de position et leurs valeurs dans le graphique. À cette fin, nous allons créer deux tableaux de chaînes et initialiser immédiatement leurs éléments en valeurs. Entre crochets, nous utilisons la valeur de la constante INFOPANEL_SIZE déclarée au tout début du programme. C'est-à-dire qu'il y aura 14 éléments dans chaque tableau.

// Array of names of objects that display names of position properties
string positionPropertyNames[INFOPANEL_SIZE]=
  {
   "name_pos_symbol",
   "name_pos_magic",
   "name_pos_comment",
   "name_pos_swap",
   "name_pos_commission",
   "name_pos_price",
   "name_pos_cprice",
   "name_pos_profit",
   "name_pos_volume",
   "name_pos_sl",
   "name_pos_tp",
   "name_pos_time",
   "name_pos_id",
   "name_pos_type"
  };
//---
// Array of names of objects that display values of position properties
string positionPropertyValues[INFOPANEL_SIZE]=
  {
   "value_pos_symbol",
   "value_pos_magic",
   "value_pos_comment",
   "value_pos_swap",
   "value_pos_commission",
   "value_pos_price",
   "value_pos_cprice",
   "value_pos_profit",
   "value_pos_volume",
   "value_pos_sl",
   "value_pos_tp",
   "value_pos_time",
   "value_pos_id",
   "value_pos_type"
  };
//---

En utilisant ces noms, vous pouvez rechercher par programme l'objet nécessaire dans le graphique et définir ou modifier ses propriétés telles que le texte affiché, la couleur, la taille, etc. De plus, ces noms seront affichés dans la fenêtre Liste d'objets (Ctrl+B) après avoir été créés dans le graphique. Mais vous ne pourrez pas les voir là car les objets créés par le programme MQL5 sont masqués par défaut. Pour les rendre visibles, vous devez cliquer sur List All dans la fenêtre Object List. Cette fonctionnalité permet de séparer les objets créés manuellement de ceux créés par programmation, ce qui est certes très pratique.

De plus, nous aurons besoin de fonctions définies par l'utilisateur qui seront utilisées par l'Expert Advisor pour créer des objets graphiques. La fonction offerte par MQL5 pour la création d'objets graphiques est ObjectCreate(). Mais puisque nous devons également définir les propriétés des objets, alors que les objets eux-mêmes peuvent avoir besoin d'être créés plus d'une fois, il serait préférable de penser à une méthode plus pratique et compacte qui pourrait être implémentée en une seule ligne de code.

Pour créer l'arrière-plan et l'en-tête du panneau d'informations, nous allons utiliser l'objet graphique Edit. Écrivons la fonction CreateEdit() :

//+------------------------------------------------------------------+
//| CREATING THE EDIT OBJECT                                         |
//+------------------------------------------------------------------+
void CreateEdit(long             chart_id,         // chart id
                int              sub_window,       // (sub)window number
                string           name,             // object name
                string           text,             // displayed text
                ENUM_BASE_CORNER corner,           // chart corner
                string           font_name,        // font
                int              font_size,        // font size
                color            font_color,       // font color
                int              x_size,           // width
                int              y_size,           // height
                int              x_distance,       // X-coordinate
                int              y_distance,       // Y-coordinate
                long             z_order,          // Z-order
                color            background_color, // background color
                bool             read_only)        // Read Only flag
  {
// If the object has been created successfully,...
   if(ObjectCreate(chart_id,name,OBJ_EDIT,sub_window,0,0))
     {
      // ...set its properties
      ObjectSetString(chart_id,name,OBJPROP_TEXT,text);                 // displayed text
      ObjectSetInteger(chart_id,name,OBJPROP_CORNER,corner);            // set the chart corner
      ObjectSetString(chart_id,name,OBJPROP_FONT,font_name);            // set the font
      ObjectSetInteger(chart_id,name,OBJPROP_FONTSIZE,font_size);       // set the font size
      ObjectSetInteger(chart_id,name,OBJPROP_COLOR,font_color);         // font color
      ObjectSetInteger(chart_id,name,OBJPROP_BGCOLOR,background_color); // background color
      ObjectSetInteger(chart_id,name,OBJPROP_XSIZE,x_size);             // width
      ObjectSetInteger(chart_id,name,OBJPROP_YSIZE,y_size);             // height
      ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,x_distance);     // set the X coordinate
      ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,y_distance);     // set the Y coordinate
      ObjectSetInteger(chart_id,name,OBJPROP_SELECTABLE,false);         // cannot select the object if FALSE
      ObjectSetInteger(chart_id,name,OBJPROP_ZORDER,z_order);           // Z-order of the object
      ObjectSetInteger(chart_id,name,OBJPROP_READONLY,read_only);       // Read Only
      ObjectSetInteger(chart_id,name,OBJPROP_ALIGN,ALIGN_LEFT);         // align left
      ObjectSetString(chart_id,name,OBJPROP_TOOLTIP,"\n");              // no tooltip if "\n"
     }
  }

Maintenant, l'objet graphique Edit (OBJ_EDIT) peut être créé en utilisant une seule ligne de code. Nous allons l'illustrer avec un exemple lors de la création d'une fonction qui définira le panneau d'informations sur le graphique.

Passons maintenant aux objets Text Label qui vont être utilisés pour afficher la liste des propriétés de position et leurs valeurs, et créons la fonction CreateLabel() de la même manière :

//+------------------------------------------------------------------+
//| CREATING THE LABEL OBJECT                                        |
//+------------------------------------------------------------------+
void CreateLabel(long               chart_id,   // chart id
                 int                sub_window, // (sub)window number
                 string             name,       // object name
                 string             text,       // displayed text
                 ENUM_ANCHOR_POINT  anchor,     // anchor point
                 ENUM_BASE_CORNER   corner,     // chart corner
                 string             font_name,  // font
                 int                font_size,  // font size
                 color              font_color, // font color
                 int                x_distance, // X-coordinate
                 int                y_distance, // Y-coordinate
                 long               z_order)    // Z-order
  {
// If the object has been created successfully,...
   if(ObjectCreate(chart_id,name,OBJ_LABEL,sub_window,0,0))
     {
      // ...set its properties
      ObjectSetString(chart_id,name,OBJPROP_TEXT,text);              // displayed text
      ObjectSetString(chart_id,name,OBJPROP_FONT,font_name);         // set the font
      ObjectSetInteger(chart_id,name,OBJPROP_COLOR,font_color);      // set the font color
      ObjectSetInteger(chart_id,name,OBJPROP_ANCHOR,anchor);         // set the anchor point
      ObjectSetInteger(chart_id,name,OBJPROP_CORNER,corner);         // set the chart corner
      ObjectSetInteger(chart_id,name,OBJPROP_FONTSIZE,font_size);    // set the font size
      ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,x_distance);  // set the X-coordinate
      ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,y_distance);  // set the Y-coordinate
      ObjectSetInteger(chart_id,name,OBJPROP_SELECTABLE,false);      // cannot select the object if FALSE
      ObjectSetInteger(chart_id,name,OBJPROP_ZORDER,z_order);        // Z-order of the object
      ObjectSetString(chart_id,name,OBJPROP_TOOLTIP,"\n");           // no tooltip if "\n"
     }
  }

Il est également conseillé de consulter les descriptions des fonctions dans MQL5 Reference.

Lorsqu'il est supprimé du graphique, l'Expert Advisor doit à son tour supprimer tous les objets qu'il a précédemment ajoutés au graphique. Pour ce faire, vous pouvez simplement passer le nom de l'objet à la fonction DeleteObjectByName(). Il recherchera ensuite l'objet par le nom spécifié et le supprimera, s'il est trouvé, à l'aide de la fonction intégrée ObjectFind() qui recherche l'objet et de la fonction ObjectDelete() qui supprime l'objet.

//+------------------------------------------------------------------+
//| DELETING THE OBJECT BY NAME                                      |
//+------------------------------------------------------------------+
void DeleteObjectByname(string name)
  {
   int  sub_window=0;      // Returns the number of the subwindow where the object is located
   bool res       =false;  // Result following an attempt to delete the object
//--- Find the object by name
   sub_window=ObjectFind(ChartID(),name);
//---
   if(sub_window>=0) // If it has been found,..
     {
      res=ObjectDelete(ChartID(),name); // ...delete it
      //---
      // If an error occurred when deleting the object,..
      if(!res) // ...print the relevant message
        {
         Print("Error deleting the object: ("+IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError()));
        }
     }
  }

De plus, dans la fonction DeleteObjectByName(), nous implémentons également une vérification des erreurs lors de la suppression d'un objet. Si une erreur se produit, un message pertinent apparaîtra contenant le code et la description de l'erreur. Comme vous pouvez le voir dans le code ci-dessus, nous utilisons une fonction supplémentaire définie par l'utilisateur qui convertit le code d'erreur en description textuelle - la fonction ErrorDescription(). Comme il y a beaucoup de codes d'erreur, je vais illustrer ce qui précède en n'utilisant qu'une partie de cette fonction (voir le code ci-dessous). La version complète du code se trouve dans le fichier de code source joint à cet article.

//+------------------------------------------------------------------+
//| RETURNING THE ERROR DESCRIPTION                                  |
//+------------------------------------------------------------------+
string ErrorDescription(int error_code)
  {
   string error_string="";
//---
   switch(error_code)
     {
      //--- Trade server return codes

      case 10004: error_string="Requote";                                                                break;
      case 10006: error_string="Request rejected";                                                       break;
      case 10007: error_string="Request canceled by trader";                                             break;
      case 10008: error_string="Order placed";                                                           break;
      case 10009: error_string="Request executed";                                                       break;
      case 10010: error_string="Request executed partially";                                             break;
      case 10011: error_string="Request processing error";                                               break;
      case 10012: error_string="Request timed out";                                                      break;
      case 10013: error_string="Invalid request";                                                        break;
      case 10014: error_string="Invalid request volume";                                                 break;
      case 10015: error_string="Invalid request price";                                                  break;
      case 10016: error_string="Invalid Stop orders in the request";                                     break;
      case 10017: error_string="Trading forbidden";                                                      break;
      case 10018: error_string="Market is closed";                                                       break;
      case 10019: error_string="Insufficient funds";                                                     break;
      case 10020: error_string="Prices changed";                                                         break;
      case 10021: error_string="No quotes to process the request";                                       break;
      case 10022: error_string="Invalid order expiration in the request";                                break;
      case 10023: error_string="Order status changed";                                                   break;
      case 10024: error_string="Too many requests";                                                      break;
      case 10025: error_string="No changes in the request";                                              break;
      case 10026: error_string="Automated trading is disabled by trader";                                break;
      case 10027: error_string="Automated trading is disabled by the client terminal";                   break;
      case 10028: error_string="Request blocked for processing";                                         break;
      case 10029: error_string="Order or position frozen";                                               break;
      case 10030: error_string="The specified type of order execution by balance is not supported";      break;
      case 10031: error_string="No connection with trade server";                                        break;
      case 10032: error_string="Transaction is allowed for live accounts only";                          break;
      case 10033: error_string="You have reached the maximum number of pending orders";                  break;
      case 10034: error_string="You have reached the maximum order and position volume for this symbol"; break;

      ...

     }
//---
   return(error_string);
  }

Dans l'article précédent, nous avons traité de la fonction GetPositionProperties() qui obtient les propriétés de position. Cette fois, la structure de la fonction va être un peu plus complexe. Nous allons vérifier une position actuellement ouverte, le drapeau de présence/absence d'une position ouverte étant stocké dans la variable globale pos_open. Ces informations peuvent être requises dans d'autres fonctions, sans avoir à appeler la fonction PositionSelect() à chaque fois.

Ensuite, si une position ouverte existe, nous obtiendrons ses propriétés, sinon toutes les variables seront mises à zéro. Écrivons maintenant une simple fonction ZeroPositionProperties() :

//+------------------------------------------------------------------+
//| ZEROING OUT VARIABLES FOR POSITION PROPERTIES                    |
//+------------------------------------------------------------------+
void ZeroPositionProperties()
  {
   pos_symbol     ="";
   pos_comment    ="";
   pos_magic      =0;
   pos_price      =0.0;
   pos_cprice     =0.0;
   pos_sl         =0.0;
   pos_tp         =0.0;
   pos_type       =WRONG_VALUE;
   pos_volume     =0.0;
   pos_commission =0.0;
   pos_swap       =0.0;
   pos_profit     =0.0;
   pos_time       =NULL;
   pos_id         =0;
  }

De plus, à la fin de la fonction GetPositionProperties(), nous appellerons une fonction SetInfoPanel() définie par l'utilisateur qui dessine/met à jour le panneau d'informations dans le graphique.

//+------------------------------------------------------------------+
//| GETTING POSITION PROPERTIES                                      |
//+------------------------------------------------------------------+
void GetPositionProperties()
  {
// Check if there is an open position
   pos_open=PositionSelect(_Symbol);
//---
   if(pos_open) // If an open position exists, get its properties
     {
      pos_symbol     =PositionGetString(POSITION_SYMBOL);
      pos_comment    =PositionGetString(POSITION_COMMENT);
      pos_magic      =PositionGetInteger(POSITION_MAGIC);
      pos_price      =PositionGetDouble(POSITION_PRICE_OPEN);
      pos_cprice     =PositionGetDouble(POSITION_PRICE_CURRENT);
      pos_sl         =PositionGetDouble(POSITION_SL);
      pos_tp         =PositionGetDouble(POSITION_TP);
      pos_type       =(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
      pos_volume     =PositionGetDouble(POSITION_VOLUME);
      pos_commission =PositionGetDouble(POSITION_COMMISSION);
      pos_swap       =PositionGetDouble(POSITION_SWAP);
      pos_profit     =PositionGetDouble(POSITION_PROFIT);
      pos_time       =(datetime)PositionGetInteger(POSITION_TIME);
      pos_id         =PositionGetInteger(POSITION_IDENTIFIER);
     }
   else // If there is no open position, zero out variables for position properties
      ZeroPositionProperties();
//---
   SetInfoPanel(); // Set/update the info panel
  }

Écrivons maintenant la fonction SetInfoPanel(). Ci-dessous le code de la fonction avec des commentaires détaillés :

//+------------------------------------------------------------------+
//| SETTING THE INFO PANEL                                           |
//|------------------------------------------------------------------+
void SetInfoPanel()
  {
   int               y_bg=18;             // Y-coordinate for the background and header
   int               y_property=32;       // Y-coordinate for the list of properties and their values
   int               line_height=12;      // Line height
//---
   int               font_size=8;         // Font size
   string            font_name="Calibri"; // Font
   color             font_color=clrWhite; // Font color
//---
   ENUM_ANCHOR_POINT anchor=ANCHOR_RIGHT_UPPER; // Anchor point in the top right corner
   ENUM_BASE_CORNER  corner=CORNER_RIGHT_UPPER; // Origin of coordinates in the top right corner of the chart
//--- X-coordinates
   int               x_first_column=120// First column (names of properties)
   int               x_second_column=10;  // Second column (values of properties)
//--- Array of Y-coordinates for the names of position properties and their values
   int               y_prop_array[INFOPANEL_SIZE]={0};
//--- Fill the array with coordinates for each line on the info panel
   y_prop_array[0]=y_property;
   y_prop_array[1]=y_property+line_height;
   y_prop_array[2]=y_property+line_height*2;
   y_prop_array[3]=y_property+line_height*3;
   y_prop_array[4]=y_property+line_height*4;
   y_prop_array[5]=y_property+line_height*5;
   y_prop_array[6]=y_property+line_height*6;
   y_prop_array[7]=y_property+line_height*7;
   y_prop_array[8]=y_property+line_height*8;
   y_prop_array[9]=y_property+line_height*9;
   y_prop_array[10]=y_property+line_height*10;
   y_prop_array[11]=y_property+line_height*11;
   y_prop_array[12]=y_property+line_height*12;
   y_prop_array[13]=y_property+line_height*13;
//--- Background of the info panel
   CreateEdit(0,0,"InfoPanelBackground","",corner,font_name,8,clrWhite,230,190,231,y_bg,0,C'15,15,15',true);
//--- Header of the info panel
   CreateEdit(0,0,"InfoPanelHeader","POSITION PROPERTIES",corner,font_name,8,clrWhite,230,14,231,y_bg,1,clrFireBrick,true);
//--- List of the names of position properties and their values
//    Property name
   CreateLabel(0,0,pos_prop_names[0],"Symbol :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[0],2);
//    Property value
   CreateLabel(0,0,pos_prop_values[0],GetValInfoPanel(0),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[0],2);
//---
   CreateLabel(0,0,pos_prop_names[1],"Magic Number :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[1],2);
   CreateLabel(0,0,pos_prop_values[1],GetValInfoPanel(1),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[1],2);
//---
   CreateLabel(0,0,pos_prop_names[2],"Comment :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[2],2);
   CreateLabel(0,0,pos_prop_values[2],GetValInfoPanel(2),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[2],2);
//---
   CreateLabel(0,0,pos_prop_names[3],"Swap :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[3],2);
   CreateLabel(0,0,pos_prop_values[3],GetValInfoPanel(3),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[3],2);
//---
   CreateLabel(0,0,pos_prop_names[4],"Commission :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[4],2);
   CreateLabel(0,0,pos_prop_values[4],GetValInfoPanel(4),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[4],2);
//---
   CreateLabel(0,0,pos_prop_names[5],"Open Price :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[5],2);
   CreateLabel(0,0,pos_prop_values[5],GetValInfoPanel(5),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[5],2);
//---
   CreateLabel(0,0,pos_prop_names[6],"Current Price :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[6],2);
   CreateLabel(0,0,pos_prop_values[6],GetValInfoPanel(6),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[6],2);
//---
   CreateLabel(0,0,pos_prop_names[7],"Profit :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[7],2);
   CreateLabel(0,0,pos_prop_values[7],GetValInfoPanel(7),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[7],2);
//---
   CreateLabel(0,0,pos_prop_names[8],"Volume :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[8],2);
   CreateLabel(0,0,pos_prop_values[8],GetValInfoPanel(8),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[8],2);
//---
   CreateLabel(0,0,pos_prop_names[9],"Stop Loss :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[9],2);
   CreateLabel(0,0,pos_prop_values[9],GetValInfoPanel(9),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[9],2);
//---
   CreateLabel(0,0,pos_prop_names[10],"Take Profit :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[10],2);
   CreateLabel(0,0,pos_prop_values[10],GetValInfoPanel(10),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[10],2);
//---
   CreateLabel(0,0,pos_prop_names[11],"Time :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[11],2);
   CreateLabel(0,0,pos_prop_values[11],GetValInfoPanel(11),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[11],2);
//---
   CreateLabel(0,0,pos_prop_names[12],"Identifier :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[12],2);
   CreateLabel(0,0,pos_prop_values[12],GetValInfoPanel(12),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[12],2);
//---
   CreateLabel(0,0,pos_prop_names[13],"Type :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[13],2);
   CreateLabel(0,0,pos_prop_values[13],GetValInfoPanel(13),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[13],2);
//---
   ChartRedraw(); // Redraw the chart
  }

Examinons de plus près la fonction SetInfoPanel(). Les variables qui ont à voir avec les propriétés des objets graphiques (coordonnées, couleur, police, texte affiché, etc.) sont déclarées au début de la fonction. Faites attention au processus de remplissage du tableau de coordonnées Y pour la liste des propriétés de position sur le panneau d'informations. Il est mis en œuvre d'une manière qui est claire pour les débutants. Mais cela peut être réduit à quelques lignes de code lors de l'utilisation d'une boucle. Vous pouvez l'écrire comme suit :

//--- Fill the array with coordinates for each line on the info panel
   for(int i=0; i<INFOPANEL_SIZE; i++)
     {
      if(i==0) y_prop_array[i]=y_property;
      else     y_prop_array[i]=y_property+line_height*i;
     }

Ensuite, toutes les propriétés des objets qui doivent être affichés sur le panneau doivent être spécifiées dans les paramètres des fonctions CreateLabel() et CreateEdit() créées précédemment, en prenant un objet à la fois. La liste entière peut également être implémentée en quelques lignes de code à l'aide d'une boucle. Pour ce faire, nous devons créer un autre tableau pour les objets qui affichent le texte des noms des propriétés de position dans le graphique. Que ce soit votre devoir.

La fonction GetPropertyValue() qui reçoit le numéro d'objet renvoie la valeur qui est ensuite transmise à la fonction CreateLabel() comme quatrième paramètre (texte affiché). Cela concerne tous les objets qui afficheront des valeurs de propriétés de position. La valeur renvoyée par la fonction est une valeur de chaîne ajustée qui sera finalement affichée sur le panneau. Ci-dessous le code de la fonction avec des commentaires détaillés :

//+------------------------------------------------------------------+
//| RETURNING THE STRING WITH POSITION PROPERTY VALUE                |
//+------------------------------------------------------------------+
string GetPropertyValue(int number)
  {
//--- Sign indicating the lack of an open position or a certain property
//    E.g. the lack of a comment, Stop Loss or Take Profit
   string empty="-";
//--- If an open position exists, return the value of the requested property
   if(pos_open)
     {
      switch(number)
        {
         case 0  : return(pos_symbol);                                           break;
         case 1  : return(IntegerToString((int)pos_magic));                      break;
         //--- return the value of the comment, if any, otherwise return the sign indicating the lack of comment
         case 2  : return(pos_comment!="" ? pos_comment : empty);                break;
         case 3  : return(DoubleToString(pos_swap,2));                           break;
         case 4  : return(DoubleToString(pos_commission,2));                     break;
         case 5  : return(DoubleToString(pos_price,_Digits));                    break;
         case 6  : return(DoubleToString(pos_cprice,_Digits));                   break;
         case 7  : return(DoubleToString(pos_profit,2));                         break;
         case 8  : return(DoubleToString(pos_volume,2));                         break;
         case 9  : return(pos_sl!=0.0 ? DoubleToString(pos_sl,_Digits) : empty); break;
         case 10 : return(pos_tp!=0.0 ? DoubleToString(pos_tp,_Digits) : empty); break;
         case 11 : return(TimeToString(pos_time,TIME_DATE|TIME_MINUTES));        break;
         case 12 : return(IntegerToString((int)pos_id));                         break;
         case 13 : return(PositionTypeToString(pos_type));                       break;
         
         default : return(empty);
        }
     }
//---
// If there is no open position, return the sign indicating the lack of the open position "-"
   return(empty);
  }

Le code ci-dessus suggère qu'une certaine valeur est préparée pour chaque nombre passé à la fonction, à condition qu'il y ait une position ouverte. S'il n'y a actuellement aucune position ouverte, la fonction renverra un tiret (-) affiché pour tous les objets qui ont à voir avec les valeurs de propriété de position.

À la fin de la fonction SetInfoPanel(), nous appelons la fonction ChartRedraw() conçue pour un rafraîchissement forcé du graphique. À moins qu'il ne soit appelé, vous ne pourrez pas voir les modifications apportées.

Nous devons maintenant écrire une fonction qui supprimera tous les objets graphiques créés par l'Expert Advisor. Appelons-le DeleteInfoPanel() :

//+------------------------------------------------------------------+
//| DELETING THE INFO PANEL                                          |
//+------------------------------------------------------------------+
void DeleteInfoPanel()
  {
   DeleteObjectByName("InfoPanelBackground");   // Delete the panel background
   DeleteObjectByName("InfoPanelHeader");       // Delete the panel header
//--- Delete position properties and their values
   for(int i=0; i<INFOPANEL_SIZE; i++)
     {
      DeleteObjectByName(pos_prop_names[i]);    // Delete the property
      DeleteObjectByName(pos_prop_values[i]);   // Delete the value
     }
//---
   ChartRedraw(); // Redraw the chart
  }

Il ne nous reste plus qu'à répartir les méthodes que nous avons créées parmi les fonctions principales de l'Expert Advisor qui étaient à l'origine présentes dans le modèle après l'avoir créé dans l’assistant MQL5 Wizard. C'est la partie la plus facile :

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Get the properties and set the panel
   GetPositionProperties();
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Print the deinitialization reason to the journal
   Print(GetDeinitReasonText(reason));
//--- When deleting from the chart
   if(reason==REASON_REMOVE)
      //--- Delete all objects relating to the info panel from the chart
      DeleteInfoPanel();

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Get the properties and update the values on the panel
   GetPositionProperties();

  }
//+------------------------------------------------------------------+

La seule chose sur laquelle vous pourriez tomber est la fonction GetDeinitReasonText() qui renvoie une description textuelle du code de motif de désinitialisation :

//+---------------------------------------------------------------------+
//| RETURNING A TEXTUAL DESCRIPTION OF THE DEINITIALIZATION REASON CODE |
//+---------------------------------------------------------------------+
string GetDeinitReasonText(int reason_code)
  {
   string text="";
//---
   switch(reason_code)
     {
      case REASON_PROGRAM :     // 0
         text="The Expert Advisor has stopped working calling the ExpertRemove() function.";   break;
      case REASON_REMOVE :      // 1
         text="The '"+EXPERT_NAME+"' program has been removed from the chart.";                break;
      case REASON_RECOMPILE :   // 2
         text="The '"+EXPERT_NAME+"' program has been recompiled.";                            break;
      case REASON_CHARTCHANGE : // 3
         text="Chart symbol or period has been changed.";                                      break;
      case REASON_CHARTCLOSE :  // 4
         text="The chart is closed.";                                                          break;
      case REASON_PARAMETERS :  // 5
         text="Input parameters have been changed by the user.";                               break;
      case REASON_ACCOUNT :     // 6
         text="A different account has been activated.";                                       break;
      case REASON_TEMPLATE :    // 7
         text="A different chart template has been applied.";                                  break;
      case REASON_INITFAILED :  // 8
         text="A flag specifying that the OnInit() handler returned zero value.";              break;
      case REASON_CLOSE :       // 9
         text="The terminal has been closed.";                                                 break;
      default : text="The reason is undefined.";
     }
//---
   return text;
  }

Si vous essayez d'utiliser l'Expert Advisor sur le symbole du graphique qui n'a actuellement aucune position ouverte, vous verrez des tirets au lieu des valeurs de propriété de position sur le panneau. Le panneau aura le même aspect après avoir fermé une certaine position.

Fig. 2. Panneau d'information en l'absence d’une position ouverte.

Fig. 2. Panneau d'information en l'absence de position ouverte.

Si l'Expert Advisor est ajouté au graphique du symbole qui a une position ouverte ou si une position est ouverte après avoir ajouté l'Expert Advisor au graphique, tous les tirets seront remplacés par les valeurs de propriété de position appropriées :

Fig. 3. Panneau d'information affichant les propriétés de la position ouverte.

Fig. 3. Panneau d'information affichant les propriétés de la position ouverte.

Il y a une petite particularité. Après avoir fermé la position, ce n'est qu'à la nouvelle coche que les valeurs sur le panneau sont mises à jour. Il existe un moyen de mettre les valeurs à jour immédiatement, mais ce qui doit être fait pour mettre en œuvre cela sera discuté dans le prochain article de la série.

 

Conclusion

Certaines des fonctions présentées dans cet article seront également utilisées dans les articles suivants de la série MQL5 Cookbook, tandis que d'autres seront modifiées et améliorées en fonction de la tâche à accomplir. Il est conseillé de lire les articles dans l'ordre, l'un après l'autre car chaque nouvel article est la suite logique du précédent. Cela dépend certainement aussi de votre niveau de compétence et de compétences, il peut donc être plus raisonnable et intéressant de commencer par des publications plus récentes. 

Le fichier de code source est joint à l'article.

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

MQL5 Cookbook : Analyse des propriétés de position dans le testeur de stratégie MetaTrader 5 MQL5 Cookbook : Analyse des propriétés de position dans le testeur de stratégie MetaTrader 5
Nous vous présenterons une version modifiée de l'Expert Advisor de l'article précédent "MQL5 Cookbook : Propriétés de la position dans le panneau d'informations personnalisé". Certains des problèmes que nous aborderons incluent l'obtention de données à partir de barres, la vérification de nouveaux événements de barre sur le symbole actuel, y compris une classe de trade de la bibliothèque standard dans un fichier, la création d'une fonction pour rechercher des signaux de trading et une fonction pour exécuter des opérations de trading , ainsi que la détermination des événements de trade dans la fonction OnTrade().
MQL5 Cookbook : Obtention des propriétés de la position MQL5 Cookbook : Obtention des propriétés de la position
Dans cet article, nous allons créer un script qui récupère toutes les propriétés de position et les affiche à l'utilisateur dans une boîte de dialogue. Lors de l'exécution du script, vous pourrez sélectionner l'un des deux modes disponibles dans la liste déroulante des paramètres externes : soit pour afficher les propriétés de position uniquement sur le symbole actuel, soit pour afficher les propriétés de position sur tous les symboles.
MQL5 Cookbook : Comment éviter les erreurs lors de la définition/modification des niveaux de trade MQL5 Cookbook : Comment éviter les erreurs lors de la définition/modification des niveaux de trade
Dans la continuité de notre travail sur l'Expert Advisor de l'article précédent de la série intitulée "MQL5 Cookbook : Analyse des propriétés des positions dans le testeur de stratégie MetaTrader 5", nous l'améliorerons avec de nombreuses fonctions utiles, ainsi que d'améliorer et d'optimiser celles existantes. L'Expert Advisor aura cette fois des paramètres externes qui peuvent être optimisés dans le testeur de stratégie MetaTrader 5 et ressemblera à certains égards à un simple système de trading.
MQL5 Cookbook : Utilisation de différents modes d'impression MQL5 Cookbook : Utilisation de différents modes d'impression
Ceci est le premier article de la série MQL5 Cookbook. Je commencerai par des exemples simples pour permettre à ceux qui font leurs premiers pas en programmation de se familiariser petit à petit avec le nouveau langage. Je me souviens de mes premiers efforts pour concevoir et programmer des systèmes de trading qui, je peux le dire, étaient assez difficiles, étant donné que c'était le premier langage de programmation de ma vie. Cependant, cela s'est avéré plus facile que je ne le pensais et il ne m'a fallu que quelques mois avant de pouvoir développer un programme assez complexe.