English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
preview
Modèles prêts à l'emploi pour inclure des indicateurs dans les Expert Advisors (Partie 2) : Volume et indicateurs de Bill Williams

Modèles prêts à l'emploi pour inclure des indicateurs dans les Expert Advisors (Partie 2) : Volume et indicateurs de Bill Williams

MetaTrader 5Exemples |
662 2
Artyom Trishkin
Artyom Trishkin

Sommaire


Introduction

L'article poursuit le thème des modèles prêts à l'emploi pour l'utilisation d'indicateurs dans les EA. Nous verrons ici comment se connecter à des EA et comment utiliser les indicateurs de volume et de Bill Williams. Nous afficherons les données reçues des indicateurs sur le tableau de bord créé dans le premier article de cette série. Le panneau a également été amélioré. À la fin de l'article, nous examinerons brièvement ses changements et améliorations.

Pour chaque indicateur considéré, l'article présentera des modèles prêts à l'emploi à utiliser dans des programmes personnalisés :

  • Variables d'entrée et variables globales,
  • Initialisation des variables et création d'une poignée sur l’indicateur,
  • Dé-initialisation,
  • Réception des données de l'indicateur dans l'EA,
  • Exemple d'affichage des données obtenues sur le tableau de bord.
Cet article, comme les précédents et les suivants de cette série, n'a qu'une valeur de référence et présente des avantages pratiques, car il nous permet de simplement copier les codes de l'article.


Indicateurs de Volume

Les indicateurs de volume sont ceux qui rendent compte du volume. Sur le marché du Forex, le "volume" correspond au nombre de ticks (variations de prix) apparus dans l'intervalle de temps. Pour les titres boursiers, le volume est le volume des transactions exécutées (en contrats ou en termes monétaires).


Accumulation/Distribution

L’Accumulation Distribution (A/D) est déterminée par les changements de prix et de volume. Le volume agit comme un coefficient de pondération lors du changement de prix : plus le coefficient (le volume) est élevé, plus la contribution du changement de prix (pour cette période de temps) sera importante dans la valeur de l'indicateur.

En fait, cet indicateur est une version de l'indicateur On-Balance Volume plus couramment utilisé. Ils sont tous deux utilisés pour confirmer les changements de prix en mesurant le volume respectif des ventes.

Lorsque l'indicateur Accumulation/Distribution augmente, cela signifie qu'il y a accumulation (achat) d'un titre particulier, étant donné que la majeure partie du volume des ventes est liée à une tendance à la hausse des prix. Lorsque l'indicateur baisse, cela signifie que le titre est distribué (vendu), car la plupart des ventes ont lieu pendant le mouvement de baisse des prix.

Les divergences entre l'indicateur Accumulation/Distribution et le prix du titre indiquent les changements de prix à venir. En règle générale, dans le cas de telles divergences, la tendance du prix évolue dans la direction de l'indicateur. Donc, si l'indicateur augmente et que le prix du titre baisse, il faut s'attendre à un retournement du prix.



Paramètres

La fonction iAD() est utilisée pour créer le handle, ou poignée, sur l'indicateur :

Retourne la poignée de l'indicateur Accumulation/Distribution. Un seul buffer.

int  iAD(
   string               symbol,             // symbol name
   ENUM_TIMEFRAMES      period,             // period
   ENUM_APPLIED_VOLUME  applied_volume      // type of volume used for calculations
   );

symbol

[in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.

period

[in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.

applied_volume

[in] Volume utilisé. Une valeur de l’énumération ENUM_APPLIED_VOLUME.

Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, elle retourne INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.

Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :

//+------------------------------------------------------------------+
//|                                                 TestVolumeAD.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//--- enums
enum ENUM_LINE_STATE
  {
   LINE_STATE_NONE,        // Undefined state
   LINE_STATE_UP,          // Upward
   LINE_STATE_DOWN,        // Downward
   LINE_STATE_TURN_UP,     // Upward reversal
   LINE_STATE_TURN_DOWN,   // Downward reversal
   LINE_STATE_STOP_UP,     // Upward stop
   LINE_STATE_STOP_DOWN,   // Downward stop
   LINE_STATE_ABOVE,       // Above value
   LINE_STATE_UNDER,       // Below value
   LINE_STATE_CROSS_UP,    // Crossing value upwards
   LINE_STATE_CROSS_DOWN,  // Crossing value downwards
   LINE_STATE_TOUCH_BELOW, // Touching value from below 
   LINE_STATE_TOUCH_ABOVE, // Touch value from above
   LINE_STATE_EQUALS,      // Equal to value
  };
//--- input parameters
input ENUM_APPLIED_VOLUME  InpVolume   =  VOLUME_TICK;   /* Applied Volume */
//--- global variables
int      handle=INVALID_HANDLE;  // Indicator handle
int      ind_digits=0;           // Number of decimal places in the indicator values
string   ind_title;              // Indicator description

L'énumération ENUM_LINE_STATE a été créée pour simplifier l'obtention de l'état d'une ligne d'indicateur, sa forme et sa position par rapport à la ligne d'un autre indicateur ou d'un autre niveau.
Pour en savoir plus sur l'énumération dans les paramètres de l’ATR de l'article précédent.

Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier de classe du panneau :

//+------------------------------------------------------------------+
//|                                                 TestVolumeAD.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//--- includes
#include <Dashboard\Dashboard.mqh>
//--- enums
enum ENUM_LINE_STATE
  {
   LINE_STATE_NONE,        // Undefined state
   LINE_STATE_UP,          // Upward
   LINE_STATE_DOWN,        // Downward
   LINE_STATE_TURN_UP,     // Upward reversal
   LINE_STATE_TURN_DOWN,   // Downward reversal
   LINE_STATE_STOP_UP,     // Upward stop
   LINE_STATE_STOP_DOWN,   // Downward stop
   LINE_STATE_ABOVE,       // Above value
   LINE_STATE_UNDER,       // Below value
   LINE_STATE_CROSS_UP,    // Crossing value upwards
   LINE_STATE_CROSS_DOWN,  // Crossing value downwards
   LINE_STATE_TOUCH_BELOW, // Touching value from below 
   LINE_STATE_TOUCH_ABOVE, // Touch value from above
   LINE_STATE_EQUALS,      // Equal to value
  };
//--- input parameters
input ENUM_APPLIED_VOLUME  InpVolume   =  VOLUME_TICK;   /* Applied Volume */
//--- global variables
int      handle=INVALID_HANDLE;  // Indicator handle
int      ind_digits=0;           // Number of decimal places in the indicator values
string   ind_title;              // Indicator description
//--- variables for the panel
int      mouse_bar_index;        // Index of the bar the data is taken from
CDashboard *panel=NULL;          // Pointer to the panel object


Initialisation

Définition des valeurs des variables globales de l'indicateur et création de son handle :

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create timer
   EventSetTimer(60);

//--- Indicator
//--- Set the indicator name and the number of decimal places
   ind_title="A/D";
   ind_digits=0;
//--- Create indicator handle
   ResetLastError();
   handle=iAD(Symbol(),PERIOD_CURRENT,InpVolume);
   if(handle==INVALID_HANDLE)
     {
      PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError());
      return INIT_FAILED;
     }

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }

Si l'EA implique l'utilisation du tableau de bord, créez-le ici :

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create timer
   EventSetTimer(60);

//--- Indicator
//--- Set the indicator name and the number of decimal places
   ind_title="A/D";
   ind_digits=0;
//--- Create indicator handle
   ResetLastError();
   handle=iAD(Symbol(),PERIOD_CURRENT,InpVolume);
   if(handle==INVALID_HANDLE)
     {
      PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError());
      return INIT_FAILED;
     }

//--- Dashboard
//--- Create the panel
   panel=new CDashboard(1,20,20,199,225);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));
//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,97);

//--- Create a table with ID 1 to display indicator data in it
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,3,2,18,97);
   
//--- Display tabular data in the journal
   panel.GridPrint(0,2);
   panel.GridPrint(1,2);
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+


Dé-initialisation

Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- destroy timer
   EventKillTimer();
   
//--- Release handle of the indicator
   ResetLastError();
   if(!IndicatorRelease(handle))
      PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
//--- Clear all comments on the chart
   Comment("");
  }

L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- destroy timer
   EventKillTimer();
   
//--- Release handle of the indicator
   ResetLastError();
   if(!IndicatorRelease(handle))
      PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
//--- Clear all comments on the chart
   Comment("");
   
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
  }


Récupération des résultats

Les fonctions générales permettant d'obtenir des données à l'aide de la poignée de l'indicateur sont présentées ci-dessous. Les fonctions ont été passées en revue dans l'article sur la connexion des oscillateurs aux EA. Les fonctions présentées peuvent être utilisées "telles quelles" dans des programmes personnalisés :

//+------------------------------------------------------------------+
//| Return the indicator data on the specified bar                   |
//+------------------------------------------------------------------+
double IndicatorValue(const int ind_handle,const int index,const int buffer_num)
  {
   double array[1]={0};
   ResetLastError();
   if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1)
     {
      PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError());
      return EMPTY_VALUE;
     }
   return array[0];
  }
//+------------------------------------------------------------------+
//| Return the state of the indicator line                           |
//+------------------------------------------------------------------+
ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num)
  {
//--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index
   const double value0=IndicatorValue(ind_handle,index,  buffer_num);
   const double value1=IndicatorValue(ind_handle,index+1,buffer_num);
   const double value2=IndicatorValue(ind_handle,index+2,buffer_num);
//--- If at least one of the values could not be obtained, return an undefined value 
   if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE)
      return LINE_STATE_NONE;
//--- Line upward reversal (value2>value1 && value0>value1)
   if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0)
      return LINE_STATE_TURN_UP;
//--- Line upward direction (value2<=value1 && value0>value1)
   else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0)
      return LINE_STATE_UP;
//--- Line upward stop (value2<=value1 && value0==value1)
   else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0)
      return LINE_STATE_STOP_UP;
//--- Line downward reversal (value2<value1 && value0<value1)
   if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0)
      return LINE_STATE_TURN_DOWN;
//--- Line downward direction (value2>=value1 && value0<value1)
   else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0)
      return LINE_STATE_DOWN;
//--- Line downward stop (value2>=value1 && value0==value1)
   else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0)
      return LINE_STATE_STOP_DOWN;
//--- Undefined state
   return LINE_STATE_NONE;
  }
//+------------------------------------------------------------------+
//| Return the state of the line relative to the specified level     |
//+------------------------------------------------------------------+
ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE)
  {
//--- Get the values of the indicator line with the shift (0,1) relative to the passed index
   const double value0=IndicatorValue(ind_handle,index,  buffer_num);
   const double value1=IndicatorValue(ind_handle,index+1,buffer_num);
//--- If at least one of the values could not be obtained, return an undefined value 
   if(value0==EMPTY_VALUE || value1==EMPTY_VALUE)
      return LINE_STATE_NONE;
//--- Define the second level to compare
   double level=(level1==EMPTY_VALUE ? level0 : level1);
//--- The line is below the level (value1<level && value0<level0)
   if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0)
      return LINE_STATE_UNDER;
//--- The line is above the level (value1>level && value0>level0)
   if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0)
      return LINE_STATE_ABOVE;
//--- The line crossed the level upwards (value1<=level && value0>level0)
   if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0)
      return LINE_STATE_CROSS_UP;
//--- The line crossed the level downwards (value1>=level && value0<level0)
   if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0)
      return LINE_STATE_CROSS_DOWN;
//--- The line touched the level from below (value1<level0 && value0==level0)
   if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0)
      return LINE_STATE_TOUCH_BELOW;
//--- The line touched the level from above (value1>level0 && value0==level0)
   if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0)
      return LINE_STATE_TOUCH_BELOW;
//--- Line is equal to the level value (value1==level0 && value0==level0)
   if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0)
      return LINE_STATE_EQUALS;
//--- Undefined state
   return LINE_STATE_NONE;
  }
//+------------------------------------------------------------------+
//| Return the indicator line state description                      |
//+------------------------------------------------------------------+
string LineStateDescription(const ENUM_LINE_STATE state)
  {
   switch(state)
     {
      case LINE_STATE_UP         :  return "Up";
      case LINE_STATE_STOP_UP    :  return "Stop Up";
      case LINE_STATE_TURN_UP    :  return "Turn Up";
      case LINE_STATE_DOWN       :  return "Down";
      case LINE_STATE_STOP_DOWN  :  return "Stop Down";
      case LINE_STATE_TURN_DOWN  :  return "Turn Down";
      case LINE_STATE_ABOVE      :  return "Above level";
      case LINE_STATE_UNDER      :  return "Under level";
      case LINE_STATE_CROSS_UP   :  return "Crossing Up";
      case LINE_STATE_CROSS_DOWN :  return "Crossing Down";
      case LINE_STATE_TOUCH_BELOW:  return "Touch from Below";
      case LINE_STATE_TOUCH_ABOVE:  return "Touch from Above";
      case LINE_STATE_EQUALS     :  return "Equals";
      default                    :  return "Unknown";
     }
  }

Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :

//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlTick  tick={0};
   MqlRates rates[1];

//--- Exit if unable to get the current prices
   if(!SymbolInfoTick(Symbol(),tick))
      return;
//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Display the indicator data from the specified bar on the panel in table 1
   panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value=IndicatorValue(handle,index,0);
   string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : "");
   panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,90);
   
//--- Display a description of the indicator line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state=LineState(handle,index,0);
   panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,90);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }

De plus, lors de l'utilisation du tableau de bord, le gestionnaire d'événements du panneau est appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, et les événements pour recevoir l'indice de la barre sous le curseur y sont gérés :

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }

Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :


Vous pouvez consulter le test TestVolumeAD.mq5 EA dans les fichiers joints à l'article.


Money Flow Index

Le Money Flow Index (MFI) est l'indicateur technique qui indique le taux auquel l'argent est investi dans un titre et en est retiré. La construction et l'interprétation de l'indicateur sont similaires au Relative Force Index, à la seule différence que le volume est important pour le MFI.

Lors de l'analyse de l'indice des flux monétaires, il convient de prendre en considération les points suivants :

  • les divergences entre l'indicateur et l'évolution du prix. Si les prix augmentent alors que le MFI diminue (ou vice versa), la probabilité d'un retournement des prix est grande ;
  • La valeur du Money Flow Index, qui est supérieure à 80 ou inférieure à 20, signale en conséquence un pic ou un creux potentiel du marché.



    Paramètres

    La fonction iMFI() est utilisée pour créer la poignée de l'indicateur :

    int  iMFI(
       string               symbol,             // symbol name
       ENUM_TIMEFRAMES      period,             // period
       int                  ma_period,          // averaging period
       ENUM_APPLIED_VOLUME  applied_volume      // type of volume used for calculations
       );
    

    symbol

    [in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.

    period

    [in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.

    ma_period

    [in] Période (nombre de barres) pour le calcul de l'indicateur.

    applied_volume

    [in] Volume utilisé. Une valeur de l’énumération ENUM_APPLIED_VOLUME.

    Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, elle retourne INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.

    Déclarez les variables d'entrée et variables globales dans l'EA pour créer l'indicateur :

    //+------------------------------------------------------------------+
    //|                                                TestVolumeMFI.mq5 |
    //|                                  Copyright 2023, MetaQuotes Ltd. |
    //|                                             https://www.mql5.com |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2023, MetaQuotes Ltd."
    #property link      "https://www.mql5.com"
    #property version   "1.00"
    //--- enums
    enum ENUM_LINE_STATE
      {
       LINE_STATE_NONE,        // Undefined state
       LINE_STATE_UP,          // Upward
       LINE_STATE_DOWN,        // Downward
       LINE_STATE_TURN_UP,     // Upward reversal
       LINE_STATE_TURN_DOWN,   // Downward reversal
       LINE_STATE_STOP_UP,     // Upward stop
       LINE_STATE_STOP_DOWN,   // Downward stop
       LINE_STATE_ABOVE,       // Above value
       LINE_STATE_UNDER,       // Below value
       LINE_STATE_CROSS_UP,    // Crossing value upwards
       LINE_STATE_CROSS_DOWN,  // Crossing value downwards
       LINE_STATE_TOUCH_BELOW, // Touching value from below 
       LINE_STATE_TOUCH_ABOVE, // Touch value from above
       LINE_STATE_EQUALS,      // Equal to value
      };
    //--- input parameters
    input uint                 InpPeriod   =  14;            /* Period         */
    input ENUM_APPLIED_VOLUME  InpVolume   =  VOLUME_TICK;   /* Applied Volume */
    input double               InpOverbough=  80;            /* Overbough level*/
    input double               InpOversold =  20;            /* Oversold level */
    //--- global variables
    int      handle=INVALID_HANDLE;  // Indicator handle
    int      period=0;               // RSI calculation period
    int      ind_digits=0;           // Number of decimal places in the indicator values
    double   overbough=0;            // Overbought level
    double   oversold=0;             // Oversold level
    string   ind_title;              // Indicator description
    
    

    Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier des classes de tableaux de bord :

    //+------------------------------------------------------------------+
    //|                                                TestVolumeMFI.mq5 |
    //|                                  Copyright 2023, MetaQuotes Ltd. |
    //|                                             https://www.mql5.com |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2023, MetaQuotes Ltd."
    #property link      "https://www.mql5.com"
    #property version   "1.00"
    //--- includes
    #include <Dashboard\Dashboard.mqh>
    //--- enums
    enum ENUM_LINE_STATE
      {
       LINE_STATE_NONE,        // Undefined state
       LINE_STATE_UP,          // Upward
       LINE_STATE_DOWN,        // Downward
       LINE_STATE_TURN_UP,     // Upward reversal
       LINE_STATE_TURN_DOWN,   // Downward reversal
       LINE_STATE_STOP_UP,     // Upward stop
       LINE_STATE_STOP_DOWN,   // Downward stop
       LINE_STATE_ABOVE,       // Above value
       LINE_STATE_UNDER,       // Below value
       LINE_STATE_CROSS_UP,    // Crossing value upwards
       LINE_STATE_CROSS_DOWN,  // Crossing value downwards
       LINE_STATE_TOUCH_BELOW, // Touching value from below 
       LINE_STATE_TOUCH_ABOVE, // Touch value from above
       LINE_STATE_EQUALS,      // Equal to value
      };
    //--- input parameters
    input uint                 InpPeriod   =  14;            /* Period         */
    input ENUM_APPLIED_VOLUME  InpVolume   =  VOLUME_TICK;   /* Applied Volume */
    input double               InpOverbough=  80;            /* Overbough level*/
    input double               InpOversold =  20;            /* Oversold level */
    //--- global variables
    int      handle=INVALID_HANDLE;  // Indicator handle
    int      period=0;               // RSI calculation period
    int      ind_digits=0;           // Number of decimal places in the indicator values
    double   overbough=0;            // Overbought level
    double   oversold=0;             // Oversold level
    string   ind_title;              // Indicator description
    //--- variables for the panel
    int      mouse_bar_index;        // Index of the bar the data is taken from
    CDashboard *panel=NULL;          // Pointer to the panel object
    
    


    Initialisation

    Définition des valeurs des variables globales de l'indicateur et création de son handle :

    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
      {
    //--- create timer
       EventSetTimer(60);
    
    //--- Indicator
    //--- Set and adjust the calculation period and levels if necessary
       period=int(InpPeriod<1 ? 14 : InpPeriod);
       overbough=InpOverbough;
       oversold=(InpOversold>=overbough ? overbough-0.01 : InpOversold);
    //--- Set the indicator name and the number of decimal places
       ind_title=StringFormat("MFI(%lu)",period);
       ind_digits=Digits();
    //--- Create indicator handle
       ResetLastError();
       handle=iMFI(Symbol(),PERIOD_CURRENT,period,InpVolume);
       if(handle==INVALID_HANDLE)
         {
          PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError());
          return INIT_FAILED;
         }
    
    //--- Successful initialization
       return(INIT_SUCCEEDED);
      }
    
    

    Si l'EA implique l'utilisation du tableau de bord, créez-le ici :

    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
      {
    //--- create timer
       EventSetTimer(60);
    
    //--- Indicator
    //--- Set and adjust the calculation period and levels if necessary
       period=int(InpPeriod<1 ? 14 : InpPeriod);
       overbough=InpOverbough;
       oversold=(InpOversold>=overbough ? overbough-0.01 : InpOversold);
    //--- Set the indicator name and the number of decimal places
       ind_title=StringFormat("MFI(%lu)",period);
       ind_digits=Digits();
    //--- Create indicator handle
       ResetLastError();
       handle=iMFI(Symbol(),PERIOD_CURRENT,period,InpVolume);
       if(handle==INVALID_HANDLE)
         {
          PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError());
          return INIT_FAILED;
         }
    
    //--- Dashboard
    //--- Create the panel
       panel=new CDashboard(1,20,20,229,243);
       if(panel==NULL)
         {
          Print("Error. Failed to create panel object");
          return INIT_FAILED;
         }
    //--- Set font parameters
       panel.SetFontParams("Calibri",9);
    //--- Display the panel with the "Symbol, Timeframe description" header text
       panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));
    //--- Create a table with ID 0 to display bar data in it
       panel.CreateNewTable(0);
    //--- Draw a table with ID 0 on the panel background
       panel.DrawGrid(0,2,20,6,2,18,112);
    
    //--- Create a table with ID 1 to display indicator data in it
       panel.CreateNewTable(1);
    //--- Get the Y2 table coordinate with ID 0 and
    //--- set the Y1 coordinate for the table with ID 1
       int y1=panel.TableY2(0)+22;
    //--- Draw a table with ID 1 on the panel background
       panel.DrawGrid(1,2,y1,4,2,18,112);
       
    //--- Display tabular data in the journal
       panel.GridPrint(0,2);
       panel.GridPrint(1,2);
    //--- Initialize the variable with the index of the mouse cursor bar
       mouse_bar_index=0;
    //--- Display the data of the current bar on the panel
       DrawData(mouse_bar_index,TimeCurrent());
    
    //--- Successful initialization
       return(INIT_SUCCEEDED);
      }
    
    


    Dé-initialisation

    Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :

    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
      {
    //--- destroy timer
       EventKillTimer();
       
    //--- Release handle of the indicator
       ResetLastError();
       if(!IndicatorRelease(handle))
          PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
    //--- Clear all comments on the chart
       Comment("");
      }
    
    

    L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :

    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
      {
    //--- destroy timer
       EventKillTimer();
       
    //--- Release handle of the indicator
       ResetLastError();
       if(!IndicatorRelease(handle))
          PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
    //--- Clear all comments on the chart
       Comment("");
       
    //--- If the panel object exists, delete it
       if(panel!=NULL)
          delete panel;
      }
    


    Récupération des résultats

    Les fonctions générales permettant d'obtenir des données à l'aide de la poignée de l'indicateur sont présentées ci-dessous. Les fonctions ont été passées en revue dans l'article sur la connexion des oscillateurs aux EA. Les fonctions présentées peuvent être utilisées "telles quelles" dans des programmes personnalisés :

    //+------------------------------------------------------------------+
    //| Return the indicator data on the specified bar                   |
    //+------------------------------------------------------------------+
    double IndicatorValue(const int ind_handle,const int index,const int buffer_num)
      {
       double array[1]={0};
       ResetLastError();
       if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1)
         {
          PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError());
          return EMPTY_VALUE;
         }
       return array[0];
      }
    //+------------------------------------------------------------------+
    //| Return the state of the indicator line                           |
    //+------------------------------------------------------------------+
    ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num)
      {
    //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index
       const double value0=IndicatorValue(ind_handle,index,  buffer_num);
       const double value1=IndicatorValue(ind_handle,index+1,buffer_num);
       const double value2=IndicatorValue(ind_handle,index+2,buffer_num);
    //--- If at least one of the values could not be obtained, return an undefined value 
       if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE)
          return LINE_STATE_NONE;
    //--- Line upward reversal (value2>value1 && value0>value1)
       if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0)
          return LINE_STATE_TURN_UP;
    //--- Line upward direction (value2<=value1 && value0>value1)
       else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0)
          return LINE_STATE_UP;
    //--- Line upward stop (value2<=value1 && value0==value1)
       else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0)
          return LINE_STATE_STOP_UP;
    //--- Line downward reversal (value2<value1 && value0<value1)
       if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0)
          return LINE_STATE_TURN_DOWN;
    //--- Line downward direction (value2>=value1 && value0<value1)
       else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0)
          return LINE_STATE_DOWN;
    //--- Line downward stop (value2>=value1 && value0==value1)
       else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0)
          return LINE_STATE_STOP_DOWN;
    //--- Undefined state
       return LINE_STATE_NONE;
      }
    //+------------------------------------------------------------------+
    //| Return the state of the line relative to the specified level     |
    //+------------------------------------------------------------------+
    ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE)
      {
    //--- Get the values of the indicator line with the shift (0,1) relative to the passed index
       const double value0=IndicatorValue(ind_handle,index,  buffer_num);
       const double value1=IndicatorValue(ind_handle,index+1,buffer_num);
    //--- If at least one of the values could not be obtained, return an undefined value 
       if(value0==EMPTY_VALUE || value1==EMPTY_VALUE)
          return LINE_STATE_NONE;
    //--- Define the second level to compare
       double level=(level1==EMPTY_VALUE ? level0 : level1);
    //--- The line is below the level (value1<level && value0<level0)
       if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0)
          return LINE_STATE_UNDER;
    //--- The line is above the level (value1>level && value0>level0)
       if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0)
          return LINE_STATE_ABOVE;
    //--- The line crossed the level upwards (value1<=level && value0>level0)
       if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0)
          return LINE_STATE_CROSS_UP;
    //--- The line crossed the level downwards (value1>=level && value0<level0)
       if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0)
          return LINE_STATE_CROSS_DOWN;
    //--- The line touched the level from below (value1<level0 && value0==level0)
       if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0)
          return LINE_STATE_TOUCH_BELOW;
    //--- The line touched the level from above (value1>level0 && value0==level0)
       if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0)
          return LINE_STATE_TOUCH_BELOW;
    //--- Line is equal to the level value (value1==level0 && value0==level0)
       if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0)
          return LINE_STATE_EQUALS;
    //--- Undefined state
       return LINE_STATE_NONE;
      }
    //+------------------------------------------------------------------+
    //| Return the indicator line state description                      |
    //+------------------------------------------------------------------+
    string LineStateDescription(const ENUM_LINE_STATE state)
      {
       switch(state)
         {
          case LINE_STATE_UP         :  return "Up";
          case LINE_STATE_STOP_UP    :  return "Stop Up";
          case LINE_STATE_TURN_UP    :  return "Turn Up";
          case LINE_STATE_DOWN       :  return "Down";
          case LINE_STATE_STOP_DOWN  :  return "Stop Down";
          case LINE_STATE_TURN_DOWN  :  return "Turn Down";
          case LINE_STATE_ABOVE      :  return "Above level";
          case LINE_STATE_UNDER      :  return "Under level";
          case LINE_STATE_CROSS_UP   :  return "Crossing Up";
          case LINE_STATE_CROSS_DOWN :  return "Crossing Down";
          case LINE_STATE_TOUCH_BELOW:  return "Touch from Below";
          case LINE_STATE_TOUCH_ABOVE:  return "Touch from Above";
          case LINE_STATE_EQUALS     :  return "Equals";
          default                    :  return "Unknown";
         }
      }
    
    

    Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :

    //+------------------------------------------------------------------+
    //| Display data from the specified timeseries index to the panel    |
    //+------------------------------------------------------------------+
    void DrawData(const int index,const datetime time)
      {
    //--- Declare the variables to receive data in them
       MqlTick  tick={0};
       MqlRates rates[1];
    
    //--- Exit if unable to get the current prices
       if(!SymbolInfoTick(Symbol(),tick))
          return;
    //--- Exit if unable to get the bar data by the specified index
       if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
          return;
    
    //--- Set font parameters for bar and indicator data headers
       int  size=0;
       uint flags=0;
       uint angle=0;
       string name=panel.FontParams(size,flags,angle);
       panel.SetFontParams(name,9,FW_BOLD);
       panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
       panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
    //--- Set font parameters for bar and indicator data
       panel.SetFontParams(name,9);
    
    //--- Display the data of the specified bar in table 0 on the panel
       panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
       panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
       panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
       panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
       panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
       panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);
    
    //--- Display the indicator data from the specified bar on the panel in table 1
       panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
       double value=IndicatorValue(handle,index,0);
       string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : "");
       panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,100);
       
    //--- Display a description of the indicator line state relative to the overbought level
       string ovb=StringFormat("%+.2f",overbough);
       panel.DrawText("Overbough", panel.CellX(1,2,0)+2, panel.CellY(1,2,0)+2);
       panel.DrawText(ovb, panel.CellX(1,2,0)+66, panel.CellY(1,2,0)+2);
       ENUM_LINE_STATE state_ovb=LineStateRelative(handle,index,0,overbough);
    //--- The label color changes depending on the value of the line relative to the level
       color clr=(state_ovb==LINE_STATE_CROSS_DOWN ? clrRed : clrNONE);
       string ovb_str=(state_ovb==LINE_STATE_ABOVE ? "Inside the area" : LineStateDescription(state_ovb));
       panel.DrawText(ovb_str,panel.CellX(1,2,1)+2,panel.CellY(1,2,1)+2,clr,100);
       
    //--- Display a description of the indicator line state relative to the oversold level
       panel.DrawText("Oversold", panel.CellX(1,3,0)+2, panel.CellY(1,3,0)+2);
       string ovs=StringFormat("%+.2f",oversold);
       panel.DrawText(ovs, panel.CellX(1,3,0)+68, panel.CellY(1,3,0)+2);
       ENUM_LINE_STATE state_ovs=LineStateRelative(handle,index,0,oversold);
    //--- The label color changes depending on the value of the line relative to the level
       clr=(state_ovs==LINE_STATE_CROSS_UP ? clrBlue : clrNONE);
       string ovs_str=(state_ovs==LINE_STATE_UNDER ? "Inside the area" : LineStateDescription(state_ovs));
       panel.DrawText(ovs_str,panel.CellX(1,3,1)+2,panel.CellY(1,3,1)+2,clr,100);
       
    //--- Display a description of the indicator line state
       panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
       ENUM_LINE_STATE state=LineState(handle,index,0);
    //--- The label color changes depending on the location of the line in the overbought/oversold areas
       clr=(state_ovb==LINE_STATE_ABOVE || state_ovb==LINE_STATE_CROSS_DOWN ? clrRed : state_ovs==LINE_STATE_UNDER || state_ovs==LINE_STATE_CROSS_UP ? clrBlue : clrNONE);
       panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clr,100);
       
    //--- Redraw the chart to immediately display all changes on the panel
       ChartRedraw(ChartID());
      }
    
    

    L'emplacement de la ligne de l'indicateur dans les zones de sur-achat/sur-vente est indiqué sur le panneau par une couleur de texte.

    De plus, lors de l'utilisation du tableau de bord, le gestionnaire d'événements du panneau est appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, et les événements pour recevoir l'indice de la barre sous le curseur y sont gérés :

    //+------------------------------------------------------------------+
    //| ChartEvent function                                              |
    //+------------------------------------------------------------------+
    void OnChartEvent(const int id,
                      const long &lparam,
                      const double &dparam,
                      const string &sparam)
      {
    //--- Handling the panel
    //--- Call the panel event handler
       panel.OnChartEvent(id,lparam,dparam,sparam);
    
    //--- If the cursor moves or a click is made on the chart
       if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
         {
          //--- Declare the variables to record time and price coordinates in them
          datetime time=0;
          double price=0;
          int wnd=0;
          //--- If the cursor coordinates are converted to date and time
          if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
            {
             //--- write the bar index where the cursor is located to a global variable
             mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
             //--- Display the bar data under the cursor on the panel 
             DrawData(mouse_bar_index,time);
            }
         }
    
    //--- If we received a custom event, display the appropriate message in the journal
       if(id>CHARTEVENT_CUSTOM)
         {
          //--- Here we can implement handling a click on the close button on the panel
          PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
         }
      }
    
    

    Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :


    Vous pouvez consulter le test TestVolumeMFI.mq5 EA dans les fichiers joints à l'article.


    On Balance Volume

    L’On Balance Volume (OBV) est un indicateur technique du momentum qui relie le volume à la variation du prix. L'indicateur, imaginé par Joseph Granville, est assez simple. Si le prix de clôture de la barre actuelle est supérieur à celui de la barre précédente, le volume de la barre actuelle est ajouté à l'OBV précédent. Si le prix de clôture de la barre actuelle est inférieur à celui de la barre précédente, le volume actuel est soustrait de l'OBV précédent.

    L'hypothèse de base, en ce qui concerne l'analyse de l’On Balance Volume, est que les changements de l’OBV précèdent les changements de prix. La théorie est que l'argent intelligent peut être vu comme affluant vers le titre par un OBV en hausse. Lorsque le public s'engage dans la sécurité, la sécurité et le volume en équilibre progressent.

    Si l'évolution du cours du titre précède celle de l'OBV, il y a "non-confirmation". Les non-confirmations peuvent se produire sur des sommets de marchés haussiers (lorsque le titre augmente sans, ou avant, l'OBV) ou sur des creux de marchés baissiers (lorsque le titre chute sans, ou avant, l'indicateur technique On Balance Volume).

    L'OBV est dans une tendance haussière lorsque chaque nouveau sommet est plus élevé que le précédent et que chaque nouveau creux est plus élevé que le précédent. De la même façon, l’On Balance Volume suit une tendance à la baisse lorsque chaque pic successif est inférieur au pic précédent et que chaque creux successif est inférieur au creux précédent. Lorsque l'OBV évolue de façon latérale et n'enregistre pas de hauts et de bas successifs, il s'agit d'une tendance douteuse.

    Une fois qu'une tendance est établie, elle reste en vigueur jusqu'à ce qu'elle soit brisée. Il y a deux façons d’identifier la fin de la tendance de l’On Balance Volume. La première se produit lorsque la tendance passe d'une tendance à la hausse à une tendance à la baisse, ou d'une tendance à la baisse à une tendance à la hausse.

    La deuxième façon dont la tendance de l’OBV peut être cassée est si la tendance se transforme en tendance douteuse et reste douteuse pendant plus de 3 jours. Ainsi, si le titre passe d'une tendance haussière à une tendance douteuse et ne reste douteux que pendant 2 jours avant de repasser à une tendance haussière, on considère que l’On Balance Volume a toujours été dans une tendance haussière.Lorsque l'OBV passe à une tendance haussière ou baissière, un "breakout", ou cassure, s'est produit.

    Comme les ruptures de l’OBV précèdent normalement les ruptures de prix, les investisseurs devraient acheter des positions longues sur les ruptures à la hausse de l'On Balance Volume. De façon similaire, les investisseurs devraient vendre à découvert lorsque l'OBV casse à la baisse. Les positions doivent être maintenues jusqu'à ce que la tendance change.



    Paramètres

    La fonction iOBV() est utilisée pour créer le handle de l'indicateur :

    Retourne le handle de l'indicateur On Balance Volume. Un seul buffer.

    int  iOBV(
       string                symbol,             // symbol name
       ENUM_TIMEFRAMES       period,             // period
       ENUM_APPLIED_VOLUME   applied_volume      // type of volume used for calculations
       );
    
    symbol

    [in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.

    period

    [in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.

    applied_volume

    [in] Volume utilisé. Toute valeur de l'énumération ENUM_APPLIED_VOLUME.

    Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, elle retourne INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.

    Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :

    //+------------------------------------------------------------------+
    //|                                                TestVolumeOBV.mq5 |
    //|                                  Copyright 2023, MetaQuotes Ltd. |
    //|                                             https://www.mql5.com |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2023, MetaQuotes Ltd."
    #property link      "https://www.mql5.com"
    #property version   "1.00"
    //--- enums
    enum ENUM_LINE_STATE
      {
       LINE_STATE_NONE,        // Undefined state
       LINE_STATE_UP,          // Upward
       LINE_STATE_DOWN,        // Downward
       LINE_STATE_TURN_UP,     // Upward reversal
       LINE_STATE_TURN_DOWN,   // Downward reversal
       LINE_STATE_STOP_UP,     // Upward stop
       LINE_STATE_STOP_DOWN,   // Downward stop
       LINE_STATE_ABOVE,       // Above value
       LINE_STATE_UNDER,       // Below value
       LINE_STATE_CROSS_UP,    // Crossing value upwards
       LINE_STATE_CROSS_DOWN,  // Crossing value downwards
       LINE_STATE_TOUCH_BELOW, // Touching value from below 
       LINE_STATE_TOUCH_ABOVE, // Touch value from above
       LINE_STATE_EQUALS,      // Equal to value
      };
    //--- input parameters
    input ENUM_APPLIED_VOLUME  InpVolume   =  VOLUME_TICK;   /* Applied Volume */
    //--- global variables
    int      handle=INVALID_HANDLE;  // Indicator handle
    int      ind_digits=0;           // Number of decimal places in the indicator values
    string   ind_title;              // Indicator description
    
    

    Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier des classes de tableaux de bord :

    //+------------------------------------------------------------------+
    //|                                                TestVolumeOBV.mq5 |
    //|                                  Copyright 2023, MetaQuotes Ltd. |
    //|                                             https://www.mql5.com |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2023, MetaQuotes Ltd."
    #property link      "https://www.mql5.com"
    #property version   "1.00"
    //--- includes
    #include <Dashboard\Dashboard.mqh>
    //--- enums
    enum ENUM_LINE_STATE
      {
       LINE_STATE_NONE,        // Undefined state
       LINE_STATE_UP,          // Upward
       LINE_STATE_DOWN,        // Downward
       LINE_STATE_TURN_UP,     // Upward reversal
       LINE_STATE_TURN_DOWN,   // Downward reversal
       LINE_STATE_STOP_UP,     // Upward stop
       LINE_STATE_STOP_DOWN,   // Downward stop
       LINE_STATE_ABOVE,       // Above value
       LINE_STATE_UNDER,       // Below value
       LINE_STATE_CROSS_UP,    // Crossing value upwards
       LINE_STATE_CROSS_DOWN,  // Crossing value downwards
       LINE_STATE_TOUCH_BELOW, // Touching value from below 
       LINE_STATE_TOUCH_ABOVE, // Touch value from above
       LINE_STATE_EQUALS,      // Equal to value
      };
    //--- input parameters
    input ENUM_APPLIED_VOLUME  InpVolume   =  VOLUME_TICK;   /* Applied Volume */
    //--- global variables
    int      handle=INVALID_HANDLE;  // Indicator handle
    int      ind_digits=0;           // Number of decimal places in the indicator values
    string   ind_title;              // Indicator description
    //--- variables for the panel
    int      mouse_bar_index;        // Index of the bar the data is taken from
    CDashboard *panel=NULL;          // Pointer to the panel object
    
    


    Initialisation

    Définition des valeurs des variables globales de l'indicateur et création de son handle :

    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
      {
    //--- create timer
       EventSetTimer(60);
    
    //--- Indicator
    //--- Set the indicator name and the number of decimal places
       ind_title="OBV";
       ind_digits=0;
    //--- Create indicator handle
       ResetLastError();
       handle=iOBV(Symbol(),PERIOD_CURRENT,InpVolume);
       if(handle==INVALID_HANDLE)
         {
          PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError());
          return INIT_FAILED;
         }
    
    //--- Successful initialization
       return(INIT_SUCCEEDED);
      }
    
    

    Si l'EA implique l'utilisation du tableau de bord, créez-le ici :

    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
      {
    //--- create timer
       EventSetTimer(60);
    
    //--- Indicator
    //--- Set the indicator name and the number of decimal places
       ind_title="OBV";
       ind_digits=0;
    //--- Create indicator handle
       ResetLastError();
       handle=iOBV(Symbol(),PERIOD_CURRENT,InpVolume);
       if(handle==INVALID_HANDLE)
         {
          PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError());
          return INIT_FAILED;
         }
    
    //--- Dashboard
    //--- Create the panel
       panel=new CDashboard(1,20,20,199,225);
       if(panel==NULL)
         {
          Print("Error. Failed to create panel object");
          return INIT_FAILED;
         }
    //--- Set font parameters
       panel.SetFontParams("Calibri",9);
    //--- Display the panel with the "Symbol, Timeframe description" header text
       panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));
    //--- Create a table with ID 0 to display bar data in it
       panel.CreateNewTable(0);
    //--- Draw a table with ID 0 on the panel background
       panel.DrawGrid(0,2,20,6,2,18,97);
    
    //--- Create a table with ID 1 to display indicator data in it
       panel.CreateNewTable(1);
    //--- Get the Y2 table coordinate with ID 0 and
    //--- set the Y1 coordinate for the table with ID 1
       int y1=panel.TableY2(0)+22;
    //--- Draw a table with ID 1 on the panel background
       panel.DrawGrid(1,2,y1,3,2,18,97);
       
    //--- Display tabular data in the journal
       panel.GridPrint(0,2);
       panel.GridPrint(1,2);
    //--- Initialize the variable with the index of the mouse cursor bar
       mouse_bar_index=0;
    //--- Display the data of the current bar on the panel
       DrawData(mouse_bar_index,TimeCurrent());
    
    //--- Successful initialization
       return(INIT_SUCCEEDED);
      }
    
    


    Dé-initialisation

    Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :

    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
      {
    //--- destroy timer
       EventKillTimer();
       
    //--- Release handle of the indicator
       ResetLastError();
       if(!IndicatorRelease(handle))
          PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
    //--- Clear all comments on the chart
       Comment("");
      }
    
    

    L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :

    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
      {
    //--- destroy timer
       EventKillTimer();
       
    //--- Release handle of the indicator
       ResetLastError();
       if(!IndicatorRelease(handle))
          PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
    //--- Clear all comments on the chart
       Comment("");
       
    //--- If the panel object exists, delete it
       if(panel!=NULL)
          delete panel;
      }
    


    Récupération des résultats

    Les fonctions générales permettant d'obtenir des données à l'aide de la poignée de l'indicateur sont présentées ci-dessous. Les fonctions ont été passées en revue dans l'article sur la connexion des oscillateurs aux EA. Les fonctions présentées peuvent être utilisées "telles quelles" dans des programmes personnalisés :

    //+------------------------------------------------------------------+
    //| Return the indicator data on the specified bar                   |
    //+------------------------------------------------------------------+
    double IndicatorValue(const int ind_handle,const int index,const int buffer_num)
      {
       double array[1]={0};
       ResetLastError();
       if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1)
         {
          PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError());
          return EMPTY_VALUE;
         }
       return array[0];
      }
    //+------------------------------------------------------------------+
    //| Return the state of the indicator line                           |
    //+------------------------------------------------------------------+
    ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num)
      {
    //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index
       const double value0=IndicatorValue(ind_handle,index,  buffer_num);
       const double value1=IndicatorValue(ind_handle,index+1,buffer_num);
       const double value2=IndicatorValue(ind_handle,index+2,buffer_num);
    //--- If at least one of the values could not be obtained, return an undefined value 
       if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE)
          return LINE_STATE_NONE;
    //--- Line upward reversal (value2>value1 && value0>value1)
       if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0)
          return LINE_STATE_TURN_UP;
    //--- Line upward direction (value2<=value1 && value0>value1)
       else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0)
          return LINE_STATE_UP;
    //--- Line upward stop (value2<=value1 && value0==value1)
       else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0)
          return LINE_STATE_STOP_UP;
    //--- Line downward reversal (value2<value1 && value0<value1)
       if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0)
          return LINE_STATE_TURN_DOWN;
    //--- Line downward direction (value2>=value1 && value0<value1)
       else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0)
          return LINE_STATE_DOWN;
    //--- Line downward stop (value2>=value1 && value0==value1)
       else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0)
          return LINE_STATE_STOP_DOWN;
    //--- Undefined state
       return LINE_STATE_NONE;
      }
    //+------------------------------------------------------------------+
    //| Return the state of the line relative to the specified level     |
    //+------------------------------------------------------------------+
    ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE)
      {
    //--- Get the values of the indicator line with the shift (0,1) relative to the passed index
       const double value0=IndicatorValue(ind_handle,index,  buffer_num);
       const double value1=IndicatorValue(ind_handle,index+1,buffer_num);
    //--- If at least one of the values could not be obtained, return an undefined value 
       if(value0==EMPTY_VALUE || value1==EMPTY_VALUE)
          return LINE_STATE_NONE;
    //--- Define the second level to compare
       double level=(level1==EMPTY_VALUE ? level0 : level1);
    //--- The line is below the level (value1<level && value0<level0)
       if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0)
          return LINE_STATE_UNDER;
    //--- The line is above the level (value1>level && value0>level0)
       if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0)
          return LINE_STATE_ABOVE;
    //--- The line crossed the level upwards (value1<=level && value0>level0)
       if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0)
          return LINE_STATE_CROSS_UP;
    //--- The line crossed the level downwards (value1>=level && value0<level0)
       if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0)
          return LINE_STATE_CROSS_DOWN;
    //--- The line touched the level from below (value1<level0 && value0==level0)
       if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0)
          return LINE_STATE_TOUCH_BELOW;
    //--- The line touched the level from above (value1>level0 && value0==level0)
       if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0)
          return LINE_STATE_TOUCH_BELOW;
    //--- Line is equal to the level value (value1==level0 && value0==level0)
       if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0)
          return LINE_STATE_EQUALS;
    //--- Undefined state
       return LINE_STATE_NONE;
      }
    //+------------------------------------------------------------------+
    //| Return the indicator line state description                      |
    //+------------------------------------------------------------------+
    string LineStateDescription(const ENUM_LINE_STATE state)
      {
       switch(state)
         {
          case LINE_STATE_UP         :  return "Up";
          case LINE_STATE_STOP_UP    :  return "Stop Up";
          case LINE_STATE_TURN_UP    :  return "Turn Up";
          case LINE_STATE_DOWN       :  return "Down";
          case LINE_STATE_STOP_DOWN  :  return "Stop Down";
          case LINE_STATE_TURN_DOWN  :  return "Turn Down";
          case LINE_STATE_ABOVE      :  return "Above level";
          case LINE_STATE_UNDER      :  return "Under level";
          case LINE_STATE_CROSS_UP   :  return "Crossing Up";
          case LINE_STATE_CROSS_DOWN :  return "Crossing Down";
          case LINE_STATE_TOUCH_BELOW:  return "Touch from Below";
          case LINE_STATE_TOUCH_ABOVE:  return "Touch from Above";
          case LINE_STATE_EQUALS     :  return "Equals";
          default                    :  return "Unknown";
         }
      }
    
    

    Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :

    //+------------------------------------------------------------------+
    //| Display data from the specified timeseries index to the panel    |
    //+------------------------------------------------------------------+
    void DrawData(const int index,const datetime time)
      {
    //--- Declare the variables to receive data in them
       MqlTick  tick={0};
       MqlRates rates[1];
    
    //--- Exit if unable to get the current prices
       if(!SymbolInfoTick(Symbol(),tick))
          return;
    //--- Exit if unable to get the bar data by the specified index
       if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
          return;
    
    //--- Set font parameters for bar and indicator data headers
       int  size=0;
       uint flags=0;
       uint angle=0;
       string name=panel.FontParams(size,flags,angle);
       panel.SetFontParams(name,9,FW_BOLD);
       panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
       panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
    //--- Set font parameters for bar and indicator data
       panel.SetFontParams(name,9);
    
    //--- Display the data of the specified bar in table 0 on the panel
       panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
       panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
       panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
       panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
       panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
       panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);
    
    //--- Display the indicator data from the specified bar on the panel in table 1
       panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
       double value=IndicatorValue(handle,index,0);
       string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : "");
       panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,90);
       
    //--- Display a description of the indicator line state
       panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
       ENUM_LINE_STATE state=LineState(handle,index,0);
       panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,90);
       
    //--- Redraw the chart to immediately display all changes on the panel
       ChartRedraw(ChartID());
      }
    
    

    De plus, lors de l'utilisation du tableau de bord, le gestionnaire d'événements du panneau est appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, et les événements pour recevoir l'indice de la barre sous le curseur y sont gérés :

    //+------------------------------------------------------------------+
    //| ChartEvent function                                              |
    //+------------------------------------------------------------------+
    void OnChartEvent(const int id,
                      const long &lparam,
                      const double &dparam,
                      const string &sparam)
      {
    //--- Handling the panel
    //--- Call the panel event handler
       panel.OnChartEvent(id,lparam,dparam,sparam);
    
    //--- If the cursor moves or a click is made on the chart
       if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
         {
          //--- Declare the variables to record time and price coordinates in them
          datetime time=0;
          double price=0;
          int wnd=0;
          //--- If the cursor coordinates are converted to date and time
          if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
            {
             //--- write the bar index where the cursor is located to a global variable
             mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
             //--- Display the bar data under the cursor on the panel 
             DrawData(mouse_bar_index,time);
            }
         }
    
    //--- If we received a custom event, display the appropriate message in the journal
       if(id>CHARTEVENT_CUSTOM)
         {
          //--- Here we can implement handling a click on the close button on the panel
          PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
         }
      }
    
    

    Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :


    Vous pouvez consulter le test TestVolumeOBV.mq5 EA dans les fichiers joints à l'article.


    Volumes

    Pour le marché du Forex, l'indicateur Volumes est l'indicateur du nombre de changements de prix sur chaque barre d’une période sélectionnée. Pour les symboles boursiers, il s'agit d'un indicateur des volumes réellement échangés (contrats, argent, unités, etc.).



    Paramètres

    La fonction iVolumes() est utilisée pour créer la poignée de l'indicateur :

    Retourne le handle de l'indicateur décrivant les volumes. Un seul buffer.

    int  iVolumes(
       string               symbol,             // symbol name
       ENUM_TIMEFRAMES      period,             // period
       ENUM_APPLIED_VOLUME  applied_volume      // volume type
       )
    

    symbol

    [in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.

    period

    [in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.

    applied_volume

    [in] Volume utilisé. Toute valeur de l'énumération ENUM_APPLIED_VOLUME.

    Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, elle retourne INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.

    Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :

    //+------------------------------------------------------------------+
    //|                                                TestVolumeOBV.mq5 |
    //|                                  Copyright 2023, MetaQuotes Ltd. |
    //|                                             https://www.mql5.com |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2023, MetaQuotes Ltd."
    #property link      "https://www.mql5.com"
    #property version   "1.00"
    //--- enums
    enum ENUM_LINE_STATE
      {
       LINE_STATE_NONE,        // Undefined state
       LINE_STATE_UP,          // Upward
       LINE_STATE_DOWN,        // Downward
       LINE_STATE_TURN_UP,     // Upward reversal
       LINE_STATE_TURN_DOWN,   // Downward reversal
       LINE_STATE_STOP_UP,     // Upward stop
       LINE_STATE_STOP_DOWN,   // Downward stop
       LINE_STATE_ABOVE,       // Above value
       LINE_STATE_UNDER,       // Below value
       LINE_STATE_CROSS_UP,    // Crossing value upwards
       LINE_STATE_CROSS_DOWN,  // Crossing value downwards
       LINE_STATE_TOUCH_BELOW, // Touching value from below 
       LINE_STATE_TOUCH_ABOVE, // Touch value from above
       LINE_STATE_EQUALS,      // Equal to value
      };
    //--- input parameters
    input ENUM_APPLIED_VOLUME  InpVolume   =  VOLUME_TICK;   /* Applied Volume */
    //--- global variables
    int      handle=INVALID_HANDLE;  // Indicator handle
    int      ind_digits=0;           // Number of decimal places in the indicator values
    string   ind_title;              // Indicator description
    
    

    Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier des classes de tableaux de bord :

    //+------------------------------------------------------------------+
    //|                                                TestVolumeOBV.mq5 |
    //|                                  Copyright 2023, MetaQuotes Ltd. |
    //|                                             https://www.mql5.com |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2023, MetaQuotes Ltd."
    #property link      "https://www.mql5.com"
    #property version   "1.00"
    //--- includes
    #include <Dashboard\Dashboard.mqh>
    //--- enums
    enum ENUM_LINE_STATE
      {
       LINE_STATE_NONE,        // Undefined state
       LINE_STATE_UP,          // Upward
       LINE_STATE_DOWN,        // Downward
       LINE_STATE_TURN_UP,     // Upward reversal
       LINE_STATE_TURN_DOWN,   // Downward reversal
       LINE_STATE_STOP_UP,     // Upward stop
       LINE_STATE_STOP_DOWN,   // Downward stop
       LINE_STATE_ABOVE,       // Above value
       LINE_STATE_UNDER,       // Below value
       LINE_STATE_CROSS_UP,    // Crossing value upwards
       LINE_STATE_CROSS_DOWN,  // Crossing value downwards
       LINE_STATE_TOUCH_BELOW, // Touching value from below 
       LINE_STATE_TOUCH_ABOVE, // Touch value from above
       LINE_STATE_EQUALS,      // Equal to value
      };
    //--- input parameters
    input ENUM_APPLIED_VOLUME  InpVolume   =  VOLUME_TICK;   /* Applied Volume */
    //--- global variables
    int      handle=INVALID_HANDLE;  // Indicator handle
    int      ind_digits=0;           // Number of decimal places in the indicator values
    string   ind_title;              // Indicator description
    //--- variables for the panel
    int      mouse_bar_index;        // Index of the bar the data is taken from
    CDashboard *panel=NULL;          // Pointer to the panel object
    
    


    Initialisation

    Définition des valeurs des variables globales de l'indicateur et création de son handle :

    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
      {
    //--- create timer
       EventSetTimer(60);
    
    //--- Indicator
    //--- Set the indicator name and the number of decimal places
       ind_title="Volumes";
       ind_digits=0;
    //--- Create indicator handle
       ResetLastError();
       handle=iVolumes(Symbol(),PERIOD_CURRENT,InpVolume);
       if(handle==INVALID_HANDLE)
         {
          PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError());
          return INIT_FAILED;
         }
    
    //--- Successful initialization
       return(INIT_SUCCEEDED);
      }
    
    

    Si l'EA implique l'utilisation du tableau de bord, créez-le ici :

    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
      {
    //--- create timer
       EventSetTimer(60);
    
    //--- Indicator
    //--- Set the indicator name and the number of decimal places
       ind_title="Volumes";
       ind_digits=0;
    //--- Create indicator handle
       ResetLastError();
       handle=iVolumes(Symbol(),PERIOD_CURRENT,InpVolume);
       if(handle==INVALID_HANDLE)
         {
          PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError());
          return INIT_FAILED;
         }
    
    //--- Dashboard
    //--- Create the panel
       panel=new CDashboard(1,20,20,199,225);
       if(panel==NULL)
         {
          Print("Error. Failed to create panel object");
          return INIT_FAILED;
         }
    //--- Set font parameters
       panel.SetFontParams("Calibri",9);
    //--- Display the panel with the "Symbol, Timeframe description" header text
       panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));
    //--- Create a table with ID 0 to display bar data in it
       panel.CreateNewTable(0);
    //--- Draw a table with ID 0 on the panel background
       panel.DrawGrid(0,2,20,6,2,18,97);
    
    //--- Create a table with ID 1 to display indicator data in it
       panel.CreateNewTable(1);
    //--- Get the Y2 table coordinate with ID 0 and
    //--- set the Y1 coordinate for the table with ID 1
       int y1=panel.TableY2(0)+22;
    //--- Draw a table with ID 1 on the panel background
       panel.DrawGrid(1,2,y1,3,2,18,97);
       
    //--- Display tabular data in the journal
       panel.GridPrint(0,2);
       panel.GridPrint(1,2);
    //--- Initialize the variable with the index of the mouse cursor bar
       mouse_bar_index=0;
    //--- Display the data of the current bar on the panel
       DrawData(mouse_bar_index,TimeCurrent());
    
    //--- Successful initialization
       return(INIT_SUCCEEDED);
      }
    
    


    Dé-initialisation

    Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :

    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
      {
    //--- destroy timer
       EventKillTimer();
       
    //--- Release handle of the indicator
       ResetLastError();
       if(!IndicatorRelease(handle))
          PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
    //--- Clear all comments on the chart
       Comment("");
      }
    
    

    L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :

    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
      {
    //--- destroy timer
       EventKillTimer();
       
    //--- Release handle of the indicator
       ResetLastError();
       if(!IndicatorRelease(handle))
          PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
    //--- Clear all comments on the chart
       Comment("");
       
    //--- If the panel object exists, delete it
       if(panel!=NULL)
          delete panel;
      }
    


    Récupération des résultats

    Les fonctions générales permettant d'obtenir des données à l'aide de la poignée de l'indicateur sont présentées ci-dessous. Les fonctions ont été passées en revue dans l'article sur la connexion des oscillateurs aux EA. Les fonctions présentées peuvent être utilisées "telles quelles" dans des programmes personnalisés :

    //+------------------------------------------------------------------+
    //| Return the indicator data on the specified bar                   |
    //+------------------------------------------------------------------+
    double IndicatorValue(const int ind_handle,const int index,const int buffer_num)
      {
       double array[1]={0};
       ResetLastError();
       if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1)
         {
          PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError());
          return EMPTY_VALUE;
         }
       return array[0];
      }
    //+------------------------------------------------------------------+
    //| Return the state of the indicator line                           |
    //+------------------------------------------------------------------+
    ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num)
      {
    //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index
       const double value0=IndicatorValue(ind_handle,index,  buffer_num);
       const double value1=IndicatorValue(ind_handle,index+1,buffer_num);
       const double value2=IndicatorValue(ind_handle,index+2,buffer_num);
    //--- If at least one of the values could not be obtained, return an undefined value 
       if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE)
          return LINE_STATE_NONE;
    //--- Line upward reversal (value2>value1 && value0>value1)
       if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0)
          return LINE_STATE_TURN_UP;
    //--- Line upward direction (value2<=value1 && value0>value1)
       else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0)
          return LINE_STATE_UP;
    //--- Line upward stop (value2<=value1 && value0==value1)
       else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0)
          return LINE_STATE_STOP_UP;
    //--- Line downward reversal (value2<value1 && value0<value1)
       if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0)
          return LINE_STATE_TURN_DOWN;
    //--- Line downward direction (value2>=value1 && value0<value1)
       else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0)
          return LINE_STATE_DOWN;
    //--- Line downward stop (value2>=value1 && value0==value1)
       else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0)
          return LINE_STATE_STOP_DOWN;
    //--- Undefined state
       return LINE_STATE_NONE;
      }
    //+------------------------------------------------------------------+
    //| Return the state of the line relative to the specified level     |
    //+------------------------------------------------------------------+
    ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE)
      {
    //--- Get the values of the indicator line with the shift (0,1) relative to the passed index
       const double value0=IndicatorValue(ind_handle,index,  buffer_num);
       const double value1=IndicatorValue(ind_handle,index+1,buffer_num);
    //--- If at least one of the values could not be obtained, return an undefined value 
       if(value0==EMPTY_VALUE || value1==EMPTY_VALUE)
          return LINE_STATE_NONE;
    //--- Define the second level to compare
       double level=(level1==EMPTY_VALUE ? level0 : level1);
    //--- The line is below the level (value1<level && value0<level0)
       if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0)
          return LINE_STATE_UNDER;
    //--- The line is above the level (value1>level && value0>level0)
       if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0)
          return LINE_STATE_ABOVE;
    //--- The line crossed the level upwards (value1<=level && value0>level0)
       if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0)
          return LINE_STATE_CROSS_UP;
    //--- The line crossed the level downwards (value1>=level && value0<level0)
       if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0)
          return LINE_STATE_CROSS_DOWN;
    //--- The line touched the level from below (value1<level0 && value0==level0)
       if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0)
          return LINE_STATE_TOUCH_BELOW;
    //--- The line touched the level from above (value1>level0 && value0==level0)
       if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0)
          return LINE_STATE_TOUCH_BELOW;
    //--- Line is equal to the level value (value1==level0 && value0==level0)
       if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0)
          return LINE_STATE_EQUALS;
    //--- Undefined state
       return LINE_STATE_NONE;
      }
    //+------------------------------------------------------------------+
    //| Return the indicator line state description                      |
    //+------------------------------------------------------------------+
    string LineStateDescription(const ENUM_LINE_STATE state)
      {
       switch(state)
         {
          case LINE_STATE_UP         :  return "Up";
          case LINE_STATE_STOP_UP    :  return "Stop Up";
          case LINE_STATE_TURN_UP    :  return "Turn Up";
          case LINE_STATE_DOWN       :  return "Down";
          case LINE_STATE_STOP_DOWN  :  return "Stop Down";
          case LINE_STATE_TURN_DOWN  :  return "Turn Down";
          case LINE_STATE_ABOVE      :  return "Above level";
          case LINE_STATE_UNDER      :  return "Under level";
          case LINE_STATE_CROSS_UP   :  return "Crossing Up";
          case LINE_STATE_CROSS_DOWN :  return "Crossing Down";
          case LINE_STATE_TOUCH_BELOW:  return "Touch from Below";
          case LINE_STATE_TOUCH_ABOVE:  return "Touch from Above";
          case LINE_STATE_EQUALS     :  return "Equals";
          default                    :  return "Unknown";
         }
      }
    
    

    Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :

    //+------------------------------------------------------------------+
    //| Display data from the specified timeseries index to the panel    |
    //+------------------------------------------------------------------+
    void DrawData(const int index,const datetime time)
      {
    //--- Declare the variables to receive data in them
       MqlTick  tick={0};
       MqlRates rates[1];
    
    //--- Exit if unable to get the current prices
       if(!SymbolInfoTick(Symbol(),tick))
          return;
    //--- Exit if unable to get the bar data by the specified index
       if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
          return;
    
    //--- Set font parameters for bar and indicator data headers
       int  size=0;
       uint flags=0;
       uint angle=0;
       string name=panel.FontParams(size,flags,angle);
       panel.SetFontParams(name,9,FW_BOLD);
       panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
       panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
    //--- Set font parameters for bar and indicator data
       panel.SetFontParams(name,9);
    
    //--- Display the data of the specified bar in table 0 on the panel
       panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
       panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
       panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
       panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
       panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
       panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);
    
    //--- Display the indicator data from the specified bar on the panel in table 1
       panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
       double value0=IndicatorValue(handle,index,  0);
       double value1=IndicatorValue(handle,index+1,0);
       string value_str=(value0!=EMPTY_VALUE ? DoubleToString(value0,ind_digits) : "");
       color clr=(value0>value1 ? clrGreen : value0<value1 ? clrRed : clrNONE);
       panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,90);
       
    //--- Display a description of the indicator line state
       panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
       ENUM_LINE_STATE state=LineState(handle,index,0);
       panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clr,90);
       
    //--- Redraw the chart to immediately display all changes on the panel
       ChartRedraw(ChartID());
      }
    
    

    La couleur du texte d'état sur le panneau correspond à la couleur de la colonne de l'indicateur sur laquelle se trouve le curseur.

    De plus, lors de l'utilisation du tableau de bord, le gestionnaire d'événements du panneau est appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, et les événements pour recevoir l'indice de la barre sous le curseur y sont gérés :

    //+------------------------------------------------------------------+
    //| ChartEvent function                                              |
    //+------------------------------------------------------------------+
    void OnChartEvent(const int id,
                      const long &lparam,
                      const double &dparam,
                      const string &sparam)
      {
    //--- Handling the panel
    //--- Call the panel event handler
       panel.OnChartEvent(id,lparam,dparam,sparam);
    
    //--- If the cursor moves or a click is made on the chart
       if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
         {
          //--- Declare the variables to record time and price coordinates in them
          datetime time=0;
          double price=0;
          int wnd=0;
          //--- If the cursor coordinates are converted to date and time
          if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
            {
             //--- write the bar index where the cursor is located to a global variable
             mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
             //--- Display the bar data under the cursor on the panel 
             DrawData(mouse_bar_index,time);
            }
         }
    
    //--- If we received a custom event, display the appropriate message in the journal
       if(id>CHARTEVENT_CUSTOM)
         {
          //--- Here we can implement handling a click on the close button on the panel
          PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
         }
      }
    
    

    Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :


    Vous pouvez consulter le test TestVolumeVolumes.mq5 EA dans les fichiers joints à l'article.


    Indicateurs de Bill Williams

    Les indicateurs de Bill Williams sont inclus dans un groupe distinct, car ils font partie du système de trading décrit dans ses livres.


    Accélérateur Oscillateur

    Le prix est le dernier élément à changer. Avant les changements de prix, la force motrice du marché change de direction, l'accélération de la force motrice doit ralentir et devenir nulle. Ensuite, il commence à accélérer jusqu'à ce que le prix commence à changer de direction.

    L’Oscillateur Acceleration/Deceleration (AC) mesure l'accélération et la décélération de la force motrice actuelle. Cet indicateur changera de direction avant tout changement de la force motrice qui, à son tour, changera de direction avant le prix. Si vous comprenez que l'Accélération/Décélération est un signal d'alerte précoce, vous bénéficiez d'avantages évidents.

    La ligne zéro est en fait l'endroit où la force motrice est en équilibre avec l'accélération. Si l'Accélération/Décélération est supérieure à zéro, il est généralement plus facile pour l'accélération de poursuivre le mouvement vers le haut (et vice versa dans les cas où elle est inférieure à zéro). Contrairement à l’ Awesome Oscillator, le passage de la ligne zéro n'est pas un signal. La seule chose à faire pour contrôler le marché et prendre des décisions est de surveiller les changements de couleur. Pour vous éviter de sérieuses réflexions, vous devez vous rappeler que vous ne pouvez pas acheter à l'aide de l'Accélération/Décélération, lorsque la barre actuelle est colorée en rouge, et que vous ne pouvez pas vendre, lorsque la barre actuelle est colorée en vert.

    Si vous entrez sur le marché dans le sens de la force motrice (l'indicateur est supérieur à zéro, à l'achat, ou inférieur à zéro, à la vente), vous n'avez besoin que de 2 barres vertes pour acheter (2 barres rouges pour vendre). Si la force motrice est dirigée contre la position à ouvrir (indicateur inférieur à zéro pour l'achat ou supérieur à zéro pour la vente), une confirmation est nécessaire, d'où la nécessité d'une barre supplémentaire. Dans ce cas, l'indicateur doit afficher 3 barres rouges au-dessus de la ligne zéro pour une position courte et 3 barres vertes au-dessous de la ligne zéro pour une position longue.


    Paramètres

    La fonction iAC() est utilisée pour créer la poignée de l'indicateur :

    Crée l'indicateur Accelerator Oscillator et renvoie son handle. Un seul buffer.

    int  iAC(
       string           symbol,     // symbol name
       ENUM_TIMEFRAMES  period      // period
       );
    

    symbol

    [in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.

    period

    [in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.

    Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, elle retourne INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.

    Déclarez des variables globales dans l'EA pour créer l'indicateur (l'indicateur n'a pas d'entrées sauf pour définir les couleurs des barres de l'histogramme haussier et baissier) :

    //+------------------------------------------------------------------+
    //|                                               TestWilliamsAC.mq5 |
    //|                                  Copyright 2023, MetaQuotes Ltd. |
    //|                                             https://www.mql5.com |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2023, MetaQuotes Ltd."
    #property link      "https://www.mql5.com"
    #property version   "1.00"
    //--- enums
    enum ENUM_LINE_STATE
      {
       LINE_STATE_NONE,        // Undefined state
       LINE_STATE_UP,          // Upward
       LINE_STATE_DOWN,        // Downward
       LINE_STATE_TURN_UP,     // Upward reversal
       LINE_STATE_TURN_DOWN,   // Downward reversal
       LINE_STATE_STOP_UP,     // Upward stop
       LINE_STATE_STOP_DOWN,   // Downward stop
       LINE_STATE_ABOVE,       // Above value
       LINE_STATE_UNDER,       // Below value
       LINE_STATE_CROSS_UP,    // Crossing value upwards
       LINE_STATE_CROSS_DOWN,  // Crossing value downwards
       LINE_STATE_TOUCH_BELOW, // Touching value from below 
       LINE_STATE_TOUCH_ABOVE, // Touch value from above
       LINE_STATE_EQUALS,      // Equal to value
      };
    //--- global variables
    int      handle=INVALID_HANDLE;  // Indicator handle
    int      ind_digits=0;           // Number of decimal places in the indicator values
    string   ind_title;              // Indicator description
    
    

    Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier des classes de tableaux de bord :

    //+------------------------------------------------------------------+
    //|                                               TestWilliamsAC.mq5 |
    //|                                  Copyright 2023, MetaQuotes Ltd. |
    //|                                             https://www.mql5.com |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2023, MetaQuotes Ltd."
    #property link      "https://www.mql5.com"
    #property version   "1.00"
    //--- includes
    #include <Dashboard\Dashboard.mqh>
    //--- enums
    enum ENUM_LINE_STATE
      {
       LINE_STATE_NONE,        // Undefined state
       LINE_STATE_UP,          // Upward
       LINE_STATE_DOWN,        // Downward
       LINE_STATE_TURN_UP,     // Upward reversal
       LINE_STATE_TURN_DOWN,   // Downward reversal
       LINE_STATE_STOP_UP,     // Upward stop
       LINE_STATE_STOP_DOWN,   // Downward stop
       LINE_STATE_ABOVE,       // Above value
       LINE_STATE_UNDER,       // Below value
       LINE_STATE_CROSS_UP,    // Crossing value upwards
       LINE_STATE_CROSS_DOWN,  // Crossing value downwards
       LINE_STATE_TOUCH_BELOW, // Touching value from below 
       LINE_STATE_TOUCH_ABOVE, // Touch value from above
       LINE_STATE_EQUALS,      // Equal to value
      };
    //--- global variables
    int      handle=INVALID_HANDLE;  // Indicator handle
    int      ind_digits=0;           // Number of decimal places in the indicator values
    string   ind_title;              // Indicator description
    //--- variables for the panel
    int      mouse_bar_index;        // Index of the bar the data is taken from
    CDashboard *panel=NULL;          // Pointer to the panel object
    
    


    Initialisation

    Définition des valeurs des variables globales de l'indicateur et création de son handle :

    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
      {
    //--- create timer
       EventSetTimer(60);
    
    //--- Indicator
    //--- Set the indicator name and the number of decimal places
       ind_title="AC";
       ind_digits=Digits()+2;
    //--- Create indicator handle
       ResetLastError();
       handle=iAC(Symbol(),PERIOD_CURRENT);
       if(handle==INVALID_HANDLE)
         {
          PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError());
          return INIT_FAILED;
         }
    
    //--- Successful initialization
       return(INIT_SUCCEEDED);
      }
    
    

    Si l'EA implique l'utilisation du tableau de bord, créez-le ici :

    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
      {
    //--- create timer
       EventSetTimer(60);
    
    //--- Indicator
    //--- Set the indicator name and the number of decimal places
       ind_title="AC";
       ind_digits=Digits()+2;
    //--- Create indicator handle
       ResetLastError();
       handle=iAC(Symbol(),PERIOD_CURRENT);
       if(handle==INVALID_HANDLE)
         {
          PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError());
          return INIT_FAILED;
         }
    
    //--- Dashboard
    //--- Create the panel
       panel=new CDashboard(1,20,20,199,225);
       if(panel==NULL)
         {
          Print("Error. Failed to create panel object");
          return INIT_FAILED;
         }
    //--- Set font parameters
       panel.SetFontParams("Calibri",9);
    //--- Display the panel with the "Symbol, Timeframe description" header text
       panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));
    //--- Create a table with ID 0 to display bar data in it
       panel.CreateNewTable(0);
    //--- Draw a table with ID 0 on the panel background
       panel.DrawGrid(0,2,20,6,2,18,97);
    
    //--- Create a table with ID 1 to display indicator data in it
       panel.CreateNewTable(1);
    //--- Get the Y2 table coordinate with ID 0 and
    //--- set the Y1 coordinate for the table with ID 1
       int y1=panel.TableY2(0)+22;
    //--- Draw a table with ID 1 on the panel background
       panel.DrawGrid(1,2,y1,3,2,18,97);
       
    //--- Display tabular data in the journal
       panel.GridPrint(0,2);
       panel.GridPrint(1,2);
    //--- Initialize the variable with the index of the mouse cursor bar
       mouse_bar_index=0;
    //--- Display the data of the current bar on the panel
       DrawData(mouse_bar_index,TimeCurrent());
    
    //--- Successful initialization
       return(INIT_SUCCEEDED);
      }
    
    


    Dé-initialisation

    Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :

    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
      {
    //--- destroy timer
       EventKillTimer();
       
    //--- Release handle of the indicator
       ResetLastError();
       if(!IndicatorRelease(handle))
          PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
    //--- Clear all comments on the chart
       Comment("");
      }
    
    

    L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :

    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
      {
    //--- destroy timer
       EventKillTimer();
       
    //--- Release handle of the indicator
       ResetLastError();
       if(!IndicatorRelease(handle))
          PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
    //--- Clear all comments on the chart
       Comment("");
       
    //--- If the panel object exists, delete it
       if(panel!=NULL)
          delete panel;
      }
    


    Récupération des résultats

    Les fonctions générales permettant d'obtenir des données à l'aide de la poignée de l'indicateur sont présentées ci-dessous. Les fonctions ont été passées en revue dans l'article sur la connexion des oscillateurs aux EA. Les fonctions présentées peuvent être utilisées "telles quelles" dans des programmes personnalisés :

    //+------------------------------------------------------------------+
    //| Return the indicator data on the specified bar                   |
    //+------------------------------------------------------------------+
    double IndicatorValue(const int ind_handle,const int index,const int buffer_num)
      {
       double array[1]={0};
       ResetLastError();
       if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1)
         {
          PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError());
          return EMPTY_VALUE;
         }
       return array[0];
      }
    //+------------------------------------------------------------------+
    //| Return the state of the indicator line                           |
    //+------------------------------------------------------------------+
    ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num)
      {
    //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index
       const double value0=IndicatorValue(ind_handle,index,  buffer_num);
       const double value1=IndicatorValue(ind_handle,index+1,buffer_num);
       const double value2=IndicatorValue(ind_handle,index+2,buffer_num);
    //--- If at least one of the values could not be obtained, return an undefined value 
       if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE)
          return LINE_STATE_NONE;
    //--- Line upward reversal (value2>value1 && value0>value1)
       if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0)
          return LINE_STATE_TURN_UP;
    //--- Line upward direction (value2<=value1 && value0>value1)
       else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0)
          return LINE_STATE_UP;
    //--- Line upward stop (value2<=value1 && value0==value1)
       else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0)
          return LINE_STATE_STOP_UP;
    //--- Line downward reversal (value2<value1 && value0<value1)
       if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0)
          return LINE_STATE_TURN_DOWN;
    //--- Line downward direction (value2>=value1 && value0<value1)
       else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0)
          return LINE_STATE_DOWN;
    //--- Line downward stop (value2>=value1 && value0==value1)
       else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0)
          return LINE_STATE_STOP_DOWN;
    //--- Undefined state
       return LINE_STATE_NONE;
      }
    //+------------------------------------------------------------------+
    //| Return the state of the line relative to the specified level     |
    //+------------------------------------------------------------------+
    ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE)
      {
    //--- Get the values of the indicator line with the shift (0,1) relative to the passed index
       const double value0=IndicatorValue(ind_handle,index,  buffer_num);
       const double value1=IndicatorValue(ind_handle,index+1,buffer_num);
    //--- If at least one of the values could not be obtained, return an undefined value 
       if(value0==EMPTY_VALUE || value1==EMPTY_VALUE)
          return LINE_STATE_NONE;
    //--- Define the second level to compare
       double level=(level1==EMPTY_VALUE ? level0 : level1);
    //--- The line is below the level (value1<level && value0<level0)
       if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0)
          return LINE_STATE_UNDER;
    //--- The line is above the level (value1>level && value0>level0)
       if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0)
          return LINE_STATE_ABOVE;
    //--- The line crossed the level upwards (value1<=level && value0>level0)
       if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0)
          return LINE_STATE_CROSS_UP;
    //--- The line crossed the level downwards (value1>=level && value0<level0)
       if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0)
          return LINE_STATE_CROSS_DOWN;
    //--- The line touched the level from below (value1<level0 && value0==level0)
       if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0)
          return LINE_STATE_TOUCH_BELOW;
    //--- The line touched the level from above (value1>level0 && value0==level0)
       if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0)
          return LINE_STATE_TOUCH_BELOW;
    //--- Line is equal to the level value (value1==level0 && value0==level0)
       if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0)
          return LINE_STATE_EQUALS;
    //--- Undefined state
       return LINE_STATE_NONE;
      }
    //+------------------------------------------------------------------+
    //| Return the indicator line state description                      |
    //+------------------------------------------------------------------+
    string LineStateDescription(const ENUM_LINE_STATE state)
      {
       switch(state)
         {
          case LINE_STATE_UP         :  return "Up";
          case LINE_STATE_STOP_UP    :  return "Stop Up";
          case LINE_STATE_TURN_UP    :  return "Turn Up";
          case LINE_STATE_DOWN       :  return "Down";
          case LINE_STATE_STOP_DOWN  :  return "Stop Down";
          case LINE_STATE_TURN_DOWN  :  return "Turn Down";
          case LINE_STATE_ABOVE      :  return "Above level";
          case LINE_STATE_UNDER      :  return "Under level";
          case LINE_STATE_CROSS_UP   :  return "Crossing Up";
          case LINE_STATE_CROSS_DOWN :  return "Crossing Down";
          case LINE_STATE_TOUCH_BELOW:  return "Touch from Below";
          case LINE_STATE_TOUCH_ABOVE:  return "Touch from Above";
          case LINE_STATE_EQUALS     :  return "Equals";
          default                    :  return "Unknown";
         }
      }
    
    

    Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :

    //+------------------------------------------------------------------+
    //| Display data from the specified timeseries index to the panel    |
    //+------------------------------------------------------------------+
    void DrawData(const int index,const datetime time)
      {
    //--- Declare the variables to receive data in them
       MqlTick  tick={0};
       MqlRates rates[1];
    
    //--- Exit if unable to get the current prices
       if(!SymbolInfoTick(Symbol(),tick))
          return;
    //--- Exit if unable to get the bar data by the specified index
       if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
          return;
    
    //--- Set font parameters for bar and indicator data headers
       int  size=0;
       uint flags=0;
       uint angle=0;
       string name=panel.FontParams(size,flags,angle);
       panel.SetFontParams(name,9,FW_BOLD);
       panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
       panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
    //--- Set font parameters for bar and indicator data
       panel.SetFontParams(name,9);
    
    //--- Display the data of the specified bar in table 0 on the panel
       panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
       panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
       panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
       panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
       panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
       panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);
    
    //--- Display the indicator data from the specified bar on the panel in table 1
       panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
       double value0=IndicatorValue(handle,index,  0);
       double value1=IndicatorValue(handle,index+1,0);
       string value_str=(value0!=EMPTY_VALUE ? DoubleToString(value0,ind_digits) : "");
       color clr=(value0>value1 ? clrGreen : value0<value1 ? clrRed : clrNONE);
       panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,90);
       
    //--- Display a description of the indicator line state
       panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
       ENUM_LINE_STATE state=LineState(handle,index,0);
       panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clr,90);
       
    //--- Redraw the chart to immediately display all changes on the panel
       ChartRedraw(ChartID());
      }
    
    

    La couleur des textes d'état de la ligne de l’indicateur sur le tableau de bord correspond à la couleur des barres de l'histogramme sur lesquelles se trouve le curseur.

    De plus, lors de l'utilisation du tableau de bord, le gestionnaire d'événements du panneau est appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, et les événements pour recevoir l'indice de la barre sous le curseur y sont gérés :

    //+------------------------------------------------------------------+
    //| ChartEvent function                                              |
    //+------------------------------------------------------------------+
    void OnChartEvent(const int id,
                      const long &lparam,
                      const double &dparam,
                      const string &sparam)
      {
    //--- Handling the panel
    //--- Call the panel event handler
       panel.OnChartEvent(id,lparam,dparam,sparam);
    
    //--- If the cursor moves or a click is made on the chart
       if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
         {
          //--- Declare the variables to record time and price coordinates in them
          datetime time=0;
          double price=0;
          int wnd=0;
          //--- If the cursor coordinates are converted to date and time
          if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
            {
             //--- write the bar index where the cursor is located to a global variable
             mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
             //--- Display the bar data under the cursor on the panel 
             DrawData(mouse_bar_index,time);
            }
         }
    
    //--- If we received a custom event, display the appropriate message in the journal
       if(id>CHARTEVENT_CUSTOM)
         {
          //--- Here we can implement handling a click on the close button on the panel
          PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
         }
      }
    
    

    Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :


    Vous pouvez consulter le test TestWilliamsAC.mq5 EA dans les fichiers joints à l'article.


    Alligator

    La plupart du temps, le marché reste stationnaire. Ce n'est que pendant 15 à 30% du temps que le marché génère des tendances, et les traders qui ne se trouvent pas sur la bourse elle-même tirent la plupart de leurs profits de ces tendances. Mon grand-père avait l'habitude de le répéter : "Même un poulet aveugle trouvera ses grains s'il est toujours nourri à la même heure". Nous appelons le trading sur tendance "un marché de poulets aveugles". Il nous a fallu des années, mais nous avons mis au point un indicateur qui nous permet de garder la tête froide jusqu'à ce que nous atteignions le "marché des poulets aveugles".
    Bill Williams

    L’Alligator est une combinaison de lignes de Balance (des Moyennes Mobiles), qui utilisent la géométrie fractale et la dynamique non linéaire.

    • La ligne bleue (la Mâchoire de l'Alligator) est la ligne d'équilibre pour la période utilisée pour construire un graphique (une moyenne mobile lissée sur 13 périodes, déplacée de 8 barres dans le futur) ;
    • La ligne rouge (les Dents de l'Alligator) est la ligne d'équilibre pour une période de temps significative, abaissée d’un ordre (une moyenne mobile lissée à 8 périodes, déplacée de 5 barres dans le futur) ;
    • La ligne verte (Lèvres d'alligator) est la ligne d'équilibre pour une période de temps significative, abaissée d’une autre ordre (une moyenne mobile lissée à 5 périodes, déplacée de 3 barres dans le futur).

    Les Lèvres, les Dents et les Mâchoires de l'Alligator illustrent l'interaction entre différentes périodes. Étant donné que les tendances du marché ne peuvent être identifiées que pendant 15 à 30% du temps, nous devons suivre les tendances et ne pas travailler sur des marchés qui ne fluctuent qu'à l'intérieur de certaines périodes de prix.

    Lorsque les Mâchoires, les Dents et les Lèvres sont fermées ou entrelacées, l'Alligator s'endort ou est déjà endormi. Lorsqu'il dort, sa faim augmente - donc plus il dort, plus il aura faim lorsqu'il se réveillera. Lorsqu'il se réveille, la première chose qu'il fait est d'ouvrir la bouche et de commencer à bâiller. Puis il commence à entendre l'odeur de la nourriture : la viande d'un taureau ou d'un ours, et se met à la chasser. Après avoir mangé suffisamment pour se sentir rassasié, l'Alligator commence à se désintéresser de la nourriture et du prix (les lignes d'équilibre se rejoignent) - c'est le moment de prendre vos profits.



    Paramètres

    La fonction iAlligator() est utilisée pour créer la poignée de l'indicateur :

    Retourne un handle sur l’indicateur Alligator.

    int  iAlligator(
       string              symbol,            // symbol name
       ENUM_TIMEFRAMES     period,            // period
       int                 jaw_period,        // period for calculating jaws
       int                 jaw_shift,         // horizontal shift of jaws
       int                 teeth_period,      // period for calculating teeth
       int                 teeth_shift,       // horizontal shift of teeth
       int                 lips_period,       // period for calculating lips
       int                 lips_shift,        // horizontal shift of lips
       ENUM_MA_METHOD      ma_method,         // smoothing type
       ENUM_APPLIED_PRICE  applied_price      // price type or handle
       );
    

    symbol

    [in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.

    period

    [in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.

    jaw_period

    [in] Période de calcul de la moyenne de la ligne bleue (Mâchoire de l’Alligator).

    jaw_shift

    [in] Décalage de la ligne bleue par rapport au graphique des prix.

    teeth_period

    [in] Période de calcul de la moyenne de la ligne rouge (Dents de l’Alligator).

    teeth_shift

    [in] Décalage de la ligne rouge par rapport au graphique des prix.

    lips_period

    [in] Période de calcul de la moyenne de la ligne verte (Lèvres de l’Alligator).

    lips_shift

    [in] Décalage de la ligne verte par rapport au graphique des prix.

    ma_method

    [in] Méthode de calcul de la moyenne. Toute valeur de l'énumération ENUM_MA_METHOD.

    applied_price

    [in] Le prix appliqué. Une des constantes de prix ENUM_APPLIED_PRICE ou un autre indicateur.

    Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, elle retourne INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.

    Indices des buffers : 0 - GATORJAW_LINE, 1 - GATORTEETH_LINE, 2 - GATORLIPS_LINE.


    Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :

    //+------------------------------------------------------------------+
    //|                                        TestWilliamsAlligator.mq5 |
    //|                                  Copyright 2023, MetaQuotes Ltd. |
    //|                                             https://www.mql5.com |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2023, MetaQuotes Ltd."
    #property link      "https://www.mql5.com"
    #property version   "1.00"
    //--- enums
    enum ENUM_LINE_STATE
      {
       LINE_STATE_NONE,        // Undefined state
       LINE_STATE_UP,          // Upward
       LINE_STATE_DOWN,        // Downward
       LINE_STATE_TURN_UP,     // Upward reversal
       LINE_STATE_TURN_DOWN,   // Downward reversal
       LINE_STATE_STOP_UP,     // Upward stop
       LINE_STATE_STOP_DOWN,   // Downward stop
       LINE_STATE_ABOVE,       // Above value
       LINE_STATE_UNDER,       // Below value
       LINE_STATE_CROSS_UP,    // Crossing value upwards
       LINE_STATE_CROSS_DOWN,  // Crossing value downwards
       LINE_STATE_TOUCH_BELOW, // Touching value from below 
       LINE_STATE_TOUCH_ABOVE, // Touch value from above
       LINE_STATE_EQUALS,      // Equal to value
      };
    //--- input parameters
    input uint                 InpPeriodJaws  =  13;            /* Jaws Period    */
    input int                  InpShiftJaws   =  8;             /* Jaws Shift     */
    input uint                 InpPeriodTeeth =  8;             /* Teeth Period   */
    input int                  InpShiftTeeth  =  5;             /* Teeth Shift    */
    input uint                 InpPeriodLips  =  5;             /* Lips Period    */
    input int                  InpShiftLips   =  3;             /* Lips Shift     */
    input ENUM_MA_METHOD       InpMethod      =  MODE_SMMA;     /* Smoothed       */
    input ENUM_APPLIED_PRICE   InpAppliedPrice=  PRICE_MEDIAN;  /* Applied Price  */
    //--- global variables
    int      handle=INVALID_HANDLE;  // Indicator handle
    int      period_jaws=0;          // Jaws line calculation period
    int      period_teeth=0;         // Teeth line calculation period
    int      period_lips=0;          // Lips line calculation period
    int      ind_digits=0;           // Number of decimal places in the indicator values
    string   ind_title;              // Indicator description
    
    

    Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier des classes de tableaux de bord :

    //+------------------------------------------------------------------+
    //|                                        TestWilliamsAlligator.mq5 |
    //|                                  Copyright 2023, MetaQuotes Ltd. |
    //|                                             https://www.mql5.com |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2023, MetaQuotes Ltd."
    #property link      "https://www.mql5.com"
    #property version   "1.00"
    //--- includes
    #include <Dashboard\Dashboard.mqh>
    //--- enums
    enum ENUM_LINE_STATE
      {
       LINE_STATE_NONE,        // Undefined state
       LINE_STATE_UP,          // Upward
       LINE_STATE_DOWN,        // Downward
       LINE_STATE_TURN_UP,     // Upward reversal
       LINE_STATE_TURN_DOWN,   // Downward reversal
       LINE_STATE_STOP_UP,     // Upward stop
       LINE_STATE_STOP_DOWN,   // Downward stop
       LINE_STATE_ABOVE,       // Above value
       LINE_STATE_UNDER,       // Below value
       LINE_STATE_CROSS_UP,    // Crossing value upwards
       LINE_STATE_CROSS_DOWN,  // Crossing value downwards
       LINE_STATE_TOUCH_BELOW, // Touching value from below 
       LINE_STATE_TOUCH_ABOVE, // Touch value from above
       LINE_STATE_EQUALS,      // Equal to value
      };
    //--- input parameters
    input uint                 InpPeriodJaws  =  13;            /* Jaws Period    */
    input int                  InpShiftJaws   =  8;             /* Jaws Shift     */
    input uint                 InpPeriodTeeth =  8;             /* Teeth Period   */
    input int                  InpShiftTeeth  =  5;             /* Teeth Shift    */
    input uint                 InpPeriodLips  =  5;             /* Lips Period    */
    input int                  InpShiftLips   =  3;             /* Lips Shift     */
    input ENUM_MA_METHOD       InpMethod      =  MODE_SMMA;     /* Smoothed       */
    input ENUM_APPLIED_PRICE   InpAppliedPrice=  PRICE_MEDIAN;  /* Applied Price  */
    //--- global variables
    int      handle=INVALID_HANDLE;  // Indicator handle
    int      period_jaws=0;          // Jaws line calculation period
    int      period_teeth=0;         // Teeth line calculation period
    int      period_lips=0;          // Lips line calculation period
    int      ind_digits=0;           // Number of decimal places in the indicator values
    string   ind_title;              // Indicator description
    //--- variables for the panel
    int      mouse_bar_index;        // Index of the bar the data is taken from
    CDashboard *panel=NULL;          // Pointer to the panel object
    
    


    Initialisation

    Définition des valeurs des variables globales de l'indicateur et création de son handle :

    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
      {
    //--- create timer
       EventSetTimer(60);
    
    //--- Indicator
    //--- Set and adjust the calculation period if necessary
       period_jaws=int(InpPeriodJaws<1 ? 13 : InpPeriodJaws);
       period_teeth=int(InpPeriodTeeth<1 ? 8 : InpPeriodTeeth);
       period_lips=int(InpPeriodLips<1 ? 5 : InpPeriodLips);
    //--- Set the indicator name and the number of decimal places
       ind_title=StringFormat("Alligator(%lu,%lu,%lu)",period_jaws,period_teeth,period_lips);
       ind_digits=Digits();
    //--- Create indicator handle
       ResetLastError();
       handle=iAlligator(Symbol(),PERIOD_CURRENT,period_jaws,InpShiftJaws,period_teeth,InpShiftTeeth,period_lips,InpShiftLips,InpMethod,InpAppliedPrice);
       if(handle==INVALID_HANDLE)
         {
          PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError());
          return INIT_FAILED;
         }
    
    //--- Successful initialization
       return(INIT_SUCCEEDED);
      }
    
    

    Si l'EA implique l'utilisation du tableau de bord, créez-le ici :

    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
      {
    //--- create timer
       EventSetTimer(60);
    
    //--- Indicator
    //--- Set and adjust the calculation period if necessary
       period_jaws=int(InpPeriodJaws<1 ? 13 : InpPeriodJaws);
       period_teeth=int(InpPeriodTeeth<1 ? 8 : InpPeriodTeeth);
       period_lips=int(InpPeriodLips<1 ? 5 : InpPeriodLips);
    //--- Set the indicator name and the number of decimal places
       ind_title=StringFormat("Alligator(%lu,%lu,%lu)",period_jaws,period_teeth,period_lips);
       ind_digits=Digits();
    //--- Create indicator handle
       ResetLastError();
       handle=iAlligator(Symbol(),PERIOD_CURRENT,period_jaws,InpShiftJaws,period_teeth,InpShiftTeeth,period_lips,InpShiftLips,InpMethod,InpAppliedPrice);
       if(handle==INVALID_HANDLE)
         {
          PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError());
          return INIT_FAILED;
         }
    
    //--- Dashboard
    //--- Create the panel
       panel=new CDashboard(1,20,20,199,261);
       if(panel==NULL)
         {
          Print("Error. Failed to create panel object");
          return INIT_FAILED;
         }
    //--- Set font parameters
       panel.SetFontParams("Calibri",9);
    //--- Display the panel with the "Symbol, Timeframe description" header text
       panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));
    //--- Create a table with ID 0 to display bar data in it
       panel.CreateNewTable(0);
    //--- Draw a table with ID 0 on the panel background
       panel.DrawGrid(0,2,20,6,2,18,97);
    
    //--- Create a table with ID 1 to display indicator data in it
       panel.CreateNewTable(1);
    //--- Get the Y2 table coordinate with ID 0 and
    //--- set the Y1 coordinate for the table with ID 1
       int y1=panel.TableY2(0)+22;
    //--- Draw a table with ID 1 on the panel background
       panel.DrawGrid(1,2,y1,5,2,18,97);
       
    //--- Display tabular data in the journal
       panel.GridPrint(0,2);
       panel.GridPrint(1,2);
    //--- Initialize the variable with the index of the mouse cursor bar
       mouse_bar_index=0;
    //--- Display the data of the current bar on the panel
       DrawData(mouse_bar_index,TimeCurrent());
    
    //--- Successful initialization
       return(INIT_SUCCEEDED);
      }
    
    


    Dé-initialisation

    Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :

    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
      {
    //--- destroy timer
       EventKillTimer();
       
    //--- Release handle of the indicator
       ResetLastError();
       if(!IndicatorRelease(handle))
          PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
    //--- Clear all comments on the chart
       Comment("");
      }
    
    

    L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :

    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
      {
    //--- destroy timer
       EventKillTimer();
       
    //--- Release handle of the indicator
       ResetLastError();
       if(!IndicatorRelease(handle))
          PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
    //--- Clear all comments on the chart
       Comment("");
       
    //--- If the panel object exists, delete it
       if(panel!=NULL)
          delete panel;
      }
    


    Récupération des résultats

    Les fonctions générales permettant d'obtenir des données à l'aide de la poignée de l'indicateur sont présentées ci-dessous. Les fonctions ont été passées en revue dans l'article sur la connexion des oscillateurs aux EA. Les fonctions présentées peuvent être utilisées "telles quelles" dans des programmes personnalisés :

    //+------------------------------------------------------------------+
    //| Return the indicator data on the specified bar                   |
    //+------------------------------------------------------------------+
    double IndicatorValue(const int ind_handle,const int index,const int buffer_num)
      {
       double array[1]={0};
       ResetLastError();
       if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1)
         {
          PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError());
          return EMPTY_VALUE;
         }
       return array[0];
      }
    //+------------------------------------------------------------------+
    //| Return the state of the indicator line                           |
    //+------------------------------------------------------------------+
    ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num)
      {
    //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index
       const double value0=IndicatorValue(ind_handle,index,  buffer_num);
       const double value1=IndicatorValue(ind_handle,index+1,buffer_num);
       const double value2=IndicatorValue(ind_handle,index+2,buffer_num);
    //--- If at least one of the values could not be obtained, return an undefined value 
       if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE)
          return LINE_STATE_NONE;
    //--- Line upward reversal (value2>value1 && value0>value1)
       if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0)
          return LINE_STATE_TURN_UP;
    //--- Line upward direction (value2<=value1 && value0>value1)
       else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0)
          return LINE_STATE_UP;
    //--- Line upward stop (value2<=value1 && value0==value1)
       else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0)
          return LINE_STATE_STOP_UP;
    //--- Line downward reversal (value2<value1 && value0<value1)
       if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0)
          return LINE_STATE_TURN_DOWN;
    //--- Line downward direction (value2>=value1 && value0<value1)
       else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0)
          return LINE_STATE_DOWN;
    //--- Line downward stop (value2>=value1 && value0==value1)
       else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0)
          return LINE_STATE_STOP_DOWN;
    //--- Undefined state
       return LINE_STATE_NONE;
      }
    //+------------------------------------------------------------------+
    //| Return the state of the line relative to the specified level     |
    //+------------------------------------------------------------------+
    ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE)
      {
    //--- Get the values of the indicator line with the shift (0,1) relative to the passed index
       const double value0=IndicatorValue(ind_handle,index,  buffer_num);
       const double value1=IndicatorValue(ind_handle,index+1,buffer_num);
    //--- If at least one of the values could not be obtained, return an undefined value 
       if(value0==EMPTY_VALUE || value1==EMPTY_VALUE)
          return LINE_STATE_NONE;
    //--- Define the second level to compare
       double level=(level1==EMPTY_VALUE ? level0 : level1);
    //--- The line is below the level (value1<level && value0<level0)
       if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0)
          return LINE_STATE_UNDER;
    //--- The line is above the level (value1>level && value0>level0)
       if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0)
          return LINE_STATE_ABOVE;
    //--- The line crossed the level upwards (value1<=level && value0>level0)
       if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0)
          return LINE_STATE_CROSS_UP;
    //--- The line crossed the level downwards (value1>=level && value0<level0)
       if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0)
          return LINE_STATE_CROSS_DOWN;
    //--- The line touched the level from below (value1<level0 && value0==level0)
       if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0)
          return LINE_STATE_TOUCH_BELOW;
    //--- The line touched the level from above (value1>level0 && value0==level0)
       if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0)
          return LINE_STATE_TOUCH_BELOW;
    //--- Line is equal to the level value (value1==level0 && value0==level0)
       if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0)
          return LINE_STATE_EQUALS;
    //--- Undefined state
       return LINE_STATE_NONE;
      }
    //+------------------------------------------------------------------+
    //| Return the indicator line state description                      |
    //+------------------------------------------------------------------+
    string LineStateDescription(const ENUM_LINE_STATE state)
      {
       switch(state)
         {
          case LINE_STATE_UP         :  return "Up";
          case LINE_STATE_STOP_UP    :  return "Stop Up";
          case LINE_STATE_TURN_UP    :  return "Turn Up";
          case LINE_STATE_DOWN       :  return "Down";
          case LINE_STATE_STOP_DOWN  :  return "Stop Down";
          case LINE_STATE_TURN_DOWN  :  return "Turn Down";
          case LINE_STATE_ABOVE      :  return "Above level";
          case LINE_STATE_UNDER      :  return "Under level";
          case LINE_STATE_CROSS_UP   :  return "Crossing Up";
          case LINE_STATE_CROSS_DOWN :  return "Crossing Down";
          case LINE_STATE_TOUCH_BELOW:  return "Touch from Below";
          case LINE_STATE_TOUCH_ABOVE:  return "Touch from Above";
          case LINE_STATE_EQUALS     :  return "Equals";
          default                    :  return "Unknown";
         }
      }
    
    

    Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :

    //+------------------------------------------------------------------+
    //| Display data from the specified timeseries index to the panel    |
    //+------------------------------------------------------------------+
    void DrawData(const int index,const datetime time)
      {
    //--- Declare the variables to receive data in them
       MqlTick  tick={0};
       MqlRates rates[1];
    
    //--- Exit if unable to get the current prices
       if(!SymbolInfoTick(Symbol(),tick))
          return;
    //--- Exit if unable to get the bar data by the specified index
       if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
          return;
    
    //--- Set font parameters for bar and indicator data headers
       int  size=0;
       uint flags=0;
       uint angle=0;
       string name=panel.FontParams(size,flags,angle);
       panel.SetFontParams(name,9,FW_BOLD);
       panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
       panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
    //--- Set font parameters for bar and indicator data
       panel.SetFontParams(name,9);
    
    //--- Display the data of the specified bar in table 0 on the panel
       panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
       panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
       panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
       panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
       panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
       panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);
    
    //--- Get the indicator lines data
       double value_jaws=IndicatorValue(handle,index,GATORJAW_LINE);
       double value_teeth=IndicatorValue(handle,index,GATORTEETH_LINE);
       double value_lips=IndicatorValue(handle,index,GATORLIPS_LINE);
       
    //--- Display the Jaws line data from the specified bar on the panel in table 1
       string jaws_str=StringFormat("Jaws(%lu)",period_jaws);
       panel.DrawText(jaws_str, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
       string value_str=(value_jaws!=EMPTY_VALUE ? DoubleToString(value_jaws,ind_digits) : "");
       panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,90);
    //--- Display the Teeth line data from the specified bar on the panel in table 1
       string teeth_str=StringFormat("Teeth(%lu)",period_teeth);
       panel.DrawText(teeth_str, panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
       value_str=(value_teeth!=EMPTY_VALUE ? DoubleToString(value_teeth,ind_digits) : "");
       panel.DrawText(value_str,panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,90);
    //--- Display the Lips line data from the specified bar on the panel in table 1
       string lips_str=StringFormat("Lips(%lu)",period_jaws);
       panel.DrawText(lips_str, panel.CellX(1,2,0)+2, panel.CellY(1,2,0)+2);
       value_str=(value_lips!=EMPTY_VALUE ? DoubleToString(value_lips,ind_digits) : "");
       panel.DrawText(value_str,panel.CellX(1,2,1)+2,panel.CellY(1,2,1)+2,clrNONE,90);
       
    //--- Display a description of the Teeth line state relative to the Jaws line
       panel.DrawText("Teeth vs Jaws", panel.CellX(1,3,0)+2, panel.CellY(1,3,0)+2);
       ENUM_LINE_STATE state_tj=LineStateRelative(handle,index,1,value_jaws,IndicatorValue(handle,index+1,GATORJAW_LINE));
       string state_tj_str=
         (
          state_tj==LINE_STATE_ABOVE        ?  "Teeth > Jaws"  : 
          state_tj==LINE_STATE_UNDER        ?  "Teeth < Jaws"  : 
          state_tj==LINE_STATE_TOUCH_ABOVE  || 
          state_tj==LINE_STATE_TOUCH_BELOW  ?  "Touch"     :
          LineStateDescription(state_tj)
         );
    //--- The label color changes depending on the value of the line relative to the level
       color clr=(state_tj==LINE_STATE_CROSS_UP || state_tj==LINE_STATE_ABOVE  ? clrBlue : state_tj==LINE_STATE_CROSS_DOWN || state_tj==LINE_STATE_UNDER ? clrRed : clrNONE);
       panel.DrawText(state_tj_str,panel.CellX(1,3,1)+2,panel.CellY(1,3,1)+2,clr,90);
       
    //--- Display a description of the Lips line state relative to the Teeth line
       panel.DrawText("Lips vs Teeth", panel.CellX(1,4,0)+2, panel.CellY(1,4,0)+2);
       ENUM_LINE_STATE state_lt=LineStateRelative(handle,index,2,value_teeth,IndicatorValue(handle,index+1,GATORTEETH_LINE));
       string state_lt_str=
         (
          state_lt==LINE_STATE_ABOVE        ?  "Lips > Teeth"  : 
          state_lt==LINE_STATE_UNDER        ?  "Lips < Teeth"  : 
          state_lt==LINE_STATE_TOUCH_ABOVE  || 
          state_lt==LINE_STATE_TOUCH_BELOW  ?  "Touch"     :
          LineStateDescription(state_lt)
         );
    //--- The label color changes depending on the value of the line relative to the level
       clr=(state_lt==LINE_STATE_CROSS_UP || state_lt==LINE_STATE_ABOVE  ? clrBlue : state_lt==LINE_STATE_CROSS_DOWN || state_lt==LINE_STATE_UNDER ? clrRed : clrNONE);
       panel.DrawText(state_lt_str,panel.CellX(1,4,1)+2,panel.CellY(1,4,1)+2,clr,90);
       
    //--- Redraw the chart to immediately display all changes on the panel
       ChartRedraw(ChartID());
      }
    
    

    En plus des valeurs des lignes de l’indicateur sur les barres situées sous le curseur, le panneau affiche aussi les états des ratios des lignes Dents - Mâchoires et Lèvres - Dents. Leurs relations sont affichées dans le texte et leurs positions relatives sont indiquées par la couleur du texte affiché.

    De plus, lors de l'utilisation du tableau de bord, le gestionnaire d'événements du panneau est appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, et les événements pour recevoir l'indice de la barre sous le curseur y sont gérés :

    //+------------------------------------------------------------------+
    //| ChartEvent function                                              |
    //+------------------------------------------------------------------+
    void OnChartEvent(const int id,
                      const long &lparam,
                      const double &dparam,
                      const string &sparam)
      {
    //--- Handling the panel
    //--- Call the panel event handler
       panel.OnChartEvent(id,lparam,dparam,sparam);
    
    //--- If the cursor moves or a click is made on the chart
       if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
         {
          //--- Declare the variables to record time and price coordinates in them
          datetime time=0;
          double price=0;
          int wnd=0;
          //--- If the cursor coordinates are converted to date and time
          if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
            {
             //--- write the bar index where the cursor is located to a global variable
             mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
             //--- Display the bar data under the cursor on the panel 
             DrawData(mouse_bar_index,time);
            }
         }
    
    //--- If we received a custom event, display the appropriate message in the journal
       if(id>CHARTEVENT_CUSTOM)
         {
          //--- Here we can implement handling a click on the close button on the panel
          PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
         }
      }
    
    

    Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :


    Vous pouvez consulter le test TestWilliamsAlligator.mq5 EA dans les fichiers joints à l'article.


    Awesome Oscillator

    L’indicateur technique Awesome Oscillator de Bill Williams (AO) est une moyenne mobile simple à 34 périodes, tracée à travers les points centraux des barres (H+L)/2, qui est soustraite de la moyenne mobile simple à 5 périodes, construite à travers les points centraux des barres (H+L)/2. Il nous montre très clairement ce qui se passe au niveau de la force motrice du marché à l'heure actuelle.

    Signaux d'Achat Valides

    La "soucoupe" est le seul signal d'achat qui survient lorsque l'histogramme est au-dessus de la ligne zéro. N'oubliez pas les éléments suivants :
    • le signal de la soucoupe est généré lorsque l'histogramme a inversé sa direction du bas vers le haut. La deuxième barre est plus basse que la première et est colorée en rouge. La troisième barre est plus haute que la deuxième et est colorée en vert ;
    • pour que le signal de soucoupe soit généré, l'histogramme doit comporter au moins trois barres.

    Gardez à l'esprit que toutes les barres de l'Awesome Oscillator doivent être au-dessus de la ligne de zéro pour que le signal de soucoupe puisse être utilisé.

    Le "Zero Line Cross" est un signal d'achat formé lorsque l'histogramme passe de valeurs négatives à des valeurs positives. Il convient de garder à l'esprit ce qui suit :

    • pour que ce signal soit généré, seules deux barres sont nécessaires ;
    • la première barre doit être en dessous de la ligne zéro, la seconde doit la franchir (passage d'une valeur négative à une valeur positive) ;
    • la génération simultanée de signaux d'achat et de vente est impossible.

    Le "Twin Peaks" est le seul signal d'achat qui peut être généré lorsque les valeurs de l'histogramme sont inférieures à zéro. N'oubliez pas les points suivants :

    • le signal est généré lorsque vous avez un pic pointant vers le bas (le plus bas) qui est en dessous de la ligne zéro et qui est suivi par un autre pic pointant vers le bas qui est un peu plus élevé (un chiffre négatif avec une valeur absolue moindre, qui est donc plus proche de la ligne zéro), que le pic précédent pointant vers le bas ;
    • l'histogramme doit être inférieur à la ligne zéro entre les deux pics. Si le graphique à barres franchit la ligne de zéro dans la section située entre les pics, le signal d'achat ne fonctionne pas. Cependant, un signal d'achat différent sera généré - le croisement de la ligne zéro ;
    • chaque nouveau pic du graphique en barres doit être plus élevé (un nombre négatif d'une valeur absolue inférieure qui est plus proche de la ligne du zéro) que le pic précédent ;
    • si un nouveau pic plus élevé se forme (plus proche de la ligne de zéro) et que le graphique en barres n'a pas franchi la ligne de zéro, un signal d'achat supplémentaire sera généré.

      Signaux de Vente

      Les signaux de vente de l'Awesome Oscillator sont identiques aux signaux d'achat. Le signal Source est inversé car il est inférieur à zéro. Le Zero Line Cross est à la baisse - la première barre est au-dessus de zéro, la seconde en dessous. Le signal des deux pics est plus élevé que la ligne de zéro et est également inversé.



      Paramètres

      La fonction iAO() est utilisée pour créer la poignée de l'indicateur :

      Retourne la poignée de l'indicateur de l'Awesome Oscillator. Un seul buffer.

      int  iAO(
         string           symbol,     // symbol name
         ENUM_TIMEFRAMES  period      // period
         );
      

      symbol

      [in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.

      period

      [in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.

      Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, elle retourne INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.


      Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :

      //+------------------------------------------------------------------+
      //|                                               TestWilliamsAO.mq5 |
      //|                                  Copyright 2023, MetaQuotes Ltd. |
      //|                                             https://www.mql5.com |
      //+------------------------------------------------------------------+
      #property copyright "Copyright 2023, MetaQuotes Ltd."
      #property link      "https://www.mql5.com"
      #property version   "1.00"
      //--- enums
      enum ENUM_LINE_STATE
        {
         LINE_STATE_NONE,        // Undefined state
         LINE_STATE_UP,          // Upward
         LINE_STATE_DOWN,        // Downward
         LINE_STATE_TURN_UP,     // Upward reversal
         LINE_STATE_TURN_DOWN,   // Downward reversal
         LINE_STATE_STOP_UP,     // Upward stop
         LINE_STATE_STOP_DOWN,   // Downward stop
         LINE_STATE_ABOVE,       // Above value
         LINE_STATE_UNDER,       // Below value
         LINE_STATE_CROSS_UP,    // Crossing value upwards
         LINE_STATE_CROSS_DOWN,  // Crossing value downwards
         LINE_STATE_TOUCH_BELOW, // Touching value from below 
         LINE_STATE_TOUCH_ABOVE, // Touch value from above
         LINE_STATE_EQUALS,      // Equal to value
        };
      //--- global variables
      int      handle=INVALID_HANDLE;  // Indicator handle
      int      ind_digits=0;           // Number of decimal places in the indicator values
      string   ind_title;              // Indicator description
      
      

      Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier des classes de tableaux de bord :

      //+------------------------------------------------------------------+
      //|                                               TestWilliamsAO.mq5 |
      //|                                  Copyright 2023, MetaQuotes Ltd. |
      //|                                             https://www.mql5.com |
      //+------------------------------------------------------------------+
      #property copyright "Copyright 2023, MetaQuotes Ltd."
      #property link      "https://www.mql5.com"
      #property version   "1.00"
      //--- includes
      #include <Dashboard\Dashboard.mqh>
      //--- enums
      enum ENUM_LINE_STATE
        {
         LINE_STATE_NONE,        // Undefined state
         LINE_STATE_UP,          // Upward
         LINE_STATE_DOWN,        // Downward
         LINE_STATE_TURN_UP,     // Upward reversal
         LINE_STATE_TURN_DOWN,   // Downward reversal
         LINE_STATE_STOP_UP,     // Upward stop
         LINE_STATE_STOP_DOWN,   // Downward stop
         LINE_STATE_ABOVE,       // Above value
         LINE_STATE_UNDER,       // Below value
         LINE_STATE_CROSS_UP,    // Crossing value upwards
         LINE_STATE_CROSS_DOWN,  // Crossing value downwards
         LINE_STATE_TOUCH_BELOW, // Touching value from below 
         LINE_STATE_TOUCH_ABOVE, // Touch value from above
         LINE_STATE_EQUALS,      // Equal to value
        };
      //--- global variables
      int      handle=INVALID_HANDLE;  // Indicator handle
      int      ind_digits=0;           // Number of decimal places in the indicator values
      string   ind_title;              // Indicator description
      //--- variables for the panel
      int      mouse_bar_index;        // Index of the bar the data is taken from
      CDashboard *panel=NULL;          // Pointer to the panel object
      
      


      Initialisation

      Définition des valeurs des variables globales de l'indicateur et création de son handle :

      //+------------------------------------------------------------------+
      //| Expert initialization function                                   |
      //+------------------------------------------------------------------+
      int OnInit()
        {
      //--- create timer
         EventSetTimer(60);
      
      //--- Indicator
      //--- Set the indicator name and the number of decimal places
         ind_title="AO";
         ind_digits=Digits()+1;
      //--- Create indicator handle
         ResetLastError();
         handle=iAO(Symbol(),PERIOD_CURRENT);
         if(handle==INVALID_HANDLE)
           {
            PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError());
            return INIT_FAILED;
           }
      
      //--- Successful initialization
         return(INIT_SUCCEEDED);
        }
      
      

      Si l'EA implique l'utilisation du tableau de bord, créez-le ici :

      //+------------------------------------------------------------------+
      //| Expert initialization function                                   |
      //+------------------------------------------------------------------+
      int OnInit()
        {
      //--- create timer
         EventSetTimer(60);
      
      //--- Indicator
      //--- Set the indicator name and the number of decimal places
         ind_title="AO";
         ind_digits=Digits()+1;
      //--- Create indicator handle
         ResetLastError();
         handle=iAO(Symbol(),PERIOD_CURRENT);
         if(handle==INVALID_HANDLE)
           {
            PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError());
            return INIT_FAILED;
           }
      
      //--- Dashboard
      //--- Create the panel
         panel=new CDashboard(1,20,20,199,225);
         if(panel==NULL)
           {
            Print("Error. Failed to create panel object");
            return INIT_FAILED;
           }
      //--- Set font parameters
         panel.SetFontParams("Calibri",9);
      //--- Display the panel with the "Symbol, Timeframe description" header text
         panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));
      //--- Create a table with ID 0 to display bar data in it
         panel.CreateNewTable(0);
      //--- Draw a table with ID 0 on the panel background
         panel.DrawGrid(0,2,20,6,2,18,97);
      
      //--- Create a table with ID 1 to display indicator data in it
         panel.CreateNewTable(1);
      //--- Get the Y2 table coordinate with ID 0 and
      //--- set the Y1 coordinate for the table with ID 1
         int y1=panel.TableY2(0)+22;
      //--- Draw a table with ID 1 on the panel background
         panel.DrawGrid(1,2,y1,3,2,18,97);
         
      //--- Display tabular data in the journal
         panel.GridPrint(0,2);
         panel.GridPrint(1,2);
      //--- Initialize the variable with the index of the mouse cursor bar
         mouse_bar_index=0;
      //--- Display the data of the current bar on the panel
         DrawData(mouse_bar_index,TimeCurrent());
      
      //--- Successful initialization
         return(INIT_SUCCEEDED);
        }
      
      


      Dé-initialisation

      Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :

      //+------------------------------------------------------------------+
      //| Expert deinitialization function                                 |
      //+------------------------------------------------------------------+
      void OnDeinit(const int reason)
        {
      //--- destroy timer
         EventKillTimer();
         
      //--- Release handle of the indicator
         ResetLastError();
         if(!IndicatorRelease(handle))
            PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
      //--- Clear all comments on the chart
         Comment("");
        }
      
      

      L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :

      //+------------------------------------------------------------------+
      //| Expert deinitialization function                                 |
      //+------------------------------------------------------------------+
      void OnDeinit(const int reason)
        {
      //--- destroy timer
         EventKillTimer();
         
      //--- Release handle of the indicator
         ResetLastError();
         if(!IndicatorRelease(handle))
            PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
      //--- Clear all comments on the chart
         Comment("");
         
      //--- If the panel object exists, delete it
         if(panel!=NULL)
            delete panel;
        }
      


      Récupération des résultats

      Les fonctions générales permettant d'obtenir des données à l'aide de la poignée de l'indicateur sont présentées ci-dessous. Les fonctions ont été passées en revue dans l'article sur la connexion des oscillateurs aux EA. Les fonctions présentées peuvent être utilisées "telles quelles" dans des programmes personnalisés :

      //+------------------------------------------------------------------+
      //| Return the indicator data on the specified bar                   |
      //+------------------------------------------------------------------+
      double IndicatorValue(const int ind_handle,const int index,const int buffer_num)
        {
         double array[1]={0};
         ResetLastError();
         if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1)
           {
            PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError());
            return EMPTY_VALUE;
           }
         return array[0];
        }
      //+------------------------------------------------------------------+
      //| Return the state of the indicator line                           |
      //+------------------------------------------------------------------+
      ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num)
        {
      //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index
         const double value0=IndicatorValue(ind_handle,index,  buffer_num);
         const double value1=IndicatorValue(ind_handle,index+1,buffer_num);
         const double value2=IndicatorValue(ind_handle,index+2,buffer_num);
      //--- If at least one of the values could not be obtained, return an undefined value 
         if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE)
            return LINE_STATE_NONE;
      //--- Line upward reversal (value2>value1 && value0>value1)
         if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0)
            return LINE_STATE_TURN_UP;
      //--- Line upward direction (value2<=value1 && value0>value1)
         else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0)
            return LINE_STATE_UP;
      //--- Line upward stop (value2<=value1 && value0==value1)
         else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0)
            return LINE_STATE_STOP_UP;
      //--- Line downward reversal (value2<value1 && value0<value1)
         if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0)
            return LINE_STATE_TURN_DOWN;
      //--- Line downward direction (value2>=value1 && value0<value1)
         else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0)
            return LINE_STATE_DOWN;
      //--- Line downward stop (value2>=value1 && value0==value1)
         else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0)
            return LINE_STATE_STOP_DOWN;
      //--- Undefined state
         return LINE_STATE_NONE;
        }
      //+------------------------------------------------------------------+
      //| Return the state of the line relative to the specified level     |
      //+------------------------------------------------------------------+
      ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE)
        {
      //--- Get the values of the indicator line with the shift (0,1) relative to the passed index
         const double value0=IndicatorValue(ind_handle,index,  buffer_num);
         const double value1=IndicatorValue(ind_handle,index+1,buffer_num);
      //--- If at least one of the values could not be obtained, return an undefined value 
         if(value0==EMPTY_VALUE || value1==EMPTY_VALUE)
            return LINE_STATE_NONE;
      //--- Define the second level to compare
         double level=(level1==EMPTY_VALUE ? level0 : level1);
      //--- The line is below the level (value1<level && value0<level0)
         if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0)
            return LINE_STATE_UNDER;
      //--- The line is above the level (value1>level && value0>level0)
         if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0)
            return LINE_STATE_ABOVE;
      //--- The line crossed the level upwards (value1<=level && value0>level0)
         if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0)
            return LINE_STATE_CROSS_UP;
      //--- The line crossed the level downwards (value1>=level && value0<level0)
         if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0)
            return LINE_STATE_CROSS_DOWN;
      //--- The line touched the level from below (value1<level0 && value0==level0)
         if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0)
            return LINE_STATE_TOUCH_BELOW;
      //--- The line touched the level from above (value1>level0 && value0==level0)
         if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0)
            return LINE_STATE_TOUCH_BELOW;
      //--- Line is equal to the level value (value1==level0 && value0==level0)
         if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0)
            return LINE_STATE_EQUALS;
      //--- Undefined state
         return LINE_STATE_NONE;
        }
      //+------------------------------------------------------------------+
      //| Return the indicator line state description                      |
      //+------------------------------------------------------------------+
      string LineStateDescription(const ENUM_LINE_STATE state)
        {
         switch(state)
           {
            case LINE_STATE_UP         :  return "Up";
            case LINE_STATE_STOP_UP    :  return "Stop Up";
            case LINE_STATE_TURN_UP    :  return "Turn Up";
            case LINE_STATE_DOWN       :  return "Down";
            case LINE_STATE_STOP_DOWN  :  return "Stop Down";
            case LINE_STATE_TURN_DOWN  :  return "Turn Down";
            case LINE_STATE_ABOVE      :  return "Above level";
            case LINE_STATE_UNDER      :  return "Under level";
            case LINE_STATE_CROSS_UP   :  return "Crossing Up";
            case LINE_STATE_CROSS_DOWN :  return "Crossing Down";
            case LINE_STATE_TOUCH_BELOW:  return "Touch from Below";
            case LINE_STATE_TOUCH_ABOVE:  return "Touch from Above";
            case LINE_STATE_EQUALS     :  return "Equals";
            default                    :  return "Unknown";
           }
        }
      
      

      Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :

      //+------------------------------------------------------------------+
      //| Display data from the specified timeseries index to the panel    |
      //+------------------------------------------------------------------+
      void DrawData(const int index,const datetime time)
        {
      //--- Declare the variables to receive data in them
         MqlTick  tick={0};
         MqlRates rates[1];
      
      //--- Exit if unable to get the current prices
         if(!SymbolInfoTick(Symbol(),tick))
            return;
      //--- Exit if unable to get the bar data by the specified index
         if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
            return;
      
      //--- Set font parameters for bar and indicator data headers
         int  size=0;
         uint flags=0;
         uint angle=0;
         string name=panel.FontParams(size,flags,angle);
         panel.SetFontParams(name,9,FW_BOLD);
         panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
         panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
      //--- Set font parameters for bar and indicator data
         panel.SetFontParams(name,9);
      
      //--- Display the data of the specified bar in table 0 on the panel
         panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
         panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
         panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
         panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
         panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
         panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);
      
      //--- Display the indicator data from the specified bar on the panel in table 1
         panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
         double value0=IndicatorValue(handle,index,  0);
         double value1=IndicatorValue(handle,index+1,0);
         string value_str=(value0!=EMPTY_VALUE ? DoubleToString(value0,ind_digits) : "");
         color clr=(value0>value1 ? clrGreen : value0<value1 ? clrRed : clrNONE);
         panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,90);
         
      //--- Display a description of the indicator line state
         panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
         ENUM_LINE_STATE state=LineState(handle,index,0);
         panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clr,90);
         
      //--- Display a description of the indicator line state relative to zero
         panel.DrawText("AO vs Zero", panel.CellX(1,2,0)+2, panel.CellY(1,2,0)+2);
         ENUM_LINE_STATE state_zero=LineStateRelative(handle,index,0,0);
         string state_zero_str=
           (
            state_zero==LINE_STATE_ABOVE        ?  "AO > 0"  : 
            state_zero==LINE_STATE_UNDER        ?  "AO < 0"  : 
            state_zero==LINE_STATE_TOUCH_ABOVE  || 
            state_zero==LINE_STATE_TOUCH_BELOW  ?  "Touch"     :
            LineStateDescription(state_zero)
           );
      //--- The label color changes depending on the value of the line relative to the level
         clr=(state_zero==LINE_STATE_CROSS_UP ? clrGreen : state_zero==LINE_STATE_CROSS_DOWN ? clrRed : clrNONE);
         panel.DrawText(state_zero_str,panel.CellX(1,2,1)+2,panel.CellY(1,2,1)+2,clr,90);
         
      //--- Redraw the chart to immediately display all changes on the panel
         ChartRedraw(ChartID());
        }
      
      

      En plus de décrire l'état de la ligne de l’indicateur, qui a la couleur de la barre de l'histogramme située sous le curseur, le panneau affiche l'état de sa position par rapport à zéro. Lorsque la ligne de l'indicateur croise la ligne zéro vers le haut, elle est marquée d'un texte vert, et la direction vers le bas est marquée d'un texte rouge.

      De plus, lors de l'utilisation du tableau de bord, le gestionnaire d'événements du panneau est appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, et les événements pour recevoir l'indice de la barre sous le curseur y sont gérés :

      //+------------------------------------------------------------------+
      //| ChartEvent function                                              |
      //+------------------------------------------------------------------+
      void OnChartEvent(const int id,
                        const long &lparam,
                        const double &dparam,
                        const string &sparam)
        {
      //--- Handling the panel
      //--- Call the panel event handler
         panel.OnChartEvent(id,lparam,dparam,sparam);
      
      //--- If the cursor moves or a click is made on the chart
         if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
           {
            //--- Declare the variables to record time and price coordinates in them
            datetime time=0;
            double price=0;
            int wnd=0;
            //--- If the cursor coordinates are converted to date and time
            if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
              {
               //--- write the bar index where the cursor is located to a global variable
               mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
               //--- Display the bar data under the cursor on the panel 
               DrawData(mouse_bar_index,time);
              }
           }
      
      //--- If we received a custom event, display the appropriate message in the journal
         if(id>CHARTEVENT_CUSTOM)
           {
            //--- Here we can implement handling a click on the close button on the panel
            PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
           }
        }
      
      

      Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :


      Vous pouvez consulter le test TestWilliamsAO.mq5 EA dans les fichiers joints à l'article.


      Fractales

      Tous les marchés se caractérisent par le fait que, la plupart du temps, les prix ne fluctuent pas beaucoup et que les changements de tendance ne sont visibles que sur une courte période (15 à 30%). Les périodes les plus lucratives sont généralement celles où les prix du marché évoluent selon une certaine tendance.

      Une fractale est l'un des 5 indicateurs du système de trading de Bill Williams, qui permet de détecter le bas ou le haut. La définition technique d'une fractale ascendante est une série d'au moins 5 barres successives, dans laquelle il y a 2 barres, avant et après le maximum le plus élevé, qui ont des maximums inférieurs. La figure d'inversion est une série d'au moins 5 barres successives, avec le BAS le plus bas au milieu et deux BAS plus élevés de part et d'autre, ce qui correspond à la fractale de vente. Sur un graphique, les fractales ont les valeurs High et Low, et sont indiquées par des flèches vers le haut ou vers le bas.

      Les signaux de l'indicateur technique Fractales doivent être filtrés à l'aide de l'indicateur technique Alligator. En d'autres termes, vous ne devez pas conclure une transaction d'achat si la fractale est inférieure aux Dents de l'Alligator et vous ne devez pas conclure une transaction de vente si la fractale est supérieure aux Dents de l'Alligator. Une fois que le signal fractal est formé et qu'il est en vigueur, ce qui est déterminé par sa position au-delà des Mâchoires de l'Alligator, il reste un signal jusqu'à ce qu'il soit touché ou jusqu'à l'apparition d'un signal fractal plus récent.



      Paramètres

      La fonction iFractals() est utilisée pour créer la poignée de l'indicateur :

      Retourne la poignée de l'indicateur Fractals.

      int  iFractals(
         string           symbol,     // symbol name
         ENUM_TIMEFRAMES  period      // period
         );
      

      symbol

      [in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.

      period

      [in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.

      Valeur de Retour

      Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, elle retourne INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.

      Index des buffers : 0 - UPPER_LINE, 1 - LOWER_LINE.


      Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :

      //+------------------------------------------------------------------+
      //|                                         TestWilliamsFractals.mq5 |
      //|                                  Copyright 2023, MetaQuotes Ltd. |
      //|                                             https://www.mql5.com |
      //+------------------------------------------------------------------+
      #property copyright "Copyright 2023, MetaQuotes Ltd."
      #property link      "https://www.mql5.com"
      #property version   "1.00"
      //--- global variables
      int      handle=INVALID_HANDLE;  // Indicator handle
      int      ind_digits=0;           // Number of decimal places in the indicator values
      string   ind_title;              // Indicator description
      
      

      Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier des classes de tableaux de bord :

      //+------------------------------------------------------------------+
      //|                                         TestWilliamsFractals.mq5 |
      //|                                  Copyright 2023, MetaQuotes Ltd. |
      //|                                             https://www.mql5.com |
      //+------------------------------------------------------------------+
      #property copyright "Copyright 2023, MetaQuotes Ltd."
      #property link      "https://www.mql5.com"
      #property version   "1.00"
      //--- includes
      #include <Dashboard\Dashboard.mqh>
      //--- global variables
      int      handle=INVALID_HANDLE;  // Indicator handle
      int      ind_digits=0;           // Number of decimal places in the indicator values
      string   ind_title;              // Indicator description
      //--- variables for the panel
      int      mouse_bar_index;        // Index of the bar the data is taken from
      CDashboard *panel=NULL;          // Pointer to the panel object
      
      


      Initialisation

      Définition des valeurs des variables globales de l'indicateur et création de son handle :

      //+------------------------------------------------------------------+
      //| Expert initialization function                                   |
      //+------------------------------------------------------------------+
      int OnInit()
        {
      //--- create timer
         EventSetTimer(60);
      
      //--- Indicator
      //--- Set the indicator name and the number of decimal places
         ind_title="Fractals";
         ind_digits=Digits();
      //--- Create indicator handle
         ResetLastError();
         handle=iFractals(Symbol(),PERIOD_CURRENT);
         if(handle==INVALID_HANDLE)
           {
            PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError());
            return INIT_FAILED;
           }
      
      //--- Successful initialization
         return(INIT_SUCCEEDED);
        }
      
      

      Si l'EA implique l'utilisation du tableau de bord, créez-le ici :

      //+------------------------------------------------------------------+
      //| Expert initialization function                                   |
      //+------------------------------------------------------------------+
      int OnInit()
        {
      //--- create timer
         EventSetTimer(60);
      
      //--- Indicator
      //--- Set the indicator name and the number of decimal places
         ind_title="Fractals";
         ind_digits=Digits();
      //--- Create indicator handle
         ResetLastError();
         handle=iFractals(Symbol(),PERIOD_CURRENT);
         if(handle==INVALID_HANDLE)
           {
            PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError());
            return INIT_FAILED;
           }
      
      //--- Dashboard
      //--- Create the panel
         panel=new CDashboard(1,20,20,199,225);
         if(panel==NULL)
           {
            Print("Error. Failed to create panel object");
            return INIT_FAILED;
           }
      //--- Set font parameters
         panel.SetFontParams("Calibri",9);
      //--- Display the panel with the "Symbol, Timeframe description" header text
         panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));
      //--- Create a table with ID 0 to display bar data in it
         panel.CreateNewTable(0);
      //--- Draw a table with ID 0 on the panel background
         panel.DrawGrid(0,2,20,6,2,18,97);
      
      //--- Create a table with ID 1 to display indicator data in it
         panel.CreateNewTable(1);
      //--- Get the Y2 table coordinate with ID 0 and
      //--- set the Y1 coordinate for the table with ID 1
         int y1=panel.TableY2(0)+22;
      //--- Draw a table with ID 1 on the panel background
         panel.DrawGrid(1,2,y1,3,2,18,97);
         
      //--- Display tabular data in the journal
         panel.GridPrint(0,2);
         panel.GridPrint(1,2);
      //--- Initialize the variable with the index of the mouse cursor bar
         mouse_bar_index=0;
      //--- Display the data of the current bar on the panel
         DrawData(mouse_bar_index,TimeCurrent());
      
      //--- Successful initialization
         return(INIT_SUCCEEDED);
        }
      
      


      Dé-initialisation

      Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :

      //+------------------------------------------------------------------+
      //| Expert deinitialization function                                 |
      //+------------------------------------------------------------------+
      void OnDeinit(const int reason)
        {
      //--- destroy timer
         EventKillTimer();
         
      //--- Release handle of the indicator
         ResetLastError();
         if(!IndicatorRelease(handle))
            PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
      //--- Clear all comments on the chart
         Comment("");
        }
      
      

      L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :

      //+------------------------------------------------------------------+
      //| Expert deinitialization function                                 |
      //+------------------------------------------------------------------+
      void OnDeinit(const int reason)
        {
      //--- destroy timer
         EventKillTimer();
         
      //--- Release handle of the indicator
         ResetLastError();
         if(!IndicatorRelease(handle))
            PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
      //--- Clear all comments on the chart
         Comment("");
         
      //--- If the panel object exists, delete it
         if(panel!=NULL)
            delete panel;
        }
      


      Récupération des résultats

      Les fonctions générales permettant d'obtenir des données à l'aide de la poignée de l'indicateur sont présentées ci-dessous. Les fonctions ont été passées en revue dans l'article sur la connexion des oscillateurs aux EA. Les fonctions présentées peuvent être utilisées "telles quelles" dans des programmes personnalisés :

      //+------------------------------------------------------------------+
      //| Return the indicator data on the specified bar                   |
      //+------------------------------------------------------------------+
      double IndicatorValue(const int ind_handle,const int index,const int buffer_num)
        {
         double array[1]={0};
         ResetLastError();
         if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1)
           {
            PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError());
            return EMPTY_VALUE;
           }
         return array[0];
        }
      //+------------------------------------------------------------------+
      //| Return the state of the indicator line                           |
      //+------------------------------------------------------------------+
      ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num)
        {
      //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index
         const double value0=IndicatorValue(ind_handle,index,  buffer_num);
         const double value1=IndicatorValue(ind_handle,index+1,buffer_num);
         const double value2=IndicatorValue(ind_handle,index+2,buffer_num);
      //--- If at least one of the values could not be obtained, return an undefined value 
         if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE)
            return LINE_STATE_NONE;
      //--- Line upward reversal (value2>value1 && value0>value1)
         if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0)
            return LINE_STATE_TURN_UP;
      //--- Line upward direction (value2<=value1 && value0>value1)
         else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0)
            return LINE_STATE_UP;
      //--- Line upward stop (value2<=value1 && value0==value1)
         else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0)
            return LINE_STATE_STOP_UP;
      //--- Line downward reversal (value2<value1 && value0<value1)
         if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0)
            return LINE_STATE_TURN_DOWN;
      //--- Line downward direction (value2>=value1 && value0<value1)
         else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0)
            return LINE_STATE_DOWN;
      //--- Line downward stop (value2>=value1 && value0==value1)
         else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0)
            return LINE_STATE_STOP_DOWN;
      //--- Undefined state
         return LINE_STATE_NONE;
        }
      //+------------------------------------------------------------------+
      //| Return the state of the line relative to the specified level     |
      //+------------------------------------------------------------------+
      ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE)
        {
      //--- Get the values of the indicator line with the shift (0,1) relative to the passed index
         const double value0=IndicatorValue(ind_handle,index,  buffer_num);
         const double value1=IndicatorValue(ind_handle,index+1,buffer_num);
      //--- If at least one of the values could not be obtained, return an undefined value 
         if(value0==EMPTY_VALUE || value1==EMPTY_VALUE)
            return LINE_STATE_NONE;
      //--- Define the second level to compare
         double level=(level1==EMPTY_VALUE ? level0 : level1);
      //--- The line is below the level (value1<level && value0<level0)
         if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0)
            return LINE_STATE_UNDER;
      //--- The line is above the level (value1>level && value0>level0)
         if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0)
            return LINE_STATE_ABOVE;
      //--- The line crossed the level upwards (value1<=level && value0>level0)
         if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0)
            return LINE_STATE_CROSS_UP;
      //--- The line crossed the level downwards (value1>=level && value0<level0)
         if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0)
            return LINE_STATE_CROSS_DOWN;
      //--- The line touched the level from below (value1<level0 && value0==level0)
         if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0)
            return LINE_STATE_TOUCH_BELOW;
      //--- The line touched the level from above (value1>level0 && value0==level0)
         if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0)
            return LINE_STATE_TOUCH_BELOW;
      //--- Line is equal to the level value (value1==level0 && value0==level0)
         if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0)
            return LINE_STATE_EQUALS;
      //--- Undefined state
         return LINE_STATE_NONE;
        }
      //+------------------------------------------------------------------+
      //| Return the indicator line state description                      |
      //+------------------------------------------------------------------+
      string LineStateDescription(const ENUM_LINE_STATE state)
        {
         switch(state)
           {
            case LINE_STATE_UP         :  return "Up";
            case LINE_STATE_STOP_UP    :  return "Stop Up";
            case LINE_STATE_TURN_UP    :  return "Turn Up";
            case LINE_STATE_DOWN       :  return "Down";
            case LINE_STATE_STOP_DOWN  :  return "Stop Down";
            case LINE_STATE_TURN_DOWN  :  return "Turn Down";
            case LINE_STATE_ABOVE      :  return "Above level";
            case LINE_STATE_UNDER      :  return "Under level";
            case LINE_STATE_CROSS_UP   :  return "Crossing Up";
            case LINE_STATE_CROSS_DOWN :  return "Crossing Down";
            case LINE_STATE_TOUCH_BELOW:  return "Touch from Below";
            case LINE_STATE_TOUCH_ABOVE:  return "Touch from Above";
            case LINE_STATE_EQUALS     :  return "Equals";
            default                    :  return "Unknown";
           }
        }
      
      

      Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :

      //+------------------------------------------------------------------+
      //| Display data from the specified timeseries index to the panel    |
      //+------------------------------------------------------------------+
      void DrawData(const int index,const datetime time)
        {
      //--- Declare the variables to receive data in them
         MqlTick  tick={0};
         MqlRates rates[1];
      
      //--- Exit if unable to get the current prices
         if(!SymbolInfoTick(Symbol(),tick))
            return;
      //--- Exit if unable to get the bar data by the specified index
         if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
            return;
      
      //--- Set font parameters for bar and indicator data headers
         int  size=0;
         uint flags=0;
         uint angle=0;
         string name=panel.FontParams(size,flags,angle);
         panel.SetFontParams(name,9,FW_BOLD);
         panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
         panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
      //--- Set font parameters for bar and indicator data
         panel.SetFontParams(name,9);
      
      //--- Display the data of the specified bar in table 0 on the panel
         panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
         panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
         panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
         panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
         panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
         panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);
      
      //--- Display the indicator data from the specified bar on the panel in table 1 (upper fractal)
         panel.DrawText(ind_title+" Up", panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
         double value0=IndicatorValue(handle,index,UPPER_LINE);
         string value_str0=(value0!=EMPTY_VALUE ? DoubleToString(value0,ind_digits) : " ");
         panel.DrawText(value_str0,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,90);
      
      //--- Display the indicator data from the specified bar on the panel in table 1 (lower fractal)
         panel.DrawText(ind_title+" Down", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
         double value1=IndicatorValue(handle,index,LOWER_LINE);
         string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,ind_digits) : " ");
         panel.DrawText(value_str1,panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,90);
         
      //--- Redraw the chart to immediately display all changes on the panel
         ChartRedraw(ChartID());
        }
      
      

      De plus, lors de l'utilisation du tableau de bord, le gestionnaire d'événements du panneau est appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, et les événements pour recevoir l'indice de la barre sous le curseur y sont gérés :

      //+------------------------------------------------------------------+
      //| ChartEvent function                                              |
      //+------------------------------------------------------------------+
      void OnChartEvent(const int id,
                        const long &lparam,
                        const double &dparam,
                        const string &sparam)
        {
      //--- Handling the panel
      //--- Call the panel event handler
         panel.OnChartEvent(id,lparam,dparam,sparam);
      
      //--- If the cursor moves or a click is made on the chart
         if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
           {
            //--- Declare the variables to record time and price coordinates in them
            datetime time=0;
            double price=0;
            int wnd=0;
            //--- If the cursor coordinates are converted to date and time
            if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
              {
               //--- write the bar index where the cursor is located to a global variable
               mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
               //--- Display the bar data under the cursor on the panel 
               DrawData(mouse_bar_index,time);
              }
           }
      
      //--- If we received a custom event, display the appropriate message in the journal
         if(id>CHARTEVENT_CUSTOM)
           {
            //--- Here we can implement handling a click on the close button on the panel
            PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
           }
        }
      
      

      Après avoir compilé et lancé l'EA sur le graphique, nous pouvons contrôler les valeurs des buffers de l'indicateur sur le tableau de bord :


      Vous pouvez consulter le test TestWilliamsFractals.mq5 EA dans les fichiers joints à l'article.


      Gator Oscillator

      L'Oscillateur Gator est basé sur l’Alligator et indique le degré de convergence/divergence de ses lignes d'équilibre (Moyenne Mobile lissée). L'histogramme du haut représente la différence absolue entre les valeurs des lignes bleues et rouges. L'histogramme du bas est la différence absolue entre les valeurs de la ligne rouge et de la ligne verte, mais avec le signe moins, car l'histogramme est dessiné de haut en bas.


      Paramètres

      La fonction iGator() est utilisée pour créer la poignée de l'indicateur :

      Retourne la poignée de l'indicateur Gator. L'oscillateur montre la différence entre les lignes bleue et rouge de l'Alligator (histogramme supérieur) et la différence entre les lignes rouge et verte (histogramme inférieur).

      int  iGator(
         string              symbol,            // symbol name
         ENUM_TIMEFRAMES     period,            // period
         int                 jaw_period,        // period for calculating jaws
         int                 jaw_shift,         // horizontal shift of jaws
         int                 teeth_period,      // period for calculating teeth
         int                 teeth_shift,       // teeth shift
         int                 lips_period,       // period for calculating lips
         int                 lips_shift,        // horizontal shift of lips 
         ENUM_MA_METHOD      ma_method,         // smoothing type
         ENUM_APPLIED_PRICE  applied_price      // price type or handle
         );
      

      symbol

      [in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.

      period

      [in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.

      jaw_period

      [in] Période de calcul de la moyenne de la ligne bleue (Mâchoire de l’Alligator).

      jaw_shift

      [in] Décalage de la ligne bleue de l'Alligator par rapport au graphique des prix. N'est pas directement lié au décalage visuel de l'histogramme de l'indicateur.

      teeth_period

      [in] Période de calcul de la moyenne de la ligne rouge (Dents de l’Alligator).

      teeth_shift

      [in] Décalage de la ligne rouge de l'Alligator par rapport au graphique des prix. N'est pas directement lié au décalage visuel de l'histogramme de l'indicateur.

      lips_period

      [in] Période de calcul de la moyenne de la ligne verte (Lèvres de l’Alligator).

      lips_shift

      [in] Décalage de la ligne verte de l'Alligator par rapport au graphique des prix. N'est pas directement lié au décalage visuel de l'histogramme de l'indicateur.

      ma_method

      [in] Méthode de calcul de la moyenne. Peut avoir n'importe quelle valeur de l'énumération ENUM_MA_METHOD.

      applied_price

      [in] Le prix appliqué. Une des constantes de prix ENUM_APPLIED_PRICE ou un autre indicateur.

      Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, elle retourne INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.

      Indices des buffers : 0 - UPPER_HISTOGRAM, 1 - couleur du buffer de l'histogramme supérieur, 2 - LOWER_HISTOGRAM, 3 - couleur du buffer de l'histogramme inférieur.


      Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :

      //+------------------------------------------------------------------+
      //|                                            TestWilliamsGator.mq5 |
      //|                                  Copyright 2023, MetaQuotes Ltd. |
      //|                                             https://www.mql5.com |
      //+------------------------------------------------------------------+
      #property copyright "Copyright 2023, MetaQuotes Ltd."
      #property link      "https://www.mql5.com"
      #property version   "1.00"
      //--- enums
      enum ENUM_LINE_STATE
        {
         LINE_STATE_NONE,        // Undefined state
         LINE_STATE_UP,          // Upward
         LINE_STATE_DOWN,        // Downward
         LINE_STATE_TURN_UP,     // Upward reversal
         LINE_STATE_TURN_DOWN,   // Downward reversal
         LINE_STATE_STOP_UP,     // Upward stop
         LINE_STATE_STOP_DOWN,   // Downward stop
         LINE_STATE_ABOVE,       // Above value
         LINE_STATE_UNDER,       // Below value
         LINE_STATE_CROSS_UP,    // Crossing value upwards
         LINE_STATE_CROSS_DOWN,  // Crossing value downwards
         LINE_STATE_TOUCH_BELOW, // Touching value from below 
         LINE_STATE_TOUCH_ABOVE, // Touch value from above
         LINE_STATE_EQUALS,      // Equal to value
        };
      //--- input parameters
      input uint                 InpPeriodJaws  =  13;            /* Jaws Period    */
      input int                  InpShiftJaws   =  8;             /* Jaws Shift     */
      input uint                 InpPeriodTeeth =  8;             /* Teeth Period   */
      input int                  InpShiftTeeth  =  5;             /* Teeth Shift    */
      input uint                 InpPeriodLips  =  5;             /* Lips Period    */
      input int                  InpShiftLips   =  3;             /* Lips Shift     */
      input ENUM_MA_METHOD       InpMethod      =  MODE_SMMA;     /* Smoothed       */
      input ENUM_APPLIED_PRICE   InpAppliedPrice=  PRICE_MEDIAN;  /* Applied Price  */
      //--- global variables
      int      handle=INVALID_HANDLE;  // Indicator handle
      int      period_jaws=0;          // Jaws line calculation period
      int      period_teeth=0;         // Teeth line calculation period
      int      period_lips=0;          // Lips line calculation period
      int      ind_digits=0;           // Number of decimal places in the indicator values
      string   ind_title;              // Indicator description
      
      

      Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier des classes de tableaux de bord :

      //+------------------------------------------------------------------+
      //|                                            TestWilliamsGator.mq5 |
      //|                                  Copyright 2023, MetaQuotes Ltd. |
      //|                                             https://www.mql5.com |
      //+------------------------------------------------------------------+
      #property copyright "Copyright 2023, MetaQuotes Ltd."
      #property link      "https://www.mql5.com"
      #property version   "1.00"
      //--- includes
      #include <Dashboard\Dashboard.mqh>
      //--- enums
      enum ENUM_LINE_STATE
        {
         LINE_STATE_NONE,        // Undefined state
         LINE_STATE_UP,          // Upward
         LINE_STATE_DOWN,        // Downward
         LINE_STATE_TURN_UP,     // Upward reversal
         LINE_STATE_TURN_DOWN,   // Downward reversal
         LINE_STATE_STOP_UP,     // Upward stop
         LINE_STATE_STOP_DOWN,   // Downward stop
         LINE_STATE_ABOVE,       // Above value
         LINE_STATE_UNDER,       // Below value
         LINE_STATE_CROSS_UP,    // Crossing value upwards
         LINE_STATE_CROSS_DOWN,  // Crossing value downwards
         LINE_STATE_TOUCH_BELOW, // Touching value from below 
         LINE_STATE_TOUCH_ABOVE, // Touch value from above
         LINE_STATE_EQUALS,      // Equal to value
        };
      //--- input parameters
      input uint                 InpPeriodJaws  =  13;            /* Jaws Period    */
      input int                  InpShiftJaws   =  8;             /* Jaws Shift     */
      input uint                 InpPeriodTeeth =  8;             /* Teeth Period   */
      input int                  InpShiftTeeth  =  5;             /* Teeth Shift    */
      input uint                 InpPeriodLips  =  5;             /* Lips Period    */
      input int                  InpShiftLips   =  3;             /* Lips Shift     */
      input ENUM_MA_METHOD       InpMethod      =  MODE_SMMA;     /* Smoothed       */
      input ENUM_APPLIED_PRICE   InpAppliedPrice=  PRICE_MEDIAN;  /* Applied Price  */
      //--- global variables
      int      handle=INVALID_HANDLE;  // Indicator handle
      int      period_jaws=0;          // Jaws line calculation period
      int      period_teeth=0;         // Teeth line calculation period
      int      period_lips=0;          // Lips line calculation period
      int      ind_digits=0;           // Number of decimal places in the indicator values
      string   ind_title;              // Indicator description
      //--- variables for the panel
      int      mouse_bar_index;        // Index of the bar the data is taken from
      CDashboard *panel=NULL;          // Pointer to the panel object
      
      


      Initialisation

      Définition des valeurs des variables globales de l'indicateur et création de son handle :

      //+------------------------------------------------------------------+
      //| Expert initialization function                                   |
      //+------------------------------------------------------------------+
      int OnInit()
        {
      //--- create timer
         EventSetTimer(60);
      
      //--- Indicator
      //--- Set and adjust the calculation period if necessary
         period_jaws=int(InpPeriodJaws<1 ? 13 : InpPeriodJaws);
         period_teeth=int(InpPeriodTeeth<1 ? 8 : InpPeriodTeeth);
         period_lips=int(InpPeriodLips<1 ? 5 : InpPeriodLips);
      //--- Set the indicator name and the number of decimal places
         ind_title=StringFormat("Gator(%lu,%lu,%lu)",period_jaws,period_teeth,period_lips);
         ind_digits=Digits()+1;
      //--- Create indicator handle
         ResetLastError();
         handle=iGator(Symbol(),PERIOD_CURRENT,period_jaws,InpShiftJaws,period_teeth,InpShiftTeeth,period_lips,InpShiftLips,InpMethod,InpAppliedPrice);
         if(handle==INVALID_HANDLE)
           {
            PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError());
            return INIT_FAILED;
           }
      
      //--- Successful initialization
         return(INIT_SUCCEEDED);
        }
      
      

      Si l'EA implique l'utilisation du tableau de bord, créez-le ici :

      //+------------------------------------------------------------------+
      //| Expert initialization function                                   |
      //+------------------------------------------------------------------+
      int OnInit()
        {
      //--- create timer
         EventSetTimer(60);
      
      //--- Indicator
      //--- Set and adjust the calculation period if necessary
         period_jaws=int(InpPeriodJaws<1 ? 13 : InpPeriodJaws);
         period_teeth=int(InpPeriodTeeth<1 ? 8 : InpPeriodTeeth);
         period_lips=int(InpPeriodLips<1 ? 5 : InpPeriodLips);
      //--- Set the indicator name and the number of decimal places
         ind_title=StringFormat("Gator(%lu,%lu,%lu)",period_jaws,period_teeth,period_lips);
         ind_digits=Digits()+1;
      //--- Create indicator handle
         ResetLastError();
         handle=iGator(Symbol(),PERIOD_CURRENT,period_jaws,InpShiftJaws,period_teeth,InpShiftTeeth,period_lips,InpShiftLips,InpMethod,InpAppliedPrice);
         if(handle==INVALID_HANDLE)
           {
            PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError());
            return INIT_FAILED;
           }
      
      //--- Dashboard
      //--- Create the panel
         panel=new CDashboard(1,20,20,229,225);
         if(panel==NULL)
           {
            Print("Error. Failed to create panel object");
            return INIT_FAILED;
           }
      //--- Set font parameters
         panel.SetFontParams("Calibri",9);
      //--- Display the panel with the "Symbol, Timeframe description" header text
         panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));
      //--- Create a table with ID 0 to display bar data in it
         panel.CreateNewTable(0);
      //--- Draw a table with ID 0 on the panel background
         panel.DrawGrid(0,2,20,6,2,18,112);
      
      //--- Create a table with ID 1 to display indicator data in it
         panel.CreateNewTable(1);
      //--- Get the Y2 table coordinate with ID 0 and
      //--- set the Y1 coordinate for the table with ID 1
         int y1=panel.TableY2(0)+22;
      //--- Draw a table with ID 1 on the panel background
         panel.DrawGrid(1,2,y1,3,2,18,112);
         
      //--- Display tabular data in the journal
         panel.GridPrint(0,2);
         panel.GridPrint(1,2);
      //--- Initialize the variable with the index of the mouse cursor bar
         mouse_bar_index=0;
      //--- Display the data of the current bar on the panel
         DrawData(mouse_bar_index,TimeCurrent());
      
      //--- Successful initialization
         return(INIT_SUCCEEDED);
        }
      
      


      Dé-initialisation

      Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :

      //+------------------------------------------------------------------+
      //| Expert deinitialization function                                 |
      //+------------------------------------------------------------------+
      void OnDeinit(const int reason)
        {
      //--- destroy timer
         EventKillTimer();
         
      //--- Release handle of the indicator
         ResetLastError();
         if(!IndicatorRelease(handle))
            PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
      //--- Clear all comments on the chart
         Comment("");
        }
      
      

      L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :

      //+------------------------------------------------------------------+
      //| Expert deinitialization function                                 |
      //+------------------------------------------------------------------+
      void OnDeinit(const int reason)
        {
      //--- destroy timer
         EventKillTimer();
         
      //--- Release handle of the indicator
         ResetLastError();
         if(!IndicatorRelease(handle))
            PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
      //--- Clear all comments on the chart
         Comment("");
         
      //--- If the panel object exists, delete it
         if(panel!=NULL)
            delete panel;
        }
      


      Récupération des résultats

      Les fonctions générales permettant d'obtenir des données à l'aide de la poignée de l'indicateur sont présentées ci-dessous. Les fonctions ont été passées en revue dans l'article sur la connexion des oscillateurs aux EA. Les fonctions présentées peuvent être utilisées "telles quelles" dans des programmes personnalisés :

      //+------------------------------------------------------------------+
      //| Return the indicator data on the specified bar                   |
      //+------------------------------------------------------------------+
      double IndicatorValue(const int ind_handle,const int index,const int buffer_num)
        {
         double array[1]={0};
         ResetLastError();
         if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1)
           {
            PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError());
            return EMPTY_VALUE;
           }
         return array[0];
        }
      //+------------------------------------------------------------------+
      //| Return the state of the indicator line                           |
      //+------------------------------------------------------------------+
      ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num)
        {
      //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index
         const double value0=IndicatorValue(ind_handle,index,  buffer_num);
         const double value1=IndicatorValue(ind_handle,index+1,buffer_num);
         const double value2=IndicatorValue(ind_handle,index+2,buffer_num);
      //--- If at least one of the values could not be obtained, return an undefined value 
         if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE)
            return LINE_STATE_NONE;
      //--- Line upward reversal (value2>value1 && value0>value1)
         if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0)
            return LINE_STATE_TURN_UP;
      //--- Line upward direction (value2<=value1 && value0>value1)
         else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0)
            return LINE_STATE_UP;
      //--- Line upward stop (value2<=value1 && value0==value1)
         else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0)
            return LINE_STATE_STOP_UP;
      //--- Line downward reversal (value2<value1 && value0<value1)
         if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0)
            return LINE_STATE_TURN_DOWN;
      //--- Line downward direction (value2>=value1 && value0<value1)
         else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0)
            return LINE_STATE_DOWN;
      //--- Line downward stop (value2>=value1 && value0==value1)
         else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0)
            return LINE_STATE_STOP_DOWN;
      //--- Undefined state
         return LINE_STATE_NONE;
        }
      //+------------------------------------------------------------------+
      //| Return the state of the line relative to the specified level     |
      //+------------------------------------------------------------------+
      ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE)
        {
      //--- Get the values of the indicator line with the shift (0,1) relative to the passed index
         const double value0=IndicatorValue(ind_handle,index,  buffer_num);
         const double value1=IndicatorValue(ind_handle,index+1,buffer_num);
      //--- If at least one of the values could not be obtained, return an undefined value 
         if(value0==EMPTY_VALUE || value1==EMPTY_VALUE)
            return LINE_STATE_NONE;
      //--- Define the second level to compare
         double level=(level1==EMPTY_VALUE ? level0 : level1);
      //--- The line is below the level (value1<level && value0<level0)
         if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0)
            return LINE_STATE_UNDER;
      //--- The line is above the level (value1>level && value0>level0)
         if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0)
            return LINE_STATE_ABOVE;
      //--- The line crossed the level upwards (value1<=level && value0>level0)
         if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0)
            return LINE_STATE_CROSS_UP;
      //--- The line crossed the level downwards (value1>=level && value0<level0)
         if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0)
            return LINE_STATE_CROSS_DOWN;
      //--- The line touched the level from below (value1<level0 && value0==level0)
         if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0)
            return LINE_STATE_TOUCH_BELOW;
      //--- The line touched the level from above (value1>level0 && value0==level0)
         if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0)
            return LINE_STATE_TOUCH_BELOW;
      //--- Line is equal to the level value (value1==level0 && value0==level0)
         if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0)
            return LINE_STATE_EQUALS;
      //--- Undefined state
         return LINE_STATE_NONE;
        }
      //+------------------------------------------------------------------+
      //| Return the indicator line state description                      |
      //+------------------------------------------------------------------+
      string LineStateDescription(const ENUM_LINE_STATE state)
        {
         switch(state)
           {
            case LINE_STATE_UP         :  return "Up";
            case LINE_STATE_STOP_UP    :  return "Stop Up";
            case LINE_STATE_TURN_UP    :  return "Turn Up";
            case LINE_STATE_DOWN       :  return "Down";
            case LINE_STATE_STOP_DOWN  :  return "Stop Down";
            case LINE_STATE_TURN_DOWN  :  return "Turn Down";
            case LINE_STATE_ABOVE      :  return "Above level";
            case LINE_STATE_UNDER      :  return "Under level";
            case LINE_STATE_CROSS_UP   :  return "Crossing Up";
            case LINE_STATE_CROSS_DOWN :  return "Crossing Down";
            case LINE_STATE_TOUCH_BELOW:  return "Touch from Below";
            case LINE_STATE_TOUCH_ABOVE:  return "Touch from Above";
            case LINE_STATE_EQUALS     :  return "Equals";
            default                    :  return "Unknown";
           }
        }
      
      

      Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :

      //+------------------------------------------------------------------+
      //| Display data from the specified timeseries index to the panel    |
      //+------------------------------------------------------------------+
      void DrawData(const int index,const datetime time)
        {
      //--- Declare the variables to receive data in them
         MqlTick  tick={0};
         MqlRates rates[1];
      
      //--- Exit if unable to get the current prices
         if(!SymbolInfoTick(Symbol(),tick))
            return;
      //--- Exit if unable to get the bar data by the specified index
         if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
            return;
      
      //--- Set font parameters for bar and indicator data headers
         int  size=0;
         uint flags=0;
         uint angle=0;
         string name=panel.FontParams(size,flags,angle);
         panel.SetFontParams(name,9,FW_BOLD);
         panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
         panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
      //--- Set font parameters for bar and indicator data
         panel.SetFontParams(name,9);
      
      //--- Display the data of the specified bar in table 0 on the panel
         panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
         panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
         panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
         panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
         panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
         panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);
      
      //--- Get the indicator buffers data
         double value0=IndicatorValue(handle,index,UPPER_HISTOGRAM); // Upper histogram
         double value1=IndicatorValue(handle,index,1);               // Upper histogram color buffer
         double value2=IndicatorValue(handle,index,LOWER_HISTOGRAM); // Lower histogram
         double value3=IndicatorValue(handle,index,3);               // Lower histogram color buffer
         color clr=clrNONE;
      //--- Display the upper histogram data from the specified bar on the panel in table 1
         panel.DrawText(ind_title+" Up", panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
         string value_str=(value0!=EMPTY_VALUE ? DoubleToString(value0,ind_digits) : "");
         clr=(value1>0 ? clrRed : clrGreen);
         panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clr,100);
         
      //--- Display the lower histogram data from the specified bar on the panel in table 1
         panel.DrawText(ind_title+" Down", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
         value_str=(value2!=EMPTY_VALUE ? DoubleToString(value2,ind_digits) : "");
         clr=(value3>0 ? clrRed : clrGreen);
         panel.DrawText(value_str,panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clr,100);
         
      //--- Redraw the chart to immediately display all changes on the panel
         ChartRedraw(ChartID());
        }
      
      

      La couleur du texte décrivant les valeurs des buffers de l’indicateur est égale à la barre correspondante de l'histogramme des indicateurs.

      De plus, lors de l'utilisation du tableau de bord, le gestionnaire d'événements du panneau est appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, et les événements pour recevoir l'indice de la barre sous le curseur y sont gérés :

      //+------------------------------------------------------------------+
      //| ChartEvent function                                              |
      //+------------------------------------------------------------------+
      void OnChartEvent(const int id,
                        const long &lparam,
                        const double &dparam,
                        const string &sparam)
        {
      //--- Handling the panel
      //--- Call the panel event handler
         panel.OnChartEvent(id,lparam,dparam,sparam);
      
      //--- If the cursor moves or a click is made on the chart
         if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
           {
            //--- Declare the variables to record time and price coordinates in them
            datetime time=0;
            double price=0;
            int wnd=0;
            //--- If the cursor coordinates are converted to date and time
            if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
              {
               //--- write the bar index where the cursor is located to a global variable
               mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
               //--- Display the bar data under the cursor on the panel 
               DrawData(mouse_bar_index,time);
              }
           }
      
      //--- If we received a custom event, display the appropriate message in the journal
         if(id>CHARTEVENT_CUSTOM)
           {
            //--- Here we can implement handling a click on the close button on the panel
            PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
           }
        }
      
      

      Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :



      Vous pouvez consulter le test TestWilliamsGator.mq5 EA dans les fichiers joints à l'article.


      Market Facilitation Index

      Le Market Facilitation Index (BW MFI) est l'indicateur qui montre le changement de prix pour un tick. Les valeurs absolues de l'indicateur ne signifient rien en l'état, seules les variations de l'indicateur ont un sens. Bill Williams insiste sur l'interchangeabilité du MFI et du volume :

      • Le Market Facilitation Index augmente et le volume augmente - cela indique que : a) le nombre d'acteurs entrant sur le marché augmente (le volume augmente) b) les nouveaux acteurs entrant ouvrent des positions dans la direction du développement de la barre, c'est-à-dire que le mouvement a commencé et s'accélère.
      • Le Market Facilitation Index baisse et le volume diminue. Cela signifie que les acteurs du marché ne sont plus intéressés.
      • Le Market Facilitation Index augmente, mais le volume diminue. Il est très probable que le marché ne soit pas soutenu par le volume des traders et que le prix varie en raison des spéculations des traders sur le parquet (agents de change et courtiers).
      • Le Market Facilitation Index diminue, mais le volume augmente. Il y a une bataille entre les haussiers et les baissiers, caractérisée par un volume important de ventes et d'achats, mais le prix ne change pas de manière significative puisque les forces sont égales. L'une des parties en présence (acheteurs contre vendeurs) finira par remporter la bataille. Généralement, la rupture d'une telle barre vous permet de savoir si cette barre détermine la poursuite de la tendance ou si elle l'annule. Bill Williams appelle ce type de bar "curtsying".



      Paramètres

      La fonction iBWMFI() est utilisée pour créer la poignée de l'indicateur :

      Renvoie le handle sur l’indicateur Market Facilitation Index. Un seul buffer.

      int  iBWMFI(
         string               symbol,             // symbol name
         ENUM_TIMEFRAMES      period,             // period
         ENUM_APPLIED_VOLUME  applied_volume      // type of volume used for calculations
         );
      

      symbol

      [in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.

      period

      [in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.

      applied_volume

      [in] Volume utilisé. Toute valeur de l'énumération ENUM_APPLIED_VOLUME.

      Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, elle retourne INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.


      Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :

      //+------------------------------------------------------------------+
      //|                                            TestWilliamsBWMFI.mq5 |
      //|                                  Copyright 2023, MetaQuotes Ltd. |
      //|                                             https://www.mql5.com |
      //+------------------------------------------------------------------+
      #property copyright "Copyright 2023, MetaQuotes Ltd."
      #property link      "https://www.mql5.com"
      #property version   "1.00"
      //--- enums
      enum ENUM_LINE_STATE
        {
         LINE_STATE_NONE,        // Undefined state
         LINE_STATE_UP,          // Upward
         LINE_STATE_DOWN,        // Downward
         LINE_STATE_TURN_UP,     // Upward reversal
         LINE_STATE_TURN_DOWN,   // Downward reversal
         LINE_STATE_STOP_UP,     // Upward stop
         LINE_STATE_STOP_DOWN,   // Downward stop
         LINE_STATE_ABOVE,       // Above value
         LINE_STATE_UNDER,       // Below value
         LINE_STATE_CROSS_UP,    // Crossing value upwards
         LINE_STATE_CROSS_DOWN,  // Crossing value downwards
         LINE_STATE_TOUCH_BELOW, // Touching value from below 
         LINE_STATE_TOUCH_ABOVE, // Touch value from above
         LINE_STATE_EQUALS,      // Equal to value
        };
      //--- input parameters
      input ENUM_APPLIED_VOLUME  InpVolume   =  VOLUME_TICK;   /* Applied Volume */
      //--- global variables
      int      handle=INVALID_HANDLE;  // Indicator handle
      int      ind_digits=0;           // Number of decimal places in the indicator values
      string   ind_title;              // Indicator description
      
      

      Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier des classes de tableaux de bord :

      //+------------------------------------------------------------------+
      //|                                            TestWilliamsBWMFI.mq5 |
      //|                                  Copyright 2023, MetaQuotes Ltd. |
      //|                                             https://www.mql5.com |
      //+------------------------------------------------------------------+
      #property copyright "Copyright 2023, MetaQuotes Ltd."
      #property link      "https://www.mql5.com"
      #property version   "1.00"
      //--- includes
      #include <Dashboard\Dashboard.mqh>
      //--- enums
      enum ENUM_LINE_STATE
        {
         LINE_STATE_NONE,        // Undefined state
         LINE_STATE_UP,          // Upward
         LINE_STATE_DOWN,        // Downward
         LINE_STATE_TURN_UP,     // Upward reversal
         LINE_STATE_TURN_DOWN,   // Downward reversal
         LINE_STATE_STOP_UP,     // Upward stop
         LINE_STATE_STOP_DOWN,   // Downward stop
         LINE_STATE_ABOVE,       // Above value
         LINE_STATE_UNDER,       // Below value
         LINE_STATE_CROSS_UP,    // Crossing value upwards
         LINE_STATE_CROSS_DOWN,  // Crossing value downwards
         LINE_STATE_TOUCH_BELOW, // Touching value from below 
         LINE_STATE_TOUCH_ABOVE, // Touch value from above
         LINE_STATE_EQUALS,      // Equal to value
        };
      //--- input parameters
      input ENUM_APPLIED_VOLUME  InpVolume   =  VOLUME_TICK;   /* Applied Volume */
      //--- global variables
      int      handle=INVALID_HANDLE;  // Indicator handle
      int      ind_digits=0;           // Number of decimal places in the indicator values
      string   ind_title;              // Indicator description
      //--- variables for the panel
      int      mouse_bar_index;        // Index of the bar the data is taken from
      CDashboard *panel=NULL;          // Pointer to the panel object
      
      


      Initialisation

      Définition des valeurs des variables globales de l'indicateur et création de son handle :

      //+------------------------------------------------------------------+
      //| Expert initialization function                                   |
      //+------------------------------------------------------------------+
      int OnInit()
        {
      //--- create timer
         EventSetTimer(60);
      
      //--- Indicator
      //--- Set the indicator name and the number of decimal places
         ind_title="BW MFI";
         ind_digits=Digits();
      //--- Create indicator handle
         ResetLastError();
         handle=iBWMFI(Symbol(),PERIOD_CURRENT,InpVolume);
         if(handle==INVALID_HANDLE)
           {
            PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError());
            return INIT_FAILED;
           }
      
      //--- Successful initialization
         return(INIT_SUCCEEDED);
        }
      
      

      Si l'EA implique l'utilisation du tableau de bord, créez-le ici :

      //+------------------------------------------------------------------+
      //| Expert initialization function                                   |
      //+------------------------------------------------------------------+
      int OnInit()
        {
      //--- create timer
         EventSetTimer(60);
      
      //--- Indicator
      //--- Set the indicator name and the number of decimal places
         ind_title="BW MFI";
         ind_digits=Digits();
      //--- Create indicator handle
         ResetLastError();
         handle=iBWMFI(Symbol(),PERIOD_CURRENT,InpVolume);
         if(handle==INVALID_HANDLE)
           {
            PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError());
            return INIT_FAILED;
           }
      
      //--- Dashboard
      //--- Create the panel
         panel=new CDashboard(1,20,20,199,225);
         if(panel==NULL)
           {
            Print("Error. Failed to create panel object");
            return INIT_FAILED;
           }
      //--- Set font parameters
         panel.SetFontParams("Calibri",9);
      //--- Display the panel with the "Symbol, Timeframe description" header text
         panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));
      //--- Create a table with ID 0 to display bar data in it
         panel.CreateNewTable(0);
      //--- Draw a table with ID 0 on the panel background
         panel.DrawGrid(0,2,20,6,2,18,97);
      
      //--- Create a table with ID 1 to display indicator data in it
         panel.CreateNewTable(1);
      //--- Get the Y2 table coordinate with ID 0 and
      //--- set the Y1 coordinate for the table with ID 1
         int y1=panel.TableY2(0)+22;
      //--- Draw a table with ID 1 on the panel background
         panel.DrawGrid(1,2,y1,3,2,18,97);
         
      //--- Display tabular data in the journal
         panel.GridPrint(0,2);
         panel.GridPrint(1,2);
      //--- Initialize the variable with the index of the mouse cursor bar
         mouse_bar_index=0;
      //--- Display the data of the current bar on the panel
         DrawData(mouse_bar_index,TimeCurrent());
      
      //--- Successful initialization
         return(INIT_SUCCEEDED);
        }
      
      


      Dé-initialisation

      Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :

      //+------------------------------------------------------------------+
      //| Expert deinitialization function                                 |
      //+------------------------------------------------------------------+
      void OnDeinit(const int reason)
        {
      //--- destroy timer
         EventKillTimer();
         
      //--- Release handle of the indicator
         ResetLastError();
         if(!IndicatorRelease(handle))
            PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
      //--- Clear all comments on the chart
         Comment("");
        }
      
      

      L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :

      //+------------------------------------------------------------------+
      //| Expert deinitialization function                                 |
      //+------------------------------------------------------------------+
      void OnDeinit(const int reason)
        {
      //--- destroy timer
         EventKillTimer();
         
      //--- Release handle of the indicator
         ResetLastError();
         if(!IndicatorRelease(handle))
            PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
      //--- Clear all comments on the chart
         Comment("");
         
      //--- If the panel object exists, delete it
         if(panel!=NULL)
            delete panel;
        }
      


      Récupération des résultats

      Les fonctions générales permettant d'obtenir des données à l'aide de la poignée de l'indicateur sont présentées ci-dessous. Les fonctions ont été passées en revue dans l'article sur la connexion des oscillateurs aux EA. Les fonctions présentées peuvent être utilisées "telles quelles" dans des programmes personnalisés :

      //+------------------------------------------------------------------+
      //| Return the indicator data on the specified bar                   |
      //+------------------------------------------------------------------+
      double IndicatorValue(const int ind_handle,const int index,const int buffer_num)
        {
         double array[1]={0};
         ResetLastError();
         if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1)
           {
            PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError());
            return EMPTY_VALUE;
           }
         return array[0];
        }
      //+------------------------------------------------------------------+
      //| Return the state of the indicator line                           |
      //+------------------------------------------------------------------+
      ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num)
        {
      //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index
         const double value0=IndicatorValue(ind_handle,index,  buffer_num);
         const double value1=IndicatorValue(ind_handle,index+1,buffer_num);
         const double value2=IndicatorValue(ind_handle,index+2,buffer_num);
      //--- If at least one of the values could not be obtained, return an undefined value 
         if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE)
            return LINE_STATE_NONE;
      //--- Line upward reversal (value2>value1 && value0>value1)
         if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0)
            return LINE_STATE_TURN_UP;
      //--- Line upward direction (value2<=value1 && value0>value1)
         else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0)
            return LINE_STATE_UP;
      //--- Line upward stop (value2<=value1 && value0==value1)
         else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0)
            return LINE_STATE_STOP_UP;
      //--- Line downward reversal (value2<value1 && value0<value1)
         if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0)
            return LINE_STATE_TURN_DOWN;
      //--- Line downward direction (value2>=value1 && value0<value1)
         else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0)
            return LINE_STATE_DOWN;
      //--- Line downward stop (value2>=value1 && value0==value1)
         else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0)
            return LINE_STATE_STOP_DOWN;
      //--- Undefined state
         return LINE_STATE_NONE;
        }
      //+------------------------------------------------------------------+
      //| Return the state of the line relative to the specified level     |
      //+------------------------------------------------------------------+
      ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE)
        {
      //--- Get the values of the indicator line with the shift (0,1) relative to the passed index
         const double value0=IndicatorValue(ind_handle,index,  buffer_num);
         const double value1=IndicatorValue(ind_handle,index+1,buffer_num);
      //--- If at least one of the values could not be obtained, return an undefined value 
         if(value0==EMPTY_VALUE || value1==EMPTY_VALUE)
            return LINE_STATE_NONE;
      //--- Define the second level to compare
         double level=(level1==EMPTY_VALUE ? level0 : level1);
      //--- The line is below the level (value1<level && value0<level0)
         if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0)
            return LINE_STATE_UNDER;
      //--- The line is above the level (value1>level && value0>level0)
         if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0)
            return LINE_STATE_ABOVE;
      //--- The line crossed the level upwards (value1<=level && value0>level0)
         if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0)
            return LINE_STATE_CROSS_UP;
      //--- The line crossed the level downwards (value1>=level && value0<level0)
         if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0)
            return LINE_STATE_CROSS_DOWN;
      //--- The line touched the level from below (value1<level0 && value0==level0)
         if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0)
            return LINE_STATE_TOUCH_BELOW;
      //--- The line touched the level from above (value1>level0 && value0==level0)
         if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0)
            return LINE_STATE_TOUCH_BELOW;
      //--- Line is equal to the level value (value1==level0 && value0==level0)
         if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0)
            return LINE_STATE_EQUALS;
      //--- Undefined state
         return LINE_STATE_NONE;
        }
      //+------------------------------------------------------------------+
      //| Return the indicator line state description                      |
      //+------------------------------------------------------------------+
      string LineStateDescription(const ENUM_LINE_STATE state)
        {
         switch(state)
           {
            case LINE_STATE_UP         :  return "Up";
            case LINE_STATE_STOP_UP    :  return "Stop Up";
            case LINE_STATE_TURN_UP    :  return "Turn Up";
            case LINE_STATE_DOWN       :  return "Down";
            case LINE_STATE_STOP_DOWN  :  return "Stop Down";
            case LINE_STATE_TURN_DOWN  :  return "Turn Down";
            case LINE_STATE_ABOVE      :  return "Above level";
            case LINE_STATE_UNDER      :  return "Under level";
            case LINE_STATE_CROSS_UP   :  return "Crossing Up";
            case LINE_STATE_CROSS_DOWN :  return "Crossing Down";
            case LINE_STATE_TOUCH_BELOW:  return "Touch from Below";
            case LINE_STATE_TOUCH_ABOVE:  return "Touch from Above";
            case LINE_STATE_EQUALS     :  return "Equals";
            default                    :  return "Unknown";
           }
        }
      
      

      Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :

      //+------------------------------------------------------------------+
      //| Display data from the specified timeseries index to the panel    |
      //+------------------------------------------------------------------+
      void DrawData(const int index,const datetime time)
        {
      //--- Declare the variables to receive data in them
         MqlTick  tick={0};
         MqlRates rates[1];
      
      //--- Exit if unable to get the current prices
         if(!SymbolInfoTick(Symbol(),tick))
            return;
      //--- Exit if unable to get the bar data by the specified index
         if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
            return;
      
      //--- Set font parameters for bar and indicator data headers
         int  size=0;
         uint flags=0;
         uint angle=0;
         string name=panel.FontParams(size,flags,angle);
         panel.SetFontParams(name,9,FW_BOLD);
         panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
         panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
      //--- Set font parameters for bar and indicator data
         panel.SetFontParams(name,9);
      
      //--- Display the data of the specified bar in table 0 on the panel
         panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
         panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
         panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
         panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
         panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
         panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);
      
      //--- Display the indicator data from the specified bar on the panel in table 1
         panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
         double value=IndicatorValue(handle,index,0);
         string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : "");
         panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,90);
         
      //--- Create Volumes indicator handle
         static bool create=false;
         static int hv=INVALID_HANDLE;
         if(!create)
           {
            ResetLastError();
            hv=iVolumes(Symbol(),PERIOD_CURRENT,InpVolume);
            if(hv==INVALID_HANDLE)
              {
               PrintFormat("%s: Failed to create indicator handle Volumes. Error %ld",__FUNCTION__,GetLastError());
               return;
              }
            create=true;
           }
      
      //--- Get Volumes indicator status
         ENUM_LINE_STATE state_vol=LineState(hv,index,0);
      //--- Display a description of the indicator line state
         panel.DrawText("BW MFI State", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
         ENUM_LINE_STATE state=LineState(handle,index,0);
         color clr=clrNONE;
         string state_str=LineStateDescription(state);
         if((state==LINE_STATE_UP || state==LINE_STATE_TURN_UP) && (state_vol==LINE_STATE_UP || state_vol==LINE_STATE_TURN_UP))
           {
            state_str="MFI Up, Vol Up";
            clr=clrGreen;
           }
         if((state==LINE_STATE_DOWN || state==LINE_STATE_TURN_DOWN) && (state_vol==LINE_STATE_DOWN || state_vol==LINE_STATE_TURN_DOWN))
           {
            state_str="MFI Dn, Vol Dn";
            clr=clrSaddleBrown;
           }
         if((state==LINE_STATE_UP || state==LINE_STATE_TURN_UP) && (state_vol==LINE_STATE_DOWN || state_vol==LINE_STATE_TURN_DOWN))
           {
            state_str="MFI Up, Vol Dn";
            clr=clrBlue;
           }
         if((state==LINE_STATE_DOWN || state==LINE_STATE_TURN_DOWN) && (state_vol==LINE_STATE_UP || state_vol==LINE_STATE_TURN_UP))
           {
            state_str="MFI Dn, Vol Up";
            clr=clrLightCoral;
           }
      
      //--- Set font parameters for indicator state data (bold font)
         name=panel.FontParams(size,flags,angle);
         panel.SetFontParams(name,9,FW_BOLD);
         panel.DrawText(state_str,panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clr,90);
      //--- Restore the normal thickness of the panel font
         panel.SetFontParams(name,9);
         
      //--- Redraw the chart to immediately display all changes on the panel
         ChartRedraw(ChartID());
        }
      
      

      Il est possible d'obtenir les données de l'indicateur BW MFI de la manière habituelle - par le biais des fonctions universelles fournies ici. En effet, pour colorer les barres de l'histogramme, deux indicateurs sont comparés : la valeur de la barre de l'histogramme et la valeur du volume par rapport à leurs valeurs précédentes. Pour obtenir le volume dans la fonction, créez un handle d'indicateur Volumes (une fois lors du premier accès) et comparez les états des lignes BW MFI et Volumes. Une description de leur relation mutuelle est affichée sur le panneau sous forme de texte.

      De plus, lors de l'utilisation du tableau de bord, le gestionnaire d'événements du panneau est appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, et les événements pour recevoir l'indice de la barre sous le curseur y sont gérés :

      //+------------------------------------------------------------------+
      //| ChartEvent function                                              |
      //+------------------------------------------------------------------+
      void OnChartEvent(const int id,
                        const long &lparam,
                        const double &dparam,
                        const string &sparam)
        {
      //--- Handling the panel
      //--- Call the panel event handler
         panel.OnChartEvent(id,lparam,dparam,sparam);
      
      //--- If the cursor moves or a click is made on the chart
         if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
           {
            //--- Declare the variables to record time and price coordinates in them
            datetime time=0;
            double price=0;
            int wnd=0;
            //--- If the cursor coordinates are converted to date and time
            if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
              {
               //--- write the bar index where the cursor is located to a global variable
               mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
               //--- Display the bar data under the cursor on the panel 
               DrawData(mouse_bar_index,time);
              }
           }
      
      //--- If we received a custom event, display the appropriate message in the journal
         if(id>CHARTEVENT_CUSTOM)
           {
            //--- Here we can implement handling a click on the close button on the panel
            PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
           }
        }
      
      

      Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :

      Vous pouvez consulter le test TestWilliamsBWMFI.mq5 EA dans les fichiers joints à l'article.


      Raffinement des classes de tableaux de bord :

      Dans les EA de tests de cette série, nous utilisons le tableau de bord créé dans le premier article. Il était possible de créer un tableau dans le panel. Les coordonnées du tableau peuvent être utilisées pour afficher des données sur le tableau de bord. Les classes de tableaux de bord ont été finalisées. Vous pouvez créer un nombre illimité de tableaux pour y placer des données. J'ai également corrigé la disparition temporaire des données du tableau de bord après avoir réduit le tableau de bord, changé de période et développé à nouveau le tableau de bord. Passons brièvement en revue les changements apportés afin de ne pas revenir sur les changements apportés aux classes du tableau de bord.

      Désormais, chaque tableau créé sur le panneau peut renvoyer ses coordonnées : X1, Y1 - coin supérieur gauche, X2 et Y2 - coin inférieur droit. Chaque plaque se voit attribuer son propre identifiant et son propre nom, ce qui permet d'y accéder pour obtenir des données.

      La classe de données tabulaires CTableData comporte désormais des variables privées et des méthodes publiques pour écrire et renvoyer ces valeurs :

      //+------------------------------------------------------------------+
      //| Table data class                                                 |
      //+------------------------------------------------------------------+
      class CTableData : public CObject
        {
      private:
         CArrayObj         m_list_rows;               // List of rows
         uint              m_id;                      // Table ID
         int               m_x1;                      // X1 coordinate
         int               m_y1;                      // Y1 coordinate
         int               m_x2;                      // X2 coordinate
         int               m_y2;                      // Y2 coordinate
         int               m_w;                       // Width
         int               m_h;                       // Height
         string            m_name;                    // Table name
      public:
      //--- Set table name
         void              SetName(const string name) { this.m_name=name;              }
      //--- Return table (1) ID and (2) name
         uint              ID(void)             const { return this.m_id;              }
         string            Name(void)           const { return this.m_name;            }
         
      //--- Set coordinate (1) X1, (2) X2
         void              SetX1(const uint x1)       { this.m_x1=(int)x1;             }
         void              SetX2(const uint x2)       { this.m_x2=(int)x2;             }
      //--- Set coordinate (1) Y1, (2) Y2
         void              SetY1(const uint y1)       { this.m_y1=(int)y1;             }
         void              SetY2(const uint y2)       { this.m_y2=(int)y2;             }
      //--- Set table coordinates
         void              SetCoords(const int x1,const int y1,const int x2,const int y2)
                             {
                              this.SetX1(x1);
                              this.SetY1(y1);
                              this.SetX2(x2);
                              this.SetY2(y2);
                             }
         
      //--- Return coordinate (1) X1, (2) X2
         int               X1(void)             const { return this.m_x1;              }
         int               X2(void)             const { return this.m_x2;              }
      //--- Return coordinate (1) Y1, (2) Y2
         int               Y1(void)             const { return this.m_y1;              }
         int               Y2(void)             const { return this.m_y2;              }
         
      //--- Return (1) width and (2) height
         int               Width(void)          const { return this.m_x2-this.m_x1+1;  }
         int               Height(void)         const { return this.m_y2-this.m_y1+1;  }
         
      //--- Return the list of table rows
      

      Ajout d'une méthode publique qui renvoie le nombre de cellules dans la ligne spécifiée :

         int               ColumnsInRow(const int row_index)
                             {
                              //--- If there is no row in the list, return 0
                              if(this.RowsTotal()==0)
                                 return 0;
                              //--- Get a pointer to the specified row and return the number of cells in it
                              CTableRow *row=this.GetRow(row_index);
                              return(row!=NULL ? row.CellsTotal() : 0);
                             }
      //--- Return the total number of cells in the table
      

      Ajout d'une méthode publique qui renvoie le nombre total de cellules du tableau :

      //--- Return the total number of cells in the table
         int               CellsTotal(void)
                             {
                              //--- If there is no row in the list, return 0
                              if(this.RowsTotal()==0)
                                 return 0;
                              //---
                              int num=0;
                              int total=this.RowsTotal();
                              for(int i=0;i<total;i++)
                                 num+=this.ColumnsInRow(i);
                              return num;
                             }
      //--- Clear lists of rows and table cells
      

      Auparavant, nous renvoyions simplement le nombre de colonnes dans la première ligne du tableau en espérant que leur nombre soit le même dans chaque ligne. Nous pouvons maintenant obtenir le nombre total de cellules du tableau - par le nombre de cellules placées dans chaque ligne du tableau. Nous pouvons également obtenir un nombre de cellules dans une ligne donnée. Il est donc possible de créer des tableaux sans treillis. La création de tableaux avec différents nombres de cellules dans les lignes n'a pas été testée en raison de l'absence de demande dans les tâches actuelles. Il est très probable que des améliorations supplémentaires soient nécessaires. Mais pour l'instant, ces tableaux ne sont pas nécessaires.

      La classe comprend la méthode virtuelle Compare qui permet de comparer les tables par ID (mode = 0) ou par nom (mode != 0) :

      //--- Virtual method for comparing two objects
         virtual int       Compare(const CObject *node,const int mode=0) const
                             {
                              const CTableData *compared=node;
                              if(mode==0)
                                 return(this.ID()>compared.ID() ? 1 : this.ID()<compared.ID() ? -1 : 0);
                              else
                                 return(this.Name()==compared.Name() ? 0 : this.Name()>compared.Name() ? 1 : -1);
                             }
      

      L'ID de la table créée est maintenant transmis au constructeur paramétrique de la classe :

      //--- Constructor/destructor
                           CTableData(const uint id) : m_id(id){ this.m_list_rows.Clear(); this.m_name="";  }
                          ~CTableData(void)                    { this.m_list_rows.Clear();                  }
      


      Alors que l'instance de l'objet de données tabulaires était précédemment déclarée dans la classe du tableau, maintenant nous déclarons la liste pour contenir des pointeurs vers les tableaux créés dans le panneau.

      //+------------------------------------------------------------------+
      //| Dashboard class                                                  |
      //+------------------------------------------------------------------+
      class CDashboard : public CObject
        {
      private:
         CCanvas           m_canvas;                  // Canvas
         CCanvas           m_workspace;               // Work space
         CArrayObj         m_list_table;              // List of tables
         ENUM_PROGRAM_TYPE m_program_type;            // Program type
         ENUM_MOUSE_STATE  m_mouse_state;             // Mouse button status
      

      Déclarez les variables permettant de créer des noms de fichiers pour enregistrer les pixels de l'arrière-plan et de la zone de travail dans un fichier de la section privée :

         string            m_name_gv_m;               // Name of the global terminal variable storing the collapsed panel flag 
      
         string            m_name_gv_u;               // Name of the global terminal variable storing the flag of the pinned panel 
         string            m_filename_bg;             // File name to save background pixels 
         string            m_filename_ws;             // File name for saving work space pixels
         
         uint              m_array_wpx[];             // Array of pixels to save/restore the workspace 
         uint              m_array_ppx[];             // Array of pixels to save/restore the panel background 
      

      Ajout et amélioration des méthodes pour travailler avec les polices de caractères du panneau, ainsi que pour créer et obtenir des tableaux et leurs coordonnées :

      //--- Set default panel font parameters
         void              SetFontParams(const string name,const int size,const uint flags=0,const uint angle=0);
      //--- Return the specified dashboard font parameters
         string            FontParams(int &size,uint &flags,uint &angle);
      //--- Return the specified panel (1) font, (2) size and font flags
         string            FontName(void)    const { return this.m_workspace.FontNameGet();  }
         int               FontSize(void)    const { return this.m_workspace.FontSizeGet();  }
         uint              FontFlags(void)   const { return this.m_workspace.FontFlagsGet(); }
      //--- Display a text message at the specified coordinates
         void              DrawText(const string text,const int x,const int y,const color clr=clrNONE,const int width=WRONG_VALUE,const int height=WRONG_VALUE);
      //--- Create a new table
         bool              CreateNewTable(const int id=WRONG_VALUE);
      //--- Return tabular data object by (1) ID and (2) name
         CTableData       *GetTable(const uint id);
         CTableData       *GetTable(const string name);
      //--- Draw a (1) background grid (2) with automatic cell size
         void              DrawGrid(const uint table_id,const uint x,const uint y,const uint rows,const uint columns,const uint row_size,const uint col_size,const color line_color=clrNONE,bool alternating_color=true);
         void              DrawGridAutoFill(const uint table_id,const uint border,const uint rows,const uint columns,const color line_color=clrNONE,bool alternating_color=true);
      //--- Print grid data (line intersection coordinates)
         void              GridPrint(const uint table_id,const uint indent=0)
                             {
                              CTableData *table=this.GetTable(table_id);
                              if(table==NULL)
                                {
                                 ::PrintFormat("%s: Error. Failed to get table object with id %lu",__FUNCTION__,table_id);
                                 return;
                                }
                              table.Print(indent);
                             }
      //--- Write the X and Y coordinate values of the specified table cell to variables
         void              CellXY(const uint table_id,const uint row,const uint column, int &x, int &y)
                             {
                              CTableData *table=this.GetTable(table_id);
                              if(table==NULL)
                                {
                                 ::PrintFormat("%s: Error. Failed to get table object with id %lu",__FUNCTION__,table_id);
                                 return;
                                }
                              table.CellXY(row,column,x,y);
                             }
      //--- Return the (1) X and (2) Y coordinate of the specified table cell
         int               CellX(const uint table_id,const uint row,const uint column)
                             {
                              CTableData *table=this.GetTable(table_id);
                              if(table==NULL)
                                {
                                 ::PrintFormat("%s: Error. Failed to get table object with id %lu",__FUNCTION__,table_id);
                                 return WRONG_VALUE;
                                }
                              return table.CellX(row,column);
                             }
         int               CellY(const uint table_id,const uint row,const uint column)
                             {
                              CTableData *table=this.GetTable(table_id);
                              if(table==NULL)
                                {
                                 ::PrintFormat("%s: Error. Failed to get table object with id %lu",__FUNCTION__,table_id);
                                 return WRONG_VALUE;
                                }
                              return table.CellY(row,column);
                             }
      //--- Write X1 and Y1, X2 and Y2 coordinate values of the specified table to the variables
         void              TableCoords(const uint table_id,int &x1,int &y1,int &x2,int &y2)
                             {
                              x1=y1=x2=y2=WRONG_VALUE;
                              CTableData *table=this.GetTable(table_id);
                              if(table==NULL)
                                 return;
                              x1=table.X1();
                              y1=table.Y1();
                              x2=table.X2();
                              y2=table.Y2();
                             }
      
      //--- Return the (1) X1, (2) Y1, (3) X2 and (4) Y2 coordinate of the specified table
         int               TableX1(const uint table_id)
                             {
                              CTableData *table=this.GetTable(table_id);
                              return(table!=NULL ? table.X1() : WRONG_VALUE);
                             }
         int               TableY1(const uint table_id)
                             {
                              CTableData *table=this.GetTable(table_id);
                              return(table!=NULL ? table.Y1() : WRONG_VALUE);
                             }
         int               TableX2(const uint table_id)
                             {
                              CTableData *table=this.GetTable(table_id);
                              return(table!=NULL ? table.X2() : WRONG_VALUE);
                             }
         int               TableY2(const uint table_id)
                             {
                              CTableData *table=this.GetTable(table_id);
                              return(table!=NULL ? table.Y2() : WRONG_VALUE);
                             }
      
      //--- Event handler
         void              OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
      //--- Constructor/destructor
                           CDashboard(const uint id,const int x,const int y, const int w,const int h,const int wnd=-1);
                          ~CDashboard();
      


      Dans le constructeur de la classe, créez des noms de fichiers pour enregistrer l'arrière-plan et l'espace de travail :

      //--- Set the names of global terminal variables to store panel coordinates, collapsed/expanded state and pinning
         this.m_name_gv_x=this.m_program_name+"_id_"+(string)this.m_id+"_"+(string)this.m_chart_id+"_X";
         this.m_name_gv_y=this.m_program_name+"_id_"+(string)this.m_id+"_"+(string)this.m_chart_id+"_Y";
         this.m_name_gv_m=this.m_program_name+"_id_"+(string)this.m_id+"_"+(string)this.m_chart_id+"_Minimize";
         this.m_name_gv_u=this.m_program_name+"_id_"+(string)this.m_id+"_"+(string)this.m_chart_id+"_Unpin";
      
      //--- Set file names for saving background and work space pixels
         this.m_filename_bg=this.m_program_name+"\\Dashboard"+(string)this.m_id+"\\background.bin";
         this.m_filename_ws=this.m_program_name+"\\Dashboard"+(string)this.m_id+"\\workspace.bin";
         
      

      À la toute fin du constructeur, si le panneau est fermé ou réduit, les données des fichiers sont chargées dans les tableaux de pixels de l'arrière-plan et de l'espace de travail :

      //--- If the panel collapse flag is set, load the background and work space pixels from the files into arrays
         if(this.m_minimized)
           {
            if(::FileIsExist(this.m_filename_bg))
               this.FileLoadBackground();
            if(::FileIsExist(this.m_filename_ws))
               this.FileLoadWorkspace();
           }
        }
      

      Ainsi, si les pixels ont été précédemment enregistrés dans des fichiers et que le panneau est créé dans une forme réduite, l'apparence du panneau est chargée à partir des fichiers et le panneau est dessiné dans une forme réduite. Lorsqu'il est développé, son apparence est obtenue à partir des tableaux de pixels remplis dans les fichiers.

      Dans le destructeur, si le panneau est réduit, avant de supprimer les objets du panneau, nous devons le développer, écrire les données des pixels dans les fichiers et le réduire à nouveau. Après cela, nous pouvons supprimer les objets du panneau - leur apparence est déjà sauvegardée dans les fichiers pour être restaurée lors de la création ultérieure dans le constructeur :

      //+------------------------------------------------------------------+
      //| Destructor                                                       |
      //+------------------------------------------------------------------+
      CDashboard::~CDashboard()
        {
      //--- Write the current values to global terminal variables
         ::GlobalVariableSet(this.m_name_gv_x,this.m_x);
         ::GlobalVariableSet(this.m_name_gv_y,this.m_y);
         ::GlobalVariableSet(this.m_name_gv_m,this.m_minimized);
         ::GlobalVariableSet(this.m_name_gv_u,this.m_movable);
      
      //--- If the panel is collapsed,
      //--- expand the panel, save the appearance into pixel arrays and collapse the panel
         if(this.m_minimized)
           {
            this.Expand();
            this.SaveBackground();
            this.SaveWorkspace();
            this.Collapse();
           }
      //--- otherwise, if the panel is expanded,
      //--- save the appearance into pixel arrays
         else
           {
            this.SaveBackground();
            this.SaveWorkspace();
           }
      //--- Save pixel arrays to files
         this.FileSaveBackground();
         this.FileSaveWorkspace();
      
      //--- Delete panel objects
         this.m_canvas.Destroy();
         this.m_workspace.Destroy();
        }
      


      Dans le bloc de gestion des clics sur le bouton minimiser/maximiser du panneau, cochez le drapeau et enregistrez l'arrière-plan et l'espace de travail dans des tableaux de pixels si le panneau est développé :

            //--- If the panel collapse/expand button is pressed 
            else if(state==MOUSE_STATE_PRESSED_INSIDE_MINIMIZE)
              {
               //--- Disable chart scrolling, right-click menu and crosshair
               this.SetChartsTool(false);
               //--- If the panel is not collapsed, save the background and work space into pixel arrays 
               if(!this.m_minimized)
                 {
                  this.SaveWorkspace();
                  this.SaveBackground();
                 }
               //--- "flip" the panel collapse flag,
               this.m_minimized=!this.m_minimized;
               //--- redraw the panel taking into account the new state of the flag,
               this.Draw(this.m_title);
               //--- redraw the panel header area 
               this.RedrawHeaderArea();
               //--- If the panel is pinned and expanded, move it to the stored location coordinates
               if(this.m_minimized && !this.m_movable)
                  this.Move(this.m_x_dock,this.m_y_dock);
               //--- Update the canvas with chart redrawing and
               this.m_canvas.Update();
               //--- write the state of the panel expand flag to the global terminal variable
               ::GlobalVariableSet(this.m_name_gv_m,this.m_minimized);
              }
      


      Les chaînes de caractères permettant d'enregistrer le tableau de pixels ont été supprimées de la méthode de réduction des panneaux. Désormais, l'enregistrement des pixels ne se fait que lorsque l'on appuie sur le bouton pour minimiser/maximiser :

      //+------------------------------------------------------------------+
      //| Collapse the panel                                               |
      //+------------------------------------------------------------------+
      void CDashboard::Collapse(void)
        {
      //--- Save the pixels of the working space and the panel background into arrays
         this.SaveWorkspace();
         this.SaveBackground();
      //--- Remember the current height of the panel
         int h=this.m_h;
      //--- Change the dimensions (height) of the canvas and working space
         if(!this.SetSizes(this.m_canvas.Width(),this.m_header_h))
            return;
      //--- Draw the header area
         this.DrawHeaderArea(this.m_title);
      //--- Return the saved panel height to the variable
         this.m_h=h;
        }
      


      Mise en œuvre d'une méthode qui renvoie l'ensemble des paramètres de la police de caractères du tableau de bord :

      //+------------------------------------------------------------------+
      //| Return the specified dashboard font parameters                   |
      //+------------------------------------------------------------------+
      string CDashboard::FontParams(int &size,uint &flags,uint &angle)
        {
         size=this.m_workspace.FontSizeGet();
         flags=this.m_workspace.FontFlagsGet();
         angle=this.m_workspace.FontAngleGet();
         return this.m_workspace.FontNameGet();
        }
      

      La méthode renvoie le nom de la police de caractères. La taille de la police, ses drapeaux et son angle sont inscrits dans les variables transmises par le lien.

      La couleur du texte est désormais également transmise à la méthode de dessin. La valeur par défaut est clrNONE, c'est-à-dire la couleur de texte précédemment définie :

      //+------------------------------------------------------------------+
      //| Display a text message at the specified coordinates              |
      //+------------------------------------------------------------------+
      void CDashboard::DrawText(const string text,const int x,const int y,const color clr=clrNONE,const int width=WRONG_VALUE,const int height=WRONG_VALUE)
        {
      //--- Declare variables to record the text width and height in them
         int w=width;
         int h=height;
      //--- If the width and height of the text passed to the method have zero values,
      //--- then the entire working space is completely cleared using the transparent color
         if(width==0 && height==0)
            this.m_workspace.Erase(0x00FFFFFF);
      //--- Otherwise
         else
           {
            //--- If the passed width and height have default values (-1), we get its width and height from the text 
            if(width==WRONG_VALUE && height==WRONG_VALUE)
               this.m_workspace.TextSize(text,w,h);
            //--- otherwise,
            else
              {
               //--- if the width passed to the method has the default value (-1) - get the width from the text, or
               //--- if the width passed to the method has a value greater than zero, use the width passed to the method, or
               //--- if the width passed to the method has a zero value, use the value 1 for the width
               w=(width ==WRONG_VALUE ? this.m_workspace.TextWidth(text)  : width>0  ? width  : 1);
               //--- if the height passed to the method has a default value (-1), get the height from the text, or
               //--- if the height passed to the method has a value greater than zero, use the height passed to the method, or
               //--- if the height passed to the method has a zero value, use value 1 for the height
               h=(height==WRONG_VALUE ? this.m_workspace.TextHeight(text) : height>0 ? height : 1);
              }
            //--- Fill the space according to the specified coordinates and the resulting width and height with a transparent color (erase the previous entry)
            this.m_workspace.FillRectangle(x,y,x+w,y+h,0x00FFFFFF);
           }
      //--- Display the text to the space cleared of previous text and update the working space without redrawing the screen
         this.m_workspace.TextOut(x,y,text,::ColorToARGB(clr==clrNONE ? this.m_fore_color : clr));
         this.m_workspace.Update(false);
        }
      


      Mise en œuvre de méthodes permettant de créer une nouvelle table et d'obtenir des données tabulaires par ID et par nom de table :

      //+------------------------------------------------------------------+
      //| Create a new table                                               |
      //+------------------------------------------------------------------+
      bool CDashboard::CreateNewTable(const int id=WRONG_VALUE)
        {
         uint num=(id>WRONG_VALUE ? id : this.m_list_table.Total());
         CTableData *table=new CTableData(num);
         this.m_list_table.Sort();
         if(this.m_list_table.Search(table)!=WRONG_VALUE)
           {
            PrintFormat("%s: Error. Table with id %lu already exists in the list",__FUNCTION__,num);
            delete table;
            return false;
           }
         if(!this.m_list_table.Add(table))
           {
            PrintFormat("%s: Error. Failed to add table with id %lu to the list",__FUNCTION__,num);
            delete table;
            return false;
           }
         return true;
        }
      //+------------------------------------------------------------------+
      //| Return tabular data object by ID                                 |
      //+------------------------------------------------------------------+
      CTableData *CDashboard::GetTable(const uint id)
        {
         if(this.m_list_table.Total()==0)
           {
            PrintFormat("%s: Error. The list of tables is empty. First you need to create a table using CreateNewTable",__FUNCTION__);
            .return NULL;
           }
         CTableData *table=new CTableData(id);
         if(table==NULL)
           {
            ::PrintFormat("%s: Error. Failed to create table object with id %lu",__FUNCTION__,id);
            .return NULL;
           }
         this.m_list_table.Sort();
         int index=this.m_list_table.Search(table);
         delete table;
         return this.m_list_table.At(index);
        }
      //+------------------------------------------------------------------+
      //| Return tabular data object by name                               |
      //+------------------------------------------------------------------+
      CTableData *CDashboard::GetTable(const string name)
        {
         if(this.m_list_table.Total()==0)
           {
            PrintFormat("%s: Error. The list of tables is empty. First you need to create a table using CreateNewTable",__FUNCTION__);
            .return NULL;
           }
         CTableData *table=new CTableData(0);
         if(table==NULL)
           {
            ::PrintFormat("%s: Error. Failed to create table object");
            .return NULL;
           }
         table.SetName(name);
         this.m_list_table.Sort(1);
         int index=this.m_list_table.Search(table);
         delete table;
         return this.m_list_table.At(index);
        }
      


      Changements dans les méthodes de dessin des tableaux :

      //+------------------------------------------------------------------+
      //| Draw the background grid                                         |
      //+------------------------------------------------------------------+
      void CDashboard::DrawGrid(const uint table_id,
                                const uint x,const uint y,const uint rows,const uint columns,const uint row_size,const uint col_size,
                                const color line_color=clrNONE,bool alternating_color=true)
        {
      //--- Get a table object by ID
         CTableData *table=this.GetTable(table_id);
         if(table==NULL)
           {
            PrintFormat("%s: Error. Failed to get table object with id %lu",__FUNCTION__,table_id);
            return;
           }
      //--- Clear all lists of the tabular data object (remove cells from rows and all rows)
         table.Clear();
      //--- Line height cannot be less than 2
         int row_h=int(row_size<2 ? 2 : row_size);
      //--- Column width cannot be less than 2
         int col_w=int(col_size<2 ? 2 : col_size);
         
      //--- The X1 (left) coordinate of the table cannot be less than 1 (to leave one pixel around the perimeter of the panel for the frame)
         int x1=int(x<1 ? 1 : x);
      //--- Calculate the X2 coordinate (right) depending on the number of columns and their width
         int x2=x1+col_w*int(columns>0 ? columns : 1);
      //--- The Y1 coordinate is located under the panel title area
         int y1=this.m_header_h+(int)y;
      //--- Calculate the Y2 coordinate (bottom) depending on the number of lines and their height
         int y2=y1+row_h*int(rows>0 ? rows : 1);
      //--- Set table coordinates
         table.SetCoords(x1,y1-this.m_header_h,x2,y2-this.m_header_h);
         
      //--- Get the color of the table grid lines, either by default or passed to the method
         color clr=(line_color==clrNONE ? C'200,200,200' : line_color);
      //--- If the initial X coordinate is greater than 1, draw a table frame
      //--- (in case of the coordinate 1, the table frame is the panel frame)
         if(x1>1)
            this.m_canvas.Rectangle(x1,y1,x2,y2,::ColorToARGB(clr,this.m_alpha));
      //--- In the loop by table rows,
         for(int i=0;i<(int)rows;i++)
           {
            //--- calculate the Y coordinate of the next horizontal grid line (Y coordinate of the next table row)
            int row_y=y1+row_h*i;
            //--- if the flag of "alternating" line colors is passed and the line is even
            if(alternating_color && i%2==0)
              {
               //--- lighten the table background color and draw a background rectangle
               color new_color=this.NewColor(clr,45,45,45);
               this.m_canvas.FillRectangle(x1+1,row_y+1,x2-1,row_y+row_h-1,::ColorToARGB(new_color,this.m_alpha));
              }
            //--- Draw a table grid horizontal line
            this.m_canvas.Line(x1,row_y,x2,row_y,::ColorToARGB(clr,this.m_alpha));
            
            //--- Create a new table row object
            CTableRow *row_obj=new CTableRow(i);
            if(row_obj==NULL)
              {
               ::PrintFormat("%s: Failed to create table row object at index %lu",(string)__FUNCTION__,i);
               continue;
              }
            //--- Add it to the list of rows of the tabular data object
            //--- (if adding an object failed, delete the created object)
            if(!table.AddRow(row_obj))
               delete row_obj;
            //--- Set its Y coordinate in the created row object taking into account the offset from the panel title
            row_obj.SetY(row_y-this.m_header_h);
           }
           
      //--- In the loop by table columns,
         for(int i=0;i<(int)columns;i++)
           {
            //--- calculate the X coordinate of the next vertical grid line (X coordinate of the next table row)
            int col_x=x1+col_w*i;
            //--- If the grid line goes beyond the panel, interrupt the loop
            if(x1==1 && col_x>=x1+m_canvas.Width()-2)
               break;
            //--- Draw a vertical line of the table grid
            this.m_canvas.Line(col_x,y1,col_x,y2,::ColorToARGB(clr,this.m_alpha));
            
            //--- Get the number of created rows from the table data object 
            int total=table.RowsTotal();
            //--- In the loop by table rows
            for(int j=0;j<total;j++)
              {
               //--- get the next row
               CTableRow *row=table.GetRow(j);
               if(row==NULL)
                  continue;
               //--- Create a new table cell 
               CTableCell *cell=new CTableCell(row.Row(),i);
               if(cell==NULL)
                 {
                  ::PrintFormat("%s: Failed to create table cell object at index %lu",(string)__FUNCTION__,i);
                  continue;
                 }
               //--- Add the created cell to the row
               //--- (if adding an object failed, delete the created object)
               if(!row.AddCell(cell))
                 {
                  delete cell;
                  continue;
                 }
               //--- In the created cell object, set its X coordinate and the Y coordinate from the row object 
               cell.SetXY(col_x,row.Y());
              }
           }
      //--- Update the canvas without redrawing the chart
         this.m_canvas.Update(false);
        }
      //+------------------------------------------------------------------+
      //| Draws the background grid with automatic cell sizing             |
      //+------------------------------------------------------------------+
      void CDashboard::DrawGridAutoFill(const uint table_id,const uint border,const uint rows,const uint columns,const color line_color=clrNONE,bool alternating_color=true)
        {
      //--- Get a table object by ID
         CTableData *table=this.GetTable(table_id);
         if(table==NULL)
           {
            PrintFormat("%s: Error. Failed to get table object with id %lu",__FUNCTION__,table_id);
            return;
           }
      //--- X1 (left) table coordinate
         int x1=(int)border;
      //--- X2 (right) table coordinate
         int x2=this.m_canvas.Width()-(int)border-1;
      //--- Y1 (upper) table coordinate
         int y1=this.m_header_h+(int)border;
      //--- Y2 (lower) table coordinate
         int y2=this.m_canvas.Height()-(int)border-1;
      //--- Set table coordinates
         table.SetCoords(x1,y1,x2,y2);
      
      //--- Get the color of the table grid lines, either by default or passed to the method
         color clr=(line_color==clrNONE ? C'200,200,200' : line_color);
      //--- If the offset from the edge of the panel is greater than zero, draw a table border,
      //--- otherwise, the panel border is used as the table border
         if(border>0)
            this.m_canvas.Rectangle(x1,y1,x2,y2,::ColorToARGB(clr,this.m_alpha));
      
      //--- Height of the entire table grid
         int greed_h=y2-y1;
      //--- Calculate the row height depending on the table height and the number of rows
         int row_h=(int)::round((double)greed_h/(double)rows);
      //--- In the loop based on the number of rows
         for(int i=0;i<(int)rows;i++)
           {
            //--- calculate the Y coordinate of the next horizontal grid line (Y coordinate of the next table row)
            int row_y=y1+row_h*i;
            //--- if the flag of "alternating" line colors is passed and the line is even
            if(alternating_color && i%2==0)
              {
               //--- lighten the table background color and draw a background rectangle
               color new_color=this.NewColor(clr,45,45,45);
               this.m_canvas.FillRectangle(x1+1,row_y+1,x2-1,row_y+row_h-1,::ColorToARGB(new_color,this.m_alpha));
              }
            //--- Draw a table grid horizontal line
            this.m_canvas.Line(x1,row_y,x2,row_y,::ColorToARGB(clr,this.m_alpha));
            
            //--- Create a new table row object
            CTableRow *row_obj=new CTableRow(i);
            if(row_obj==NULL)
              {
               ::PrintFormat("%s: Failed to create table row object at index %lu",(string)__FUNCTION__,i);
               continue;
              }
            //--- Add it to the list of rows of the tabular data object
            //--- (if adding an object failed, delete the created object)
            if(!table.AddRow(row_obj))
               delete row_obj;
            //--- Set its Y coordinate in the created row object taking into account the offset from the panel title
            row_obj.SetY(row_y-this.m_header_h);
           }
           
      //--- Table grid width
         int greed_w=x2-x1;
      //--- Calculate the column width depending on the table width and the number of columns
         int col_w=(int)::round((double)greed_w/(double)columns);
      //--- In the loop by table columns,
         for(int i=0;i<(int)columns;i++)
           {
            //--- calculate the X coordinate of the next vertical grid line (X coordinate of the next table row)
            int col_x=x1+col_w*i;
            //--- If this is not the very first vertical line, draw it
            //--- (the first vertical line is either the table frame or the panel frame)
            if(i>0)
               this.m_canvas.Line(col_x,y1,col_x,y2,::ColorToARGB(clr,this.m_alpha));
            
            //--- Get the number of created rows from the table data object 
            int total=table.RowsTotal();
            //--- In the loop by table rows
            for(int j=0;j<total;j++)
              {
               //--- get the next row
               CTableRow *row=table.GetRow(j);
               if(row==NULL)
                  continue;
               //--- Create a new table cell 
               CTableCell *cell=new CTableCell(row.Row(),i);
               if(cell==NULL)
                 {
                  ::PrintFormat("%s: Failed to create table cell object at index %lu",(string)__FUNCTION__,i);
                  continue;
                 }
               //--- Add the created cell to the row
               //--- (if adding an object failed, delete the created object)
               if(!row.AddCell(cell))
                 {
                  delete cell;
                  continue;
                 }
               //--- In the created cell object, set its X coordinate and the Y coordinate from the row object 
               cell.SetXY(col_x,row.Y());
              }
           }
      //--- Update the canvas without redrawing the chart
         this.m_canvas.Update(false);
        }
      


      Les méthodes d'enregistrement/de chargement des pixels vers/depuis le fichier appliquent désormais les noms de fichiers précédemment créés dans le constructeur :

      //+------------------------------------------------------------------+
      //| Save the pixel array of the working space to a file              |
      //+------------------------------------------------------------------+
      bool CDashboard::FileSaveWorkspace(void)
        {
      //--- If the saved array is empty, inform of that and return 'false'
         if(this.m_array_wpx.Size()==0)
           {
            ::PrintFormat("%s: Error. The workspace pixel array is empty.",__FUNCTION__);
            return false;
           }
      //--- If the array could not be saved to a file, report this and return 'false'
         if(!::FileSave(this.m_filename_ws,this.m_array_wpx))
           {
            ::PrintFormat("%s: FileSave '%s' failed. Error %lu",__FUNCTION__,this.m_filename_ws,::GetLastError());
            return false;
           }
      //--- Successful, return 'true'
         return true;
        }
      //+------------------------------------------------------------------+
      //| Save the pixel array of the panel background to a file           |
      //+------------------------------------------------------------------+
      bool CDashboard::FileSaveBackground(void)
        {
      //--- If the saved array is empty, inform of that and return 'false'
         if(this.m_array_ppx.Size()==0)
           {
            ::PrintFormat("%s: Error. The background pixel array is empty.",__FUNCTION__);
            return false;
           }
      //--- If the array could not be saved to a file, report this and return 'false'
         if(!::FileSave(this.m_filename_bg,this.m_array_ppx))
           {
            ::PrintFormat("%s: FileSave '%s' failed. Error %lu",__FUNCTION__,this.m_filename_bg,::GetLastError());
            return false;
           }
      //--- Successful, return 'true'
         return true;
        }
      //+------------------------------------------------------------------+
      //| Upload the array of working space pixels from a file             |
      //+------------------------------------------------------------------+
      bool CDashboard::FileLoadWorkspace(void)
        {
      //--- If failed to upload data from the file into the array, report this and return 'false'
         if(::FileLoad(this.m_filename_ws,this.m_array_wpx)==WRONG_VALUE)
           {
            ::PrintFormat("%s: FileLoad '%s' failed. Error %lu",__FUNCTION__,this.m_filename_ws,::GetLastError());
            return false;
           }
      //--- Successful, return 'true'
         return true;
        }
      //+------------------------------------------------------------------+
      //| Upload the array of panel background pixels from a file          |
      //+------------------------------------------------------------------+
      bool CDashboard::FileLoadBackground(void)
        {
         if(::FileLoad(this.m_filename_bg,this.m_array_ppx)==WRONG_VALUE)
           {
            ::PrintFormat("%s: FileLoad '%s' failed. Error %lu",__FUNCTION__,this.m_filename_bg,::GetLastError());
            return false;
           }
      //--- Successful, return 'true'
         return true;
        }
      


      Conclusion

      Dans cet article, nous avons examiné la connexion aux Volumes et aux EAs des indicateurs de Bill Williams. Tous les codes fournis dans l'article peuvent être utilisés "tels quels" pour les insérer dans le code personnalisé. Nous examinerons ensuite la dernière catégorie d'indicateurs - les indicateurs de tendance - sous l'angle de leur lien et de leur utilisation dans les EA.

      Tous les fichiers (EA de test et classes de panel) peuvent être téléchargés à partir de la liste de fichiers jointe ci-dessous. La classe du tableau de bord doit être située à l'adresse \MQL5\Include\Dashboard\Dashboard.mqh.


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

      Derniers commentaires | Aller à la discussion (2)
      Gunnar Forsgren
      Gunnar Forsgren | 5 mai 2024 à 16:01
      Excellent matériel, les plus grands éloges.

      Un détail ; dans le livre de Bill Williams, la phrase sur un poulet aveugle dit :

      "Même un poulet aveugle trouvera un épi de maïs de temps en temps"
      Ici, il est écrit :
      "Même un poulet aveugle trouvera ses épis, s'il est toujours nourri en même temps". Mais il pourrait s'agir d'un effet de traduction russe/anglais.

      Dans son livre, Bill Williams s'appuie vraiment sur ce que je suppose être une "tendance contemporaine à l'hypnose de masse", en présentant les trois courbes de moyennes mobiles de l'indicateur Alligator comme ayant un rapport avec :
      "la science du chaos, ainsi que la physique quantique, l'holographie, la cybernétique, la dynamique non linéaire, la théorie de l'information et la géométrie fractale". Mais son discours sur le chaos est un peu trop exagéré. Le livre contient également une grande sagesse. Quoi qu'il en soit, l'Alligator est une combinaison pratique d'AMM.
      Artyom Trishkin
      Artyom Trishkin | 5 mai 2024 à 18:41
      Gunnar Forsgren moyennes mobiles de l'indicateur Alligator comme ayant un rapport avec :
      "la science du chaos, ainsi que la physique quantique, l'holographie, la cybernétique, la dynamique non linéaire, la théorie de l'information et la géométrie fractale". Mais son discours sur le chaos est un peu trop exagéré. Le livre contient également une grande sagesse. Quoi qu'il en soit, l'Alligator est une combinaison pratique d'AMM.

      Merci pour votre évaluation.
      Je n'ai pas lu les travaux de Williams, je ne dirai donc pas exactement comment et ce qu'il a dit.
      Vous pouvez parler et écrire beaucoup. Mais le plus important est de le faire. Et, mieux encore, de le faire correctement)

      Modèles prêts à l'emploi pour inclure des indicateurs dans les Expert Advisors (Partie 3) : Indicateurs de tendance Modèles prêts à l'emploi pour inclure des indicateurs dans les Expert Advisors (Partie 3) : Indicateurs de tendance
      Dans cet article de référence, nous examinerons les indicateurs standard de la catégorie Indicateurs de Tendance. Nous créerons des modèles prêts à l'emploi pour l'utilisation d'indicateurs dans les EA - déclaration et définition des paramètres, initialisation et dé-initialisation de l'indicateur, ainsi que l’obtention des résultats et des signaux à partir des buffers des indicateurs dans les EA.
      Modèles prêts à l'emploi pour ajouter des indicateurs dans les Expert Advisors (Partie 1) : Oscillateurs Modèles prêts à l'emploi pour ajouter des indicateurs dans les Expert Advisors (Partie 1) : Oscillateurs
      L'article examine les indicateurs standard de la catégorie des Oscillateurs. Nous créerons des modèles prêts à l'emploi pour être utilisé dans les EA : déclaration et définition des paramètres, initialisation et dé-initialisation des indicateurs, ainsi que la récupération des données et des signaux depuis les buffers des indicateurs dans les EA.
      Python, ONNX et MetaTrader 5 : Création d'un modèle RandomForest avec RobustScaler et PolynomialFeatures pour le pré-traitement des données Python, ONNX et MetaTrader 5 : Création d'un modèle RandomForest avec RobustScaler et PolynomialFeatures pour le pré-traitement des données
      Dans cet article, nous allons créer un modèle de forêt aléatoire (random forest) en Python, entraîner le modèle et le sauvegarder en tant que pipeline ONNX avec un pré-traitement des données. Ensuite, nous utiliserons le modèle dans le terminal MetaTrader 5.
      Algorithmes d'optimisation de la population : Algorithme de type Electro-Magnétique (ЕМ) Algorithmes d'optimisation de la population : Algorithme de type Electro-Magnétique (ЕМ)
      L'article décrit les principes, les méthodes et les possibilités d'utilisation de l'Algorithme Electro-Magnétique dans divers problèmes d'optimisation. L'algorithme EM est un outil d'optimisation efficace capable de travailler avec de grandes quantités de données et des fonctions multidimensionnelles.