English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Le MQL5 Cookbook : Surveillance de plusieurs trames temporelles dans une seule fenêtre

Le MQL5 Cookbook : Surveillance de plusieurs trames temporelles dans une seule fenêtre

MetaTrader 5Exemples | 13 janvier 2022, 08:54
249 0
Anatoli Kazharski
Anatoli Kazharski

Introduction

Lors du choix de la direction d'ouverture d'une position, un graphique des prix avec plusieurs trames temporelles affichées en même temps peut être très utile. Le terminal client MetaTrader 5 fournit 21 trames temporelles d'analyse. Vous pouvez tirer parti d'objets graphiques spéciaux que vous pouvez placer sur le graphique existant et définir le symbole, la trame temporelle et d'autres propriétés à cet endroit. Vous pouvez ajouter n'importe quel nombre de tels objets de graphique, mais cela serait assez gênant et prendrait du temps si cela était fait manuellement. De plus, toutes les propriétés du graphique ne peuvent pas être définies en mode manuel.

Dans cet article, nous examinerons de plus près ces objets graphiques. À des fins d'illustration, nous allons créer un indicateur avec des commandes (boutons) qui nous permettront de définir plusieurs objets de graphique dans une sous-fenêtre en même temps. De plus, les objets du graphique s'adapteront avec précision dans la sous-fenêtre et seront automatiquement ajustés lorsque le graphique principal ou la fenêtre du terminal est redimensionné.

En plus des boutons pour ajouter des objets de graphique, nous aurons également des boutons pour activer/désactiver certaines propriétés du graphique, y compris celles qui ne peuvent être modifiées que par programmation.


Développement

Vous pouvez ajouter manuellement un objet graphique en utilisant Insert menu->Objects->Graphical Objects->Chart. Par exemple, voici comment les objets avec les trames temporelles H4 et D1 sont affichés sur le graphique 1 heure :

Fig. 1. Objets cartographiques

Fig. 1. Objets de graphique

En modifiant les paramètres de l'objet, vous ne pouvez gérer qu'un ensemble limité de propriétés :

Fig. 2. Propriétés de l'objet graphique

Fig. 2. Propriétés de l'objet graphique

Pourtant, des paramètres tels que les niveaux de prix de demande et d'offre, le retrait du bord droit du graphique, les niveaux de trade, etc. ne peuvent être affichés que s'ils sont correctement programmés.

Nous commençons donc le développement de l'indicateur. Disons que nous l'appelons ChartObjects (titre provisoire de l'article). À l'aide de MQL5 Wizard, créez un modèle pour l'indicateur dans MetaEditor. Lorsque vous sélectionnez les gestionnaires d'événements du programme d'indicateurs personnalisés, optez pour ceux comme indiqué dans la capture d'écran ci-dessous :

Fig. 3. Gestionnaires d'événements de l'indicateur

Fig. 3. Gestionnaires d'événements de l'indicateur

Lorsqu'il est ouvert dans MetaEditor, le code source du modèle se présente comme suit :

//+------------------------------------------------------------------+
//|                                                 ChartObjects.mq5 |
//|                        Copyright 2013, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
  {
//---
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| TradeTransaction function                                        |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
                        const MqlTradeRequest& request,
                        const MqlTradeResult& result)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   
  }
//+------------------------------------------------------------------+

Nous n'aurons fondamentalement pas besoin de la fonction OnCalculate() dans cette implémentation mais il est impossible de compiler l'indicateur sans elle. De plus, nous aurons besoin de l'une des fonctions principales - OnDeinit(). Il surveillera la suppression du programme à partir du graphique. Après le traitement primaire du modèle, nous avons le code source suivant :

//+------------------------------------------------------------------+
//|                                                 ChartObjects.mq5 |
//|                        Copyright 2013, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
//---
#property indicator_chart_window // Indicator is in the main window
#property indicator_plots 0      // Zero plotting series
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set the short name for the indicator
   IndicatorSetString(INDICATOR_SHORTNAME,"TimeFramesPanel");
//--- Initialization completed successfully
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Indicator deinitialization                                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- If the indicator has been deleted from the chart
   if(reason==REASON_REMOVE)
     {
     }
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
  {
//---

//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---

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

Maintenant, nous devons créer un indicateur qui sera utilisé comme stockage (sous-fenêtre) pour les objets du graphique. Ce sera essentiellement un indicateur factice. Appelons-le SubWindow. Son code est fourni ci-dessous :

//+------------------------------------------------------------------+
//|                                                    SubWindow.mq5 |
//|                        Copyright 2013, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
//---
#property indicator_chart_window // Indicator is in the subwindow
#property indicator_plots 0      // Zero plotting series
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set the short name for the indicator
   IndicatorSetString(INDICATOR_SHORTNAME,"SubWindow");
//--- Initialization completed successfully
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
  {
//---
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

L'indicateur SubWindow.ex5 sera stocké en tant que ressource dans ChartObjects.ex5 après la compilation. Ainsi, le développeur du programme sera finalement en mesure de fournir à l'utilisateur final un seul fichier au lieu de deux.

Comme déjà décrit dans l'article précédent intitulé "MQL5 Cookbook : Notifications sonores pour les événements de trading de MetaTrader 5", les fichiers de ressources peuvent être inclus dans un programme à l'aide de la directive #resource. Au début de notre programme ChartObjects, nous devons ajouter la chaîne de code suivante :

//--- Include indicator resource
#resource "\\Indicators\\SubWindow.ex5"

Ensuite, à l'aide de la directive #define, nous définissons les tailles des tableaux qui seront attribués aux commandes :

//--- Number of time frame buttons
#define TIMEFRAME_BUTTONS 21
//--- Number of buttons for chart object properties
#define PROPERTY_BUTTONS 5

Et, comme d'habitude, nous déclarons des variables globales au tout début du programme :

//--- Location of the SubWindow indicator in the resource
string subwindow_path         ="::Indicators\\SubWindow.ex5";
int    subwindow_number       =-1;               // Subwindow number
int    subwindow_handle       =INVALID_HANDLE;   // SubWindow indicator handle
string subwindow_shortname    ="SubWindow";      // Short name of the indicator
//---
int    chart_width            =0;                // Chart width
int    chart_height           =0;                // Chart height
int    chart_scale            =0;                // Chart scale
//---
color  cOffButtonFont         =clrWhite;         // Unclicked button text color
color  cOffButtonBackground   =clrDarkSlateGray; // Unclicked button background color
color  cOffButtonBorder       =clrLightGray;     // Unclicked button border color
//---
color  cOnButtonFont          =clrGold;          // Clicked button text color
color  cOnButtonBackground    =C'28,47,47';      // Clicked button background color
color  cOnButtonBorder        =clrLightGray;     // Clicked button border color

Ceci est suivi par la déclaration de tableaux pour les boutons de trame temporelle :

//--- Array of object names for time frame buttons
string timeframe_button_names[TIMEFRAME_BUTTONS]=
  {
   "button_M1","button_M2","button_M3","button_M4","button_M5","button_M6","button_M10",
   "button_M12","button_M15","button_M20","button_M30","button_H1","button_H2","button_H3",
   "button_H4","button_H6","button_H8","button_H12","button_D1","button_W1","button_MN"
  };
//--- Array of text displayed on time frame buttons
string timeframe_button_texts[TIMEFRAME_BUTTONS]=
  {
   "M1","M2","M3","M4","M5","M6","M10",
   "M12","M15","M20","M30","H1","H2","H3",
   "H4","H6","H8","H12","D1","W1","MN"
  };
//--- Array of time frame button states
bool timeframe_button_states[TIMEFRAME_BUTTONS]={false};

Tableaux de boutons pour commander les propriétés de l'objet graphique :

//--- Array of object names for buttons of chart properties
string property_button_names[PROPERTY_BUTTONS]=
  {
   "property_button_date","property_button_price",
   "property_button_ohlc","property_button_askbid",
   "property_button_trade_levels"
  };
//--- Array of text displayed on buttons of chart properties
string property_button_texts[PROPERTY_BUTTONS]=
  {
   "Date","Price","OHLC","Ask / Bid","Trade Levels"
  };
//--- Array of states for buttons of chart properties
bool property_button_states[PROPERTY_BUTTONS]={false};

//--- Array of sizes for buttons of chart properties
int property_button_widths[PROPERTY_BUTTONS]=
  {
   66,68,66,100,101
  };

Et enfin, nous avons un tableau de noms d'objets graphiques :

//--- Array of chart object names
string chart_object_names[TIMEFRAME_BUTTONS]=
  {
   "chart_object_m1","chart_object_m2","chart_object_m3","chart_object_m4","chart_object_m5","chart_object_m6","chart_object_m10",
   "chart_object_m12","chart_object_m15","chart_object_m20","chart_object_m30","chart_object_h1","chart_object_h2","chart_object_h3",
   "chart_object_h4","chart_object_h6","chart_object_h8","chart_object_h12","chart_object_d1","chart_object_w1","chart_object_mn"
  };

Avant de passer aux fonctions liées à l'interaction avec les objets graphiques, écrivons d'abord les fonctions qui créent ces objets dans le graphique. Dans notre programme, nous aurons besoin de deux types d'objets graphiques : OBJ_BUTTON et OBJ_CHART.

Les boutons seront créés par la fonction CreateButton() :

//+------------------------------------------------------------------+
//| Creating the Button object                                       |
//+------------------------------------------------------------------+
void CreateButton(long              chart_id,         // chart id
                  int               window_number,    // window number
                  string            name,             // object name
                  string            text,             // displayed name
                  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
                  color             background_color, // background color
                  color             border_color,     // border color
                  int               x_size,           // width
                  int               y_size,           // height
                  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_BUTTON,window_number,0,0))
     {
      // set its properties
      ObjectSetString(chart_id,name,OBJPROP_TEXT,text);                  // setting name
      ObjectSetString(chart_id,name,OBJPROP_FONT,font_name);             // setting font
      ObjectSetInteger(chart_id,name,OBJPROP_COLOR,font_color);          // setting font color
      ObjectSetInteger(chart_id,name,OBJPROP_BGCOLOR,background_color);  // setting background color
      ObjectSetInteger(chart_id,name,OBJPROP_BORDER_COLOR,border_color); // setting border color
      ObjectSetInteger(chart_id,name,OBJPROP_ANCHOR,anchor);             // setting anchor point
      ObjectSetInteger(chart_id,name,OBJPROP_CORNER,corner);             // setting chart corner
      ObjectSetInteger(chart_id,name,OBJPROP_FONTSIZE,font_size);        // setting font size
      ObjectSetInteger(chart_id,name,OBJPROP_XSIZE,x_size);              // setting width
      ObjectSetInteger(chart_id,name,OBJPROP_YSIZE,y_size);              // setting height
      ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,x_distance);      // setting X-coordinate
      ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,y_distance);      // setting Y-coordinate
      ObjectSetInteger(chart_id,name,OBJPROP_SELECTABLE,false);          // object is not available for selection
      ObjectSetInteger(chart_id,name,OBJPROP_STATE,false);               // button state (clicked/unclicked)
      ObjectSetInteger(chart_id,name,OBJPROP_ZORDER,z_order);            // Z-order for getting the click event
      ObjectSetString(chart_id,name,OBJPROP_TOOLTIP,"\n");               // no tooltip
     }
  }

En conséquence, la création d'un graphique dans une sous-fenêtre sera effectuée par la fonction CreateChartInSubwindow() :

//+------------------------------------------------------------------+
//| Creating a chart object in a subwindow                           |
//+------------------------------------------------------------------+
void CreateChartInSubwindow(int             window_number,  // subwindow number
                            int             x_distance,     // X-coordinate
                            int             y_distance,     // Y-coordinate
                            int             x_size,         // width
                            int             y_size,         // height
                            string          name,           // object name
                            string          symbol,         // symbol
                            ENUM_TIMEFRAMES timeframe,      // time frame
                            int             subchart_scale, // bar scale
                            bool            show_dates,     // show date scale
                            bool            show_prices,    // show price scale
                            bool            show_ohlc,      // show OHLC prices
                            bool            show_ask_bid,   // show ask/bid levels
                            bool            show_levels,    // show trade levels
                            string          tooltip)        // tooltip
  {
//--- If the object has been created successfully
   if(ObjectCreate(0,name,OBJ_CHART,window_number,0,0))
     {
      //--- Set the properties of the chart object
      ObjectSetInteger(0,name,OBJPROP_CORNER,CORNER_LEFT_UPPER);   // chart corner
      ObjectSetInteger(0,name,OBJPROP_XDISTANCE,x_distance);       // X-coordinate
      ObjectSetInteger(0,name,OBJPROP_YDISTANCE,y_distance);       // Y-coordinate
      ObjectSetInteger(0,name,OBJPROP_XSIZE,x_size);               // width
      ObjectSetInteger(0,name,OBJPROP_YSIZE,y_size);               // height
      ObjectSetInteger(0,name,OBJPROP_CHART_SCALE,subchart_scale); // bar scale
      ObjectSetInteger(0,name,OBJPROP_DATE_SCALE,show_dates);      // date scale
      ObjectSetInteger(0,name,OBJPROP_PRICE_SCALE,show_prices);    // price scale
      ObjectSetString(0,name,OBJPROP_SYMBOL,symbol);               // symbol
      ObjectSetInteger(0,name,OBJPROP_PERIOD,timeframe);           // time frame
      ObjectSetString(0,name,OBJPROP_TOOLTIP,tooltip);             // tooltip
      ObjectSetInteger(0,name,OBJPROP_BACK,false);                 // object in the foreground
      ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);           // object is not available for selection
      ObjectSetInteger(0,name,OBJPROP_COLOR,clrWhite);             // white color
      //--- Get the chart object identifier
      long subchart_id=ObjectGetInteger(0,name,OBJPROP_CHART_ID);
      //--- Set the special properties of the chart object
      ChartSetInteger(subchart_id,CHART_SHOW_OHLC,show_ohlc);           // OHLC
      ChartSetInteger(subchart_id,CHART_SHOW_TRADE_LEVELS,show_levels); // trade levels
      ChartSetInteger(subchart_id,CHART_SHOW_BID_LINE,show_ask_bid);    // bid level
      ChartSetInteger(subchart_id,CHART_SHOW_ASK_LINE,show_ask_bid);    // ask level
      ChartSetInteger(subchart_id,CHART_COLOR_LAST,clrLimeGreen);       // color of the level of the last executed deal 
      ChartSetInteger(subchart_id,CHART_COLOR_STOP_LEVEL,clrRed);       // color of Stop order levels  
      //--- Refresh the chart object
      ChartRedraw(subchart_id);
     }
  }

Dans le code ci-dessus, nous définissons d'abord les propriétés de graphique standard pour un objet graphique. Après avoir obtenu l'identifiant de l'objet graphique, les propriétés spéciales sont définies. Il est également important d'actualiser l'objet graphique à l'aide de la fonction ChartRedraw(), l'identifiant de l'objet graphique lui étant transmis.

Divisons le réglage des commandes entre deux fonctions : AddTimeframeButtons() et AddPropertyButtons():

//+------------------------------------------------------------------+
//| Adding time frame buttons                                        |
//+------------------------------------------------------------------+
void AddTimeframeButtons()
  {
   int x_dist =1;   // Indent from the left side of the chart
   int y_dist =125; // Indent from the bottom of the chart
   int x_size =28;  // Button width
   int y_size =20;  // Button height
//---
   for(int i=0; i<TIMEFRAME_BUTTONS; i++)
     {
      //--- If 7 buttons have already been added to the same row, set the coordinates for the next row
      if(i%7==0)
        {
         x_dist=1;
         y_dist-=21;
        }
      //--- Add a time frame button
      CreateButton(0,0,timeframe_button_names[i],timeframe_button_texts[i],
                   ANCHOR_LEFT_LOWER,CORNER_LEFT_LOWER,"Arial",8,
                   cOffButtonFont,cOffButtonBackground,cOffButtonBorder,
                   x_size,y_size,x_dist,y_dist,3);
      //--- Set the X-coordinate for the next button
      x_dist+=x_size+1;
     }
  }
//+------------------------------------------------------------------+
//| Adding buttons of chart properties                               |
//+------------------------------------------------------------------+
void AddPropertyButtons()
  {
   int x_dist =1;  // Indent from the left side of the chart
   int y_dist =41; // Indent from the bottom of the chart
   int x_size =66; // Button width
   int y_size =20; // Button height
//---
   for(int i=0; i<PROPERTY_BUTTONS; i++)
     {
      //--- If the first three buttons have already been added, set the coordinates for the next row
      if(i==3)
        {
         x_dist=1;
         y_dist-=21;
        }
      //--- Add a button
      CreateButton(0,0,property_button_names[i],property_button_texts[i],
                   ANCHOR_LEFT_LOWER,CORNER_LEFT_LOWER,"Arial",8,
                   cOffButtonFont,cOffButtonBackground,cOffButtonBorder,
                   property_button_widths[i],y_size,x_dist,y_dist,3);
      //--- Set the X-coordinate for the next button
      x_dist+=property_button_widths[i]+1;
     }
  } 

Lors de la suppression de l'indicateur du graphique, nous devons également supprimer les objets créés par le programme. Pour cela, nous aurons besoin des fonctions auxiliaires suivantes :

//+------------------------------------------------------------------+
//| Deleting the panel with time frame buttons                       |
//+------------------------------------------------------------------+
void DeleteTimeframeButtons()
  {
   for(int i=0; i<TIMEFRAME_BUTTONS; i++)
      DeleteObjectByName(timeframe_button_names[i]);
  }
//+------------------------------------------------------------------+
//| Deleting the panel with buttons of chart properties              |
//+------------------------------------------------------------------+
void DeletePropertyButtons()
  {
   for(int i=0; i<PROPERTY_BUTTONS; i++)
      DeleteObjectByName(property_button_names[i]);
  }
//+------------------------------------------------------------------+
//| Deleting objects by name                                         |
//+------------------------------------------------------------------+
void DeleteObjectByName(string object_name)
  {
//--- If such object exists
   if(ObjectFind(ChartID(),object_name)>=0)
     {
      //--- Delete it or print the relevant error message
      if(!ObjectDelete(ChartID(),object_name))
         Print("Error ("+IntegerToString(GetLastError())+") when deleting the object!");
     }
  } 

Maintenant, pour nous assurer que le panneau est défini sur le graphique lors du chargement de l'indicateur et que tous les objets du panneau sont supprimés lors de la suppression de l'indicateur du graphique, nous devons ajouter les chaînes de code suivantes aux fonctions de gestion OnInit() et OnDeinit() :

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Add the panel with time frame buttons to the chart
   AddTimeframeButtons();
//--- Add the panel with buttons of chart properties to the chart
   AddPropertyButtons();
//--- Redraw the chart
   ChartRedraw();
//--- Initialization completed successfully
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Indicator deinitialization                                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- If the indicator has been deleted from the chart
   if(reason==REASON_REMOVE)
     {
      //--- Delete buttons
      DeleteTimeframeButtons();
      DeletePropertyButtons();
      //--- Redraw the chart
      ChartRedraw();
     }
  }

Si nous compilions l'indicateur maintenant et l'attaquions au graphique, nous verrions le panneau comme illustré dans la capture d'écran ci-dessous :

Fig. 4. Le panneau avec les boutons

Fig. 4. Le panneau avec les boutons

Maintenant, tout est prêt pour commencer à créer des fonctions d'interaction entre l'utilisateur et le panneau. La quasi-totalité d'entre eux seront appelés à partir de la fonction principale OnChartEvent(). Dans cet article, nous allons considérer deux événements qui seront gérés dans cette fonction :

  • CHARTEVENT_OBJECT_CLICK - événement du clic sur un objet graphique.
  • CHARTEVENT_CHART_CHANGE - événement de redimensionnement du graphique ou de modification des propriétés du graphique à l'aide de la fenêtre de dialogue des propriétés.

Commençons par l'événement CHARTEVENT_OBJECT_CLICK. La fonction ChartEventObjectClick() que nous sommes sur le point d'écrire obtiendra tous les arguments de la fonction OnChartEvent() (pour d'autres événements, nous créerons des fonctions similaires) :

//+------------------------------------------------------------------+
//| Event of the click on a graphical object                         |
//+------------------------------------------------------------------+
bool ChartEventObjectClick(int id,
                           long lparam,
                           double dparam,
                           string sparam)
  {
//--- Click on a graphical object
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- If a time frame button has been clicked, set/delete 'SubWindow' and a chart object
      if(ToggleSubwindowAndChartObject(sparam))
         return(true);
      //--- If a button of chart properties has been clicked, set/delete the property in chart objects
      if(ToggleChartObjectProperty(sparam))
         return(true);
     }
//---
   return(false);
  }

Le code de la fonction ChartEventObjectClick() est simple. L'événement de clic sur le bouton du panneau est déterminé à l'aide de l'identifiant. Ensuite, la logique de mise en œuvre est divisée en deux directions : la gestion de l'événement de clic sur les boutons de trame temporelle ou l'événement de clic sur les boutons des propriétés du graphique. Le paramètre de chaîne sparam contenant le nom de l'objet sur lequel vous avez cliqué avec le bouton gauche est transmis aux fonctions ToggleSubwindowAndChartObject() et ToggleChartObjectProperty() correspondantes.

Regardons le code source de ces fonctions. Nous allons commencer par ToggleSubwindowAndChartObject() :

//+------------------------------------------------------------------+
//| Setting/deleting SubWindow and a chart object                    |
//+------------------------------------------------------------------+
bool ToggleSubwindowAndChartObject(string clicked_object_name)
  {
//--- Make sure that the click was on the time frame button object
   if(CheckClickOnTimeframeButton(clicked_object_name))
     {
      //--- Check if the SubWindow exists
      subwindow_number=ChartWindowFind(0,subwindow_shortname);
      //--- If the SubWindow does not exist, set it
      if(subwindow_number<0)
        {
         //--- If the SubWindow is set
         if(AddSubwindow())
           {
            //--- Add chart objects to it
            AddChartObjectsToSubwindow(clicked_object_name);
            return(true);
           }
        }
      //--- If the SubWindow exists
      if(subwindow_number>0)
        {
         //--- Add chart objects to it
         AddChartObjectsToSubwindow(clicked_object_name);
         return(true);
        }
     }
//---
   return(false);
  }

Vous devriez être en mesure de comprendre facilement la logique d'implémentation à l'aide des commentaires fournis dans le code ci-dessus. Les chaînes en évidence comportent des fonctions personnalisées dont le code peut être trouvé plus loin.

La fonction CheckClickOnTimeframeButton() renvoie true si le bouton cliqué est associé au panneau des trames temporelles :

//+------------------------------------------------------------------+
//| Checking if a time frame button has been clicked                 |
//+------------------------------------------------------------------+
bool CheckClickOnTimeframeButton(string clicked_object_name)
  {
//--- Iterate over all time frame buttons and check the names 
   for(int i=0; i<TIMEFRAME_BUTTONS; i++)
     {
      //--- Report the match
      if(clicked_object_name==timeframe_button_names[i])
         return(true);
     }
//---
   return(false);
  }

Si le clic sur un bouton de trame temporelle a été confirmé, nous vérifions ensuite si la sous-fenêtre (SubWindow) est actuellement ajoutée au graphique principal. Sinon, il est défini à l'aide de la fonction AddSubwindow() :

//+------------------------------------------------------------------+
//| Adding a subwindow for chart objects                             |
//+------------------------------------------------------------------+
bool AddSubwindow()
  {
//--- Get the "SubWindow" indicator handle
   subwindow_handle=iCustom(_Symbol,_Period,subwindow_path);
//--- If the handle has been obtained
   if(subwindow_handle!=INVALID_HANDLE)
     {
      //--- Determine the number of windows in the chart for the subwindow number
      subwindow_number=(int)ChartGetInteger(0,CHART_WINDOWS_TOTAL);
      //--- Add the SubWindow to the chart
      if(!ChartIndicatorAdd(0,subwindow_number,subwindow_handle))
         Print("Failed to add the SUBWINDOW indicator ! ");
      //--- The subwindow exists
      else
         return(true);
     }
//--- There is no subwindow
   return(false);
  }

Nous ajoutons ensuite des objets graphiques à la sous-fenêtre créée à l'aide de la fonction AddChartObjectsToSubwindow() :

//+------------------------------------------------------------------+
//| Adding chart objects to the subwindow                            |
//+------------------------------------------------------------------+
void AddChartObjectsToSubwindow(string clicked_object_name)
  {
   ENUM_TIMEFRAMES tf                 =WRONG_VALUE; // Time frame
   string          object_name        ="";          // Object name
   string          object_text        ="";          // Object text
   int             x_distance         =0;           // X-coordinate
   int             total_charts       =0;           // Total chart objects
   int             chart_object_width =0;           // Chart object width
//--- Get the bar scale and SubWindow height/width
   chart_scale=(int)ChartGetInteger(0,CHART_SCALE);
   chart_width=(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS,subwindow_number);
   chart_height=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS,subwindow_number);
//--- Get the number of chart objects in the SUBWINDOW
   total_charts=ObjectsTotal(0,subwindow_number,OBJ_CHART);
//--- If there are no chart objects
   if(total_charts==0)
     {
      //--- Check if a time frame button has been clicked
      if(CheckClickOnTimeframeButton(clicked_object_name))
        {
         //--- Initialize the array of time frame buttons
         InitializeTimeframeButtonStates();
         //--- Get the time frame button text for the chart object tooltip
         object_text=ObjectGetString(0,clicked_object_name,OBJPROP_TEXT);
         //--- Get the time frame for the chart object
         tf=StringToTimeframe(object_text);
         //--- Set the chart object
         CreateChartInSubwindow(subwindow_number,0,0,chart_width,chart_height,
                                "chart_object_"+object_text,_Symbol,tf,chart_scale,
                                property_button_states[0],property_button_states[1],
                                property_button_states[2],property_button_states[3],
                                property_button_states[4],object_text);
         //--- Refresh the chart and exit
         ChartRedraw();
         return;
        }
     }
//--- If chart objects already exist in the SubWindow
   if(total_charts>0)
     {
      //--- Get the number of clicked time frame buttons and initialize the array of states
      int pressed_buttons_count=InitializeTimeframeButtonStates();
      //--- If there are no clicked buttons, delete the SubWindow
      if(pressed_buttons_count==0)
         DeleteSubwindow();
      //--- If the clicked buttons exist
      else
        {
         //--- Delete all chart objects from the subwindow
         ObjectsDeleteAll(0,subwindow_number,OBJ_CHART);
         //--- Get the width for chart objects
         chart_object_width=chart_width/pressed_buttons_count;
         //--- Iterate over all buttons in a loop
         for(int i=0; i<TIMEFRAME_BUTTONS; i++)
           {
            //--- If the button is clicked
            if(timeframe_button_states[i])
              {
               //--- Get the time frame button text for the chart object tooltip
               object_text=ObjectGetString(0,timeframe_button_names[i],OBJPROP_TEXT);
               //--- Get the time frame for the chart object
               tf=StringToTimeframe(object_text);
               //--- Set the chart object
               CreateChartInSubwindow(subwindow_number,x_distance,0,chart_object_width,chart_height,
                                      chart_object_names[i],_Symbol,tf,chart_scale,
                                      property_button_states[0],property_button_states[1],
                                      property_button_states[2],property_button_states[3],
                                      property_button_states[4],object_text);
               //--- Determine the X-coordinate for the next chart object
               x_distance+=chart_object_width;
              }
           }
        }
     }
//--- Refresh the chart
   ChartRedraw();
  }

Les commentaires détaillés fournis dans le code ci-dessus devraient vous aider à comprendre le fonctionnement de la fonction. Les fonctions personnalisées que nous n'avons pas rencontrées auparavant sont mises en évidence.

La fonction InitializeTimeframeButtonStates() renvoie le nombre de boutons de trame temporelle cliqués et initialise le tableau d'états correspondant. Il définit également des couleurs en fonction de l'état du bouton :

//+------------------------------------------------------------------+
//| Initializing array of time frame button states and               |
//| returning the number of clicked buttons                          |
//+------------------------------------------------------------------+
int InitializeTimeframeButtonStates()
  {
//--- Counter of the clicked time frame buttons
   int pressed_buttons_count=0;
//--- Iterate over all time frame buttons and count the clicked ones
   for(int i=0; i<TIMEFRAME_BUTTONS; i++)
     {
      //--- If the button is clicked
      if(ObjectGetInteger(0,timeframe_button_names[i],OBJPROP_STATE))
        {
         //--- Indicate it in the current index of the array
         timeframe_button_states[i]=true;
         //--- Set clicked button colors
         ObjectSetInteger(0,timeframe_button_names[i],OBJPROP_COLOR,cOnButtonFont);
         ObjectSetInteger(0,timeframe_button_names[i],OBJPROP_BGCOLOR,cOnButtonBackground);
         //--- Increase the counter by one
         pressed_buttons_count++;
        }
      else
        {
         //--- Set unclicked button colors
         ObjectSetInteger(0,timeframe_button_names[i],OBJPROP_COLOR,cOffButtonFont);
         ObjectSetInteger(0,timeframe_button_names[i],OBJPROP_BGCOLOR,cOffButtonBackground);
         //--- Indicate that the button is unclicked
         timeframe_button_states[i]=false;
        }
     }
//--- Return the number of clicked buttons
   return(pressed_buttons_count);
  }

La fonction DeleteSubwindow() est très simple : elle vérifie l'existence de la sous-fenêtre pour les graphiques et la supprime :

//+------------------------------------------------------------------+
//| Deleting subwindow for chart objects                             |
//+------------------------------------------------------------------+
void DeleteSubwindow()
  {
//--- If the SubWindow exists
   if((subwindow_number=ChartWindowFind(0,subwindow_shortname))>0)
     {
      //--- Delete it
      if(!ChartIndicatorDelete(0,subwindow_number,subwindow_shortname))
         Print("Failed to delete the "+subwindow_shortname+" indicator!");
     }
  }

Nous devons maintenant examiner les propriétés des objets de graphique. En d'autres termes, nous revenons à la fonction ChartEventObjectClick() et considérons la fonction ToggleChartObjectProperty(). Le nom de l'objet cliqué lui est également transmis.

//+------------------------------------------------------------------+
//| Setting/deleting chart object property                           |
//| depending on the clicked button state                            |
//+------------------------------------------------------------------+
bool ToggleChartObjectProperty(string clicked_object_name)
  {

//--- If the "Date" button is clicked
   if(clicked_object_name=="property_button_date")
     {
      //--- If the button is clicked
      if(SetButtonColor(clicked_object_name))
         ShowDate(true);
      //--- If the button is unclicked
      else
         ShowDate(false);
      //--- Refresh the chart and exit
      ChartRedraw();
      return(true);
     }
//--- If the "Price" button is clicked
   if(clicked_object_name=="property_button_price")
     {
      //--- If the button is clicked
      if(SetButtonColor(clicked_object_name))
         ShowPrice(true);
      //--- If the button is unclicked
      else
         ShowPrice(false);
      //--- Refresh the chart and exit
      ChartRedraw();
      return(true);
     }
//--- If the "OHLC" button is clicked
   if(clicked_object_name=="property_button_ohlc")
     {
      //--- If the button is clicked
      if(SetButtonColor(clicked_object_name))
         ShowOHLC(true);
      //--- If the button is unclicked
      else
         ShowOHLC(false);
      //--- Refresh the chart and exit
      ChartRedraw();
      return(true);
     }
//--- If the "Ask/Bid" button is clicked
   if(clicked_object_name=="property_button_askbid")
     {
      //--- If the button is clicked
      if(SetButtonColor(clicked_object_name))
         ShowAskBid(true);
      //--- If the button is unclicked
      else
         ShowAskBid(false);
      //--- Refresh the chart and exit
      ChartRedraw();
      return(true);
     }
//--- If the "Trade Levels" button is clicked
   if(clicked_object_name=="property_button_trade_levels")
     {
      //--- If the button is clicked
      if(SetButtonColor(clicked_object_name))
         ShowTradeLevels(true);
      //--- If the button is unclicked
      else
         ShowTradeLevels(false);
      //--- Refresh the chart and exit
      ChartRedraw();
      return(true);
     }
//--- No matches
   return(false);
  }

Dans le code ci-dessus, le nom de l'objet cliqué est successivement comparé au nom de l'objet lié aux propriétés du graphe. S'il y a une correspondance, nous vérifions ensuite si le bouton est cliqué ou non dans la fonction SetButtonColor() et définissons les couleurs de bouton appropriées.

//+------------------------------------------------------------------+
//| Setting color of button elements depending on the state          |
//+------------------------------------------------------------------+
bool SetButtonColor(string clicked_object_name)
  {
//--- If the button is clicked
   if(ObjectGetInteger(0,clicked_object_name,OBJPROP_STATE))
     {
      //--- Set clicked button colors
      ObjectSetInteger(0,clicked_object_name,OBJPROP_COLOR,cOnButtonFont);
      ObjectSetInteger(0,clicked_object_name,OBJPROP_BGCOLOR,cOnButtonBackground);
      return(true);
     }
//--- If the button is unclicked
   if(!ObjectGetInteger(0,clicked_object_name,OBJPROP_STATE))
     {
      //--- Set unclicked button colors
      ObjectSetInteger(0,clicked_object_name,OBJPROP_COLOR,cOffButtonFont);
      ObjectSetInteger(0,clicked_object_name,OBJPROP_BGCOLOR,cOffButtonBackground);
      return(false);
     }
//---
   return(false);
  }

La fonction SetButtonColor() renvoie l'état du bouton. Selon cet attribut, le programme informe la fonction concernée qu'une certaine propriété doit être activée ou désactivée dans tous les objets de diagramme dans la sous-fenêtre. Une fonction distincte est écrite pour chaque propriété. Les codes de fonction correspondants sont fournis ci-dessous :

//+------------------------------------------------------------------+
//| Enabling/disabling dates for all chart objects                   |
//+------------------------------------------------------------------+
void ShowDate(bool state)
  {
   int    total_charts =0;  // Number of objects
   string chart_name  =""; // Chart object name
//--- Check if the SubWindow exists
//    If it exists, then
   if((subwindow_number=ChartWindowFind(0,subwindow_shortname))>0)
     {
      //--- Get the number of chart objects
      total_charts=ObjectsTotal(0,subwindow_number,OBJ_CHART);
      //--- Iterate over all chart objects in a loop
      for(int i=0; i<total_charts; i++)
        {
         //--- Get the chart object name
         chart_name=ObjectName(0,i,subwindow_number,OBJ_CHART);
         //--- Set the property
         ObjectSetInteger(0,chart_name,OBJPROP_DATE_SCALE,state);
        }
      //--- Set the button state to the relevant index
      if(state)
         property_button_states[0]=true;
      else
         property_button_states[0]=false;
      //--- Refresh the chart
      ChartRedraw();
     }
  }
//+------------------------------------------------------------------+
//| Enabling/disabling prices for all chart objects                  |
//+------------------------------------------------------------------+
void ShowPrice(bool state)
  {
   int    total_charts =0;  // Number of objects
   string chart_name  =""; // Chart object name
//--- Check if the SubWindow exists
//    If it exists, then
   if((subwindow_number=ChartWindowFind(0,subwindow_shortname))>0)
     {
      //--- Get the number of chart objects
      total_charts=ObjectsTotal(0,subwindow_number,OBJ_CHART);
      //--- Iterate over all chart objects in a loop
      for(int i=0; i<total_charts; i++)
        {
         //--- Get the chart object name
         chart_name=ObjectName(0,i,subwindow_number,OBJ_CHART);
         //--- Set the property
         ObjectSetInteger(0,chart_name,OBJPROP_PRICE_SCALE,state);
        }
      //--- Set the button state to the relevant index
      if(state)
         property_button_states[1]=true;
      else
         property_button_states[1]=false;
      //--- Refresh the chart
      ChartRedraw();
     }
  }
//+------------------------------------------------------------------+
//| Enabling/disabling OHLC for all chart objects                    |
//+------------------------------------------------------------------+
void ShowOHLC(bool state)
  {
   int    total_charts =0;  // Number of objects
   long   subchart_id =0;  // Chart object identifier
   string chart_name  =""; // Chart object name
//--- Check if the SubWindow exists
//    If it exists, then
   if((subwindow_number=ChartWindowFind(0,subwindow_shortname))>0)
     {
      //--- Get the number of chart objects
      total_charts=ObjectsTotal(0,subwindow_number,OBJ_CHART);
      //--- Iterate over all chart objects in a loop
      for(int i=0; i<total_charts; i++)
        {
         //--- Get the chart object name
         chart_name=ObjectName(0,i,subwindow_number,OBJ_CHART);
         //--- Get the chart object identifier
         subchart_id=ObjectGetInteger(0,chart_name,OBJPROP_CHART_ID);
         //--- Set the property
         ChartSetInteger(subchart_id,CHART_SHOW_OHLC,state);
         //--- Refresh the chart object
         ChartRedraw(subchart_id);
        }
      //--- Set the button state to the relevant index
      if(state)
         property_button_states[2]=true;
      else
         property_button_states[2]=false;
      //--- Refresh the chart
      ChartRedraw();
     }
  }
//+------------------------------------------------------------------+
//| Enabling/disabling Ask/Bid levels for all chart objects          |
//+------------------------------------------------------------------+
void ShowAskBid(bool state)
  {
   int    total_charts =0;  // Number of objects
   long   subchart_id =0;  // Chart object identifier
   string chart_name  =""; // Chart object name
//--- Check if the SubWindow exists
//    If it exists, then
   if((subwindow_number=ChartWindowFind(0,subwindow_shortname))>0)
     {
      //--- Get the number of chart objects
      total_charts=ObjectsTotal(0,subwindow_number,OBJ_CHART);
      //--- Iterate over all chart objects in a loop
      for(int i=0; i<total_charts; i++)
        {
         //--- Get the chart object name
         chart_name=ObjectName(0,i,subwindow_number,OBJ_CHART);
         //--- Get the chart object identifier
         subchart_id=ObjectGetInteger(0,chart_name,OBJPROP_CHART_ID);
         //--- Set the properties
         ChartSetInteger(subchart_id,CHART_SHOW_ASK_LINE,state);
         ChartSetInteger(subchart_id,CHART_SHOW_BID_LINE,state);
         //--- Refresh the chart object
         ChartRedraw(subchart_id);
        }
      //--- Set the button state to the relevant index
      if(state)
         property_button_states[3]=true;
      else
         property_button_states[3]=false;
      //--- Refresh the chart
      ChartRedraw();
     }
  }
//+------------------------------------------------------------------+
//| Enabling/disabling trade levels for all chart objects            |
//+------------------------------------------------------------------+
void ShowTradeLevels(bool state)
  {
   int    total_charts =0;  // Number of objects
   long   subchart_id =0;  // Chart object identifier
   string chart_name  =""; // Chart object name
//--- Check if the SubWindow exists
//    If it exists, then
   if((subwindow_number=ChartWindowFind(0,subwindow_shortname))>0)
     {
      //--- Get the number of chart objects
      total_charts=ObjectsTotal(0,subwindow_number,OBJ_CHART);
      //--- Iterate over all chart objects in a loop
      for(int i=0; i<total_charts; i++)
        {
         //--- Get the chart object name
         chart_name=ObjectName(0,i,subwindow_number,OBJ_CHART);
         //--- Get the chart object identifier
         subchart_id=ObjectGetInteger(0,chart_name,OBJPROP_CHART_ID);
         //--- Set the property
         ChartSetInteger(subchart_id,CHART_SHOW_TRADE_LEVELS,state);
         //--- Refresh the chart object
         ChartRedraw(subchart_id);
        }
      //--- Set the button state to the relevant index
      if(state)
         property_button_states[4]=true;
      else
         property_button_states[4]=false;
      //--- Refresh the chart
      ChartRedraw();
     }
  }

Maintenant, toutes les fonctions sont prêtes pour l'interaction avec le panneau. Nous avons seulement besoin d'ajouter une chaîne de code à la fonction principale OnChartEvent() :

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- The CHARTEVENT_OBJECT_CLICK event
   if(ChartEventObjectClick(id,lparam,dparam,sparam))
      return;

  }

Si l'indicateur est compilé et exécuté dans le graphique en ce moment, les objets du graphique seront ajoutés à la sous-fenêtre lorsque les boutons de trame temporelle pertinente sont cliqués. De plus, si nous cliquons sur l'un des boutons de propriétés, nous pourrons voir les changements correspondants dans les objets du graphique :

Fig. 5. Ajout des objets du graphique avec les propriétés spécifiées

Fig. 5. Ajout des objets de graphique avec les propriétés spécifiées

Cependant, si la fenêtre ou la sous-fenêtre du graphique est redimensionnée, les tailles des objets du graphique ne seront pas ajustées en conséquence. Il est donc temps de voir l'événement CHARTEVENT_CHART_CHANGE.

Tout comme nous avons créé la fonction ChartEventObjectClick() pour suivre l'événement de "clic sur un objet graphique", écrivons maintenant la fonction ChartEventChartChange() :

//+------------------------------------------------------------------+
//| Event of modifying the chart properties                          |
//+------------------------------------------------------------------+
bool ChartEventChartChange(int id,
                           long lparam,
                           double dparam,
                           string sparam)
  {
//--- Chart has been resized or the chart properties have been modified
   if(id==CHARTEVENT_CHART_CHANGE)
     {
      //--- If the SubWindow has been deleted (or does not exist), while the time frame buttons are clicked, 
      //    release all the buttons (reset)
      if(OnSubwindowDelete())
         return(true);
      //--- Save the height and width values of the main chart and SubWindow, if it exists
      GetSubwindowWidthAndHeight();
      //--- Adjust the sizes of chart objects
      AdjustChartObjectsSizes();
      //--- Refresh the chart and exit
      ChartRedraw();
      return(true);
     }
//---
   return(false);
  }

Si le programme a établi que la taille ou les propriétés du graphique principal ont été modifiées, nous utilisons d'abord la fonction OnSubwindowDelete() pour vérifier si la sous-fenêtre a été supprimée. Si la sous-fenêtre est introuvable, le panneau est réinitialisé.

//+------------------------------------------------------------------+
//| Response to Subwindow deletion                                   |
//+------------------------------------------------------------------+
bool OnSubwindowDelete()
  {
//--- if there is no SubWindow
   if(ChartWindowFind(0,subwindow_shortname)<1)
     {
      //--- Reset the panel with time frame buttons
      AddTimeframeButtons();
      ChartRedraw();
      return(true);
     }
//--- SubWindow exists
   return(false);
  }

Si la sous-fenêtre est là où elle devrait être, les valeurs de largeur et de hauteur de la sous-fenêtre sont attribuées aux variables globales dans la fonction GetSubwindowWidthAndHeight() :

//+------------------------------------------------------------------+
//| Saving the SubWindow height and width values                     |
//+------------------------------------------------------------------+
void GetSubwindowWidthAndHeight()
  {
//--- Check if there is a subwindow named SubWindow
   if((subwindow_number=ChartWindowFind(0,subwindow_shortname))>0)
     {
      // Get the subwindow height and width
      chart_height=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS,subwindow_number);
      chart_width=(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS,subwindow_number);
     }
  }

Et enfin, les tailles des objets graphiques sont ajustées dans la fonction AdjustChartObjectsSizes() :

//+------------------------------------------------------------------+
//| Adjusting width of chart objects when modifying the window width |
//+------------------------------------------------------------------+
void AdjustChartObjectsSizes()
  {
   int             x_distance         =0;           // X-coordinate
   int             total_objects      =0;           // Number of chart objects
   int             chart_object_width =0;           // Chart object width
   string          object_name        ="";          // Object name
   ENUM_TIMEFRAMES TF                 =WRONG_VALUE; // Time frame
//--- Get the SubWindow number
   if((subwindow_number=ChartWindowFind(0,subwindow_shortname))>0)
     {
      //--- Get the total number of chart objects
      total_objects=ObjectsTotal(0,subwindow_number,OBJ_CHART);
      //--- If there are no objects, delete the subwindow and exit
      if(total_objects==0)
        {
         DeleteSubwindow();
         return;
        }
      //--- Get the width for chart objects
      chart_object_width=chart_width/total_objects;
      //--- Iterate over all chart objects in a loop
      for(int i=total_objects-1; i>=0; i--)
        {
         //--- Get the name
         object_name=ObjectName(0,i,subwindow_number,OBJ_CHART);
         //--- Set the chart object width and height
         ObjectSetInteger(0,object_name,OBJPROP_YSIZE,chart_height);
         ObjectSetInteger(0,object_name,OBJPROP_XSIZE,chart_object_width);
         //--- Set the chart object position
         ObjectSetInteger(0,object_name,OBJPROP_YDISTANCE,0);
         ObjectSetInteger(0,object_name,OBJPROP_XDISTANCE,x_distance);
         //--- Set the new X-coordinate for the next chart object
         x_distance+=chart_object_width;
        }
     }
  }

Pour suivre l'événement de modification de la taille et des propriétés du graphique principal, la chaîne suivante doit être ajoutée à la fonction OnChartEvent() :

Après avoir compilé l'indicateur et l'avoir attaché au graphique, vous pourrez voir que les objets du graphique sont ajustés à la taille de la sous-fenêtre chaque fois que la fenêtre principale est redimensionnée.

 

Conclusion

Terminons l'article ici. En tant que devoir, essayez d'implémenter une fonctionnalité telle que l'ajustement des symboles dans les objets du graphique lorsque le symbole du graphique principal est modifié. Vous pouvez également souhaiter que les trames temporelles dans les objets de graphique soient définies successivement du plus bas au plus haut (de gauche à droite). Cette possibilité n'a pas été mise en œuvre dans la version de l'indicateur décrite ci-dessus.

Vous pouvez trouver une vidéo démontrant la mise en œuvre de ces fonctionnalités dans la description de l'application prête à l'emploi - TF PANEL. Les fichiers de code source sont joints à l'article et sont disponibles en téléchargement.

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

Fichiers joints |
subwindow.mq5 (1.55 KB)
chartobjects.mq5 (39.85 KB)
Le MQL5 Cookbook : Commandes de la sous-fenêtre d'indicateur - Boutons Le MQL5 Cookbook : Commandes de la sous-fenêtre d'indicateur - Boutons
Dans cet article, nous examinerons un exemple de développement d'une interface utilisateur avec des commandes de bouton. Pour transmettre l'idée d'interactivité à l'utilisateur, les boutons changeront de couleur lorsque le curseur les survolera. Avec le curseur sur un bouton, la couleur du bouton sera légèrement assombrie, devenant nettement plus sombre lorsque le bouton est cliqué. De plus, nous ajouterons des info-bulles à chaque bouton, créant ainsi une interface intuitive.
Le MQL5 Cookbook : Notifications sonores pour les événements de trading MetaTrader 5 Le MQL5 Cookbook : Notifications sonores pour les événements de trading MetaTrader 5
Dans cet article, nous examinerons des problèmes tels que l'inclusion de fichiers sonores dans le fichier de l'Expert Advisor, et ainsi l'ajout de notifications sonores aux événements de trading. Le fait que les fichiers seront inclus signifie que les fichiers sonores seront situés à l'intérieur de l'Expert Advisor. Ainsi, lorsque vous donnez la version compilée de l'Expert Advisor (*.ex5) à un autre utilisateur, vous n'aurez pas à fournir également les fichiers sonores et à expliquer où ils doivent être sauvegardés.
Le MQL5 Cookbook : Commande de la sous-fenêtre d’indicateur - Barre de défilement Le MQL5 Cookbook : Commande de la sous-fenêtre d’indicateur - Barre de défilement
Continuons à explorer les différentes commandes et cette fois, tournons notre attention vers la barre de défilement. Tout comme dans l'article précédent intitulé "MQL5 Cookbook : Commande de la sous-fenêtre d’indicateur - Boutons", toutes les opérations seront effectuées dans la sous-fenêtre d'indicateur. Prenez un moment pour lire l'article mentionné ci-dessus car il fournit une description détaillée de l'utilisation des événements dans la fonction OnChartEvent(), alors que ce point ne sera abordé qu'avec désinvolture dans cet article. À des fins d'illustration, cette fois-ci, nous allons créer une barre de défilement verticale pour une grande liste de toutes les propriétés d'instruments financiers qui peuvent être obtenues à l'aide des ressources MQL5.
Le MQL5 Cookbook : Enregistrement des résultats d'optimisation d'un Expert Advisor sur la base de critères spécifiés Le MQL5 Cookbook : Enregistrement des résultats d'optimisation d'un Expert Advisor sur la base de critères spécifiés
Nous continuons la série d'articles sur la programmation MQL5. Cette fois, nous verrons comment obtenir les résultats de chaque passe d'optimisation lors de l'optimisation des paramètres de l'Expert Advisor. La mise en œuvre sera effectuée de manière à garantir que si les conditions spécifiées dans les paramètres externes sont remplies, les valeurs de passage correspondantes seront écrites dans un fichier. En plus des valeurs de test, nous enregistrerons également les paramètres qui ont conduit à de tels résultats.