English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Construire un Analyseur de Spectre

Construire un Analyseur de Spectre

MetaTrader 5Exemples | 17 novembre 2021, 16:45
245 0
Victor
Victor

Introduction

Cet article est destiné à familiariser ses lecteurs avec une variante possible d'utilisation des objets graphiques du langage MQL5. Il analyse un indicateur, qui implémente un panneau de contrôle d'un simple analyseur de spectre utilisant les objets graphiques.

Trois fichiers sont joints à l'article :

  1. SpecAnalyzer.mq5 – l'indicateur décrit dans cet article.
  2. SpecAnalyzer.mqh – le fichier d'inclusion pour SpecAnalyzer.mq5.
  3. SAInpData.mq5 – l'indicateur utilisé pour l'organisation de l'accès aux données externes.

Pour charger normalement l'indicateur SpecAnalyzer, vous devez placer les trois fichiers dans le dossier \MQL5\Indicators du terminal client. Ensuite, vous devez compiler les fichiers SpecAnalyzer.mq5 et SAInpData.mq5. L'indicateur est destiné à être chargé dans la fenêtre graphique principale. Une fois l'indicateur chargé, il modifie les paramètres d'affichage de cette fenêtre, et lorsqu'il est retiré tous les objets graphiques sont supprimés de la fenêtre. C'est pourquoi vous devez charger l'indicateur dans une fenêtre séparée spéciale créée pour lui, afin d'éviter un changement accidentel du mode d'affichage des fenêtres existantes du terminal.

Compte tenu du fait que l'article ne comporte pas le code source complet de l'indicateur, il est recommandé d'ouvrir le code dans les fichiers joints lors de la lecture de l'article.

L'indicateur décrit dans l'article ne prétend pas être une application toute faite. C'est juste un exemple d'utilisation d'objets graphiques du langage. Ceux qui sont intéressés peuvent mettre à jour et optimiser eux-mêmes le code présenté dans l'article.

Coordonnées

Deux méthodes peuvent être utilisées dans MQL5 pour indiquer les coordonnées lors du dessin d'objets graphiques. Pour certains objets, les coordonnées sont indiquées en nombre de pixels à partir d'un point indiqué de la fenêtre ; et pour d'autres, les coordonnées sont indiquées en tant que valeurs de prix et de temps du graphique affiché dans la fenêtre.

Par exemple, pour placer un objet tel que « Étiquette » ou « Bouton » sur un graphique, vous devez spécifier leurs coordonnées comme la distance en pixels de l'un des coins de la fenêtre graphique. Avec cette façon de traitement les objets conservent leur position quelles que soient les propriétés actuelles de la fenêtre et l'échelle du graphique qui y est affiché. Même si la taille de la fenêtre change, ces objets conservent leur position et se lient les uns aux autres. Si vous déplacez le graphique dans la fenêtre ,à l'aide du bouton gauche de la souris, ces objets conservent leur position par rapport au point d'ancrage choisi de la fenêtre.

L'autre groupe d'objets implique la liaison à un graphique dans la fenêtre au lieu des coordonnées de la fenêtre. Ces objets sont « Courbe de tendance », « Rectangle », etc. Lors de la création et du placement de tels objets, les coordonnées sont indiquées en tant que valeur de temps et de prix d'un graphique affiché dans la fenêtre. Avec ce mode d’indication des coordonnées, les objets changent de position par rapport à la fenêtre graphique et les uns par rapport aux autres lorsque l'échelle de la carte est modifiée ou lorsqu'elle défile. Puisqu’une nouvelle barre apparaît sur le graphique, les objets changent également de position, car l'axe du temps se déplace vers la gauche sur la taille du lapse de temps.

Dans l'indicateur SpecAnalyzer, les deux types d'objets graphiques sont utilisés simultanément pour créer le panneau de contrôle de l'analyseur de spectre. Pour que les objets tenus au graphique à ne pas bouger relativement à la fenêtre, nous fixons un mode d'affichage du graphique selon l'axe vertical et le mode correspondant à l'échelle d'affichage minimum possible au long de l'échelle horizontale du graphique. De plus, le minimum de l'échelle verticale est défini sur 0,0 ; et pour l'axe horizontal, nous définissons le mode sans décalage de la barre zéro du bord droit et sans défilement automatique vers le bord droit du graphique. Par conséquent, le point de coordonnée qui correspond à la barre zéro et à la valeur 0.0 du graphique semble être dans le coin inférieur droit, et avec l'échelle fixe, il peut être utilisé comme point d'ancrage pour les objets tels que « Courbe de tendance » et « Rectangle » . À cela, si nous définissons le même coin inférieur droit que le point d'ancrage des objets comme "Étiquette" ou "Bouton", alors les deux types d'objets seront définitivement liés l'un à l'autre.

Toutes les propriétés nécessaires du graphique sont définies dans la fonction SetOwnProperty() dans le fichier SpecAnalyzer.mqh.

void GRaphChart::SetOwnProperty(void)
  {
  ChartSetInteger(m_chart_id,CHART_FOREGROUND,1);
  ChartSetInteger(m_chart_id,CHART_SHIFT,0);
  ChartSetInteger(m_chart_id,CHART_AUTOSCROLL,0);
  ChartSetInteger(m_chart_id,CHART_AUTOSCROLL,1);
  ChartSetInteger(m_chart_id,CHART_SCALE,0);
  ChartSetInteger(m_chart_id,CHART_SCALEFIX_11,1);
  ChartSetInteger(m_chart_id,CHART_SHOW_OHLC,0);
  ChartSetInteger(m_chart_id,CHART_SHOW_BID_LINE,0);
  ChartSetInteger(m_chart_id,CHART_SHOW_ASK_LINE,0);
  ChartSetInteger(m_chart_id,CHART_SHOW_LAST_LINE,0);
  ChartSetInteger(m_chart_id,CHART_SHOW_PERIOD_SEP,0);
  ChartSetInteger(m_chart_id,CHART_SHOW_GRID,0);
  ChartSetInteger(m_chart_id,CHART_SHOW_VOLUMES,CHART_VOLUME_HIDE);
  ChartSetInteger(m_chart_id,CHART_SHOW_OBJECT_DESCR,0);
  ChartSetInteger(m_chart_id,CHART_SHOW_TRADE_LEVELS,0);
  ChartSetInteger(m_chart_id,CHART_COLOR_BACKGROUND,Black);
  ChartSetInteger(m_chart_id,CHART_COLOR_FOREGROUND,Black);
  ChartSetDouble(m_chart_id,CHART_FIXED_MIN,0.0);
  }

En plus de définir les propriétés nécessaires du graphique pour assurer la liaison des objets graphiques, cette fonction définit les propriétés qui permettent d'attribuer une couleur et de restreindre l'affichage de certains éléments du graphique.

Étant donné que l'indicateur SpecAnalyzer modifie les propriétés du graphique pendant le travail, nous devons enregistrer les paramètres précédents du graphique lors du chargement de l'indicateur et restaurer les paramètres lors du déchargement. La bibliothèque standard de MQL5 comprend les fonctions virtuelles spéciales à cet effet - Save() et Load() de la classe CChart. Ces fonctions sont destinées à enregistrer les propriétés d'un objet de la classe CChart dans un fichier et à restaurer ces propriétés à partir du fichier créé. Pour modifier l'ensemble des propriétés enregistrées et éviter d'utiliser le fichier des opérations lors de l'enregistrement des propriétés d'un graphique, les fonctions virtuelles Save() et Load() de la classe CChart sont outrepassées lors de la création de la nouvelle classe GRaphChart (voir le fichier SpecAnalyzer.mqh). 

class GRaphChart : public CChart
  {
  protected:
    struct ChartPropertyes
      {
      double shift_size;
      double fixed_max;
      double fixed_min;
      double points_per_bar;
      long   mode;
      bool   foreground;
      bool   shift;
      bool   autoscroll;
      long   scale;
      bool   scalefix;
      bool   scalefix_11;
      bool   scale_pt_per_bar;
      bool   show_ohls;
      bool   show_bid_line;
      bool   show_ask_line;
      bool   show_last_line;
      bool   show_period_sep;
      bool   show_grid;
      long   show_volumes;
      bool   show_object_descr;
      bool   show_trade_levels;
      long   color_background;
      long   color_foreground;
      long   color_grid;
      long   color_volume;
      long   color_chart_up;
      long   color_chart_down;
      long   color_chart_line;
      long   color_candle_bull;
      long   color_candle_bear;
      long   color_bid;
      long   color_ask;
      long   color_last;
      long   color_stop_level;
      string ch_comment;
      };
      ChartPropertyes ChProp;
  
  public:
                   GRaphChart();
                  ~GRaphChart();
                   
         void      SetOwnProperty();
  virtual void      Save();
  virtual void      Load();
  };

La classe de base de GRaphChart est CChart de la bibliothèque standard de MQL5. La classe GRaphChart comporte la description de la structure ChartPropertyes et la création de l'objet ChProp destiné à stocker les propriétés du graphique dans la mémoire au lieu d'un fichier comme cela est implémenté dans la classe de base. La fonction Save() remplit la structure ChProp avec des données en fonction des propriétés actuelles du graphique, et la fonction Load() restaure les propriétés précédemment enregistrées à partir de celle-ci.

La fonction Save() est appelée dans le constructeur de la classe GRaphChart, et la fonction Load() est appelée dans son destructeur. C'est pourquoi la sauvegarde et la restauration de l'état précédent du graphique sont effectuées automatiquement lors de la création et de la suppression de l'objet de la classe GRaphChart. Le SetOwnProperty() mentionné ci-dessus est également appelé dans le constructeur de classe.

//---------------------------------------------------- Constructor GRaphChart --
GRaphChart::GRaphChart()
  {
  m_chart_id=ChartID();
  Save();                                // Keep a original chart settings
  SetOwnProperty();                             // Set own chart settings
  }
//----------------------------------------------------- Destructor GRaphChart --
GRaphChart::~GRaphChart()
  {
  Load();                             // Restore a previous chart settings
  m_chart_id=-1;
  }

Démontrons l'utilisation de la classe GRaphChart avec un exemple simple. Pour ce faire, créons un nouvel indicateur personnalisé dans MetaEditor et nommons-le Test. Incluez le fichier d'en-tête SpecAnalyzer.mqh dans le code de l'indicateur et créez un objet de la classe GRaphChart en ajoutant deux lignes.

//+------------------------------------------------------------------+
//|                                                         Test.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window

#include "SpecAnalyzer.mqh"    // <----- Including header file 

GRaphChart  MainChart; // <----- Creating object of the class GRaphChart

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
  {
//---
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

Pour une compilation réussie du code ci-dessus, le fichier SpecAnalyzer.mqh doit être placé dans le dossier \MQL5\Indicators du terminal client.

Si vous créez un graphique dans le terminal client et essayez d'y charger notre exemple de test, les propriétés du graphique seront modifiées et vous ne verrez qu'une fenêtre vide prête à y afficher des objets graphiques. Lorsque vous supprimez notre indicateur de test du graphique, son apparence initiale sera restaurée avec l'arrivée d'un nouveau tick.

Revenons à l'indicateur SpecAnalyzer. Au début de l'indicateur (voir le fichier SpecAnalyzer.mq5), la création de l'objet MainChart de la classe GRaphChart est effectuée, ce qui conduit au chargement de l'indicateur et à la sauvegarde des propriétés du graphique.

                 button. button. button.
GRaphChart MainChart; // Create MainChart object
                 button. button. button.

Lors du déchargement de l'indicateur, l'objet MainChart est automatiquement terminé, les propriétés initiales du graphique sont alors restaurées dans le destructeur de classe. 

Panneau de contrôle

L'apparence du panneau de contrôle dans l'indicateur SpecAnalyzer est déterminée par des objets graphiques placés dans la fenêtre. La classe AllGrObject réunit toutes les fonctions nécessaires pour créer et interagir avec elles ; voir le fichier SpecAnalyzer.mqh.

class AllGrObject : public CChart
  {
  protected:
    long      m_chart_id;                                    // chart identifier
    
  public:
              AllGrObject();
             ~AllGrObject();
                   
    void      AddLabel(string name,int fsize,string font,
                             color col,int x,int y,string text="");
    void      AddButton(string name,int xsize,int ysize,color bgcol,
                        int fsize,string font,color col,int x,int y,
                        string text="",int state=0);
    void      AddEdit(string name,int xsize,int ysize,color bgcol,int fsize,
                      string font,color col,int x,int y,string text="");
    void      AddTrendLine(string name,color col,int style=0,int width=1);
    void      AddArrowline(string name,color col,int style=0,int width=1);
    void      AddRectangle(string name,color col,int style=0,int width=1);
    void      MoveGrObject(string name,int x1,int y1,int x2,int y2);
    void      SetButtonProp(string name,bool state,color col);
    long      GetRowNumber(string name);
    void      LabelTxt(string name,string str);
    
  };

Les fonctions de la classe, dont les noms commencent par Add, sont destinées à créer les objets graphiques. Par exemple, AddButton() crée l'objet « Button ».

Dans l'application, les coordonnées de tous les objets graphiques sont définies comme la distance en pixels du coin inférieur droit du graphique. Pour les objets « Courbe de tendance », « Ligne fléchée » et « Rectangle », nous devons transformer ces coordonnées en valeurs de temps et de prix. Une telle transformation est effectuée dans la fonction MoveGrObject() avant d'affecter des coordonnées à un objet. Un pixel horizontal correspond à une barre et un pixel vertical correspond à un point.

void AllGrObject::MoveGrObject(string name,int x1,int y1,int x2,int y2)
  {
  datetime t1[1],t2[1];
  long typ;
  
  typ=ObjectGetInteger(m_chart_id,name,OBJPROP_TYPE);
  if(typ==OBJ_TREND||typ==OBJ_ARROWED_LINE||typ==OBJ_RECTANGLE)
    {
    CopyTime(_Symbol,_Period,x1,1,t1);
    CopyTime(_Symbol,_Period,x2,1,t2);
    ObjectSetInteger(m_chart_id,name,OBJPROP_TIME,0,t1[0]);
    ObjectSetDouble(m_chart_id,name,OBJPROP_PRICE,0,_Point*y1);
    ObjectSetInteger(m_chart_id,name,OBJPROP_TIME,1,t2[0]);
    ObjectSetDouble(m_chart_id,name,OBJPROP_PRICE,1,_Point*y2);
    }
  }

Tous les objets graphiques ne sont créés qu'une seule fois dans l'indicateur, cela se fait lors de l'appel de gr_object_create() depuis la fonction OnInit() de l'indicateur ; voir le fichier SpecAnalyzer.mq5. Pour tous les objets, à l'exception de « Courbe de tendance », « Ligne fléchée » et « Rectangle », les coordonnées sont immédiatement définies. Pour des objets comme « Courbe de tendance », « Ligne fléchée » et « Rectangle » les coordonnées sont définis en appelant la fonction gr_object_coordinate() qui utilise la fonction MoveGrObject() mentionnée ci-dessus, qui transforme le mode de traitement. 

void gr_object_coordinate()
  {
  GObj.MoveGrObject("Trdline1",48,150,48,360);
  GObj.MoveGrObject("Trdline2",176,150,176,360);
  GObj.MoveGrObject("Trdline3",304,150,304,360);
  GObj.MoveGrObject("Trdline4",432,150,432,360);
  GObj.MoveGrObject("Trdline5",42,350,560,350);
  GObj.MoveGrObject("Trdline6",42,300,560,300);
  GObj.MoveGrObject("Trdline7",42,250,560,250);
  GObj.MoveGrObject("Trdline8",42,200,560,200);
  GObj.MoveGrObject("Arrline1",560,150,28,150);
  GObj.MoveGrObject("Arrline2",560,150,560,370);
  GObj.MoveGrObject("Rect1",0,1,208,110);
  GObj.MoveGrObject("Rect2",208,1,416,110);
  GObj.MoveGrObject("Rect3",416,1,624,110);
  GObj.MoveGrObject("Rect4",0,1,624,400);
  GObj.MoveGrObject("Rect5",20,10,195,80);
  }

L'appel de la fonction gr_object_coordinate() est inclus dans la fonction OnCalculate() de l'indicateur. Il fournit un recalcul correct des coordonnées lorsqu'une nouvelle barre est formée sur le graphique, puisque la fonction est appelée à chaque arrivée d'un nouveau tick.

Les boutons sur le panneau de l'indicateur sont divisés en trois groupes. Le premier groupe se compose de quatre boutons situés à gauche ; ils permettent de sélectionner un mode d'affichage du résultat de l'estimation du spectre de séquence d'entrée par l'indicateur. Quatre modes d'affichage sont pris en charge (selon le nombre de boutons) :

  1. Amplitude/Ligne - affichage du module de transformée de Fourier à une échelle linéaire le long de l'axe Y.
  2. Amplitude/dB - affichage du module de transformée de Fourier à une échelle logarithmique le long de l'axe Y.
  3. Power/Line - affichage du carré du module de la transformée de Fourier à une échelle linéaire le long de l'axe Y.
  4. Puissance/dB - affichage du carré du module de la transformée de Fourier à une échelle logarithmique le long de l'axe Y.

Pour traiter les clics sur les boutons de ce groupe, le code suivant est inclus dans la fonction OnChartEvent() de l'indicateur : 

  if(id==CHARTEVENT_OBJECT_CLICK)                       // Click on the gr. object
    {
    if(sparam=="Butt1")                                   // Click on the button
      {
      GObj.SetButtonProp("Butt1",1,Chocolate);
      GObj.SetButtonProp("Butt2",0,SlateGray);
      GObj.SetButtonProp("Butt3",0,SlateGray);
      GObj.SetButtonProp("Butt4",0,SlateGray);
      YPowerFlag=0;YdBFlag=0;
      }
    if(sparam=="Butt2")                                   // Click on the button
      {
      GObj.SetButtonProp("Butt1",0,SlateGray);
      GObj.SetButtonProp("Butt2",1,Chocolate);
      GObj.SetButtonProp("Butt3",0,SlateGray);
      GObj.SetButtonProp("Butt4",0,SlateGray);
      YPowerFlag=0;YdBFlag=1;
      }
    if(sparam=="Butt3")                                   // Click on the button
      {
      GObj.SetButtonProp("Butt1",0,SlateGray);
      GObj.SetButtonProp("Butt2",0,SlateGray);
      GObj.SetButtonProp("Butt3",1,Chocolate);
      GObj.SetButtonProp("Butt4",0,SlateGray);
      YPowerFlag=1;YdBFlag=0;
      }
    if(sparam=="Butt4")                                   // Click on the button
      {
      GObj.SetButtonProp("Butt1",0,SlateGray);
      GObj.SetButtonProp("Butt2",0,SlateGray);
      GObj.SetButtonProp("Butt3",0,SlateGray);
      GObj.SetButtonProp("Butt4",1,Chocolate);
      YPowerFlag=1;YdBFlag=1;
      }

Lorsqu'un clic sur l'un des boutons est détecté, l'état des autres boutons passe à non enfoncé, ce qui empêche d'appuyer simultanément sur plusieurs boutons d'un même groupe. Dans le même temps, les valeurs correspondantes sont définies pour les indicateurs YPowerFlag et YdBFlag qui déterminent le mode d'affichage actuel.

Le deuxième groupe composé de quatre boutons permet de sélectionner une source de données d'entrée. Il peut s'agir de données externes obtenues en appelant l'indicateur SAInpData.mq5 ou de trois séquences de test générées par l'application elle-même. Le dernier groupe de boutons comprend deux boutons utilisés pour faire défiler la liste dans le champ de saisie d'informations textuelles. La gestion du clic sur tous ces boutons est également effectuée dans la fonction OnChartEvent() de l'indicateur de la même manière que les boutons du premier groupe ; voir le fichier SpecAnalyzer.mq5.

Montrons un exemple d'utilisation de la classe AllGrObject à l’aide l'indicateur de test précédemment créé Test.mq5. Pour ce faire, ajoutez plusieurs lignes à son code source et incluez les fonctions gr_object_create() et gr_object_coordinate() mentionnées précédemment à partir du fichier SpecAnalyzer.mq5.

//+------------------------------------------------------------------+
//|                                                         Test.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window

#include "SpecAnalyzer.mqh" 

GRaphChart  MainChart;

AllGrObject GObj;        // <----- Creating object of the class AllGrObject

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
//---

  gr_object_create();          // <----- creating graphical objects

   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
  {
//---

  MainChart.SetOwnProperty();    // <----- restoring current properties of the chart
  gr_object_coordinate();     // <----- setting coordinates for the graphical objects


//--- return value of prev_calculated for next call
   return(rates_total);
  }

//----------------------------------------------- Create all graphical objects --
void gr_object_create()
  {
  GObj.AddLabel("Title",10,"Arial",DarkGray,256,367,"Spectrum Analyzer");
  GObj.AddLabel("Label1",9,"Arial",LightSteelBlue,557,128,"0");
  GObj.AddLabel("Label2",9,"Arial",LightSteelBlue,422,128,"128");
  GObj.AddLabel("Label3",9,"Arial",LightSteelBlue,294,128,"256");
  GObj.AddLabel("Label4",9,"Arial",LightSteelBlue,166,128,"384");
  GObj.AddLabel("Label5",9,"Arial",LightSteelBlue,40,128,"512");
  GObj.AddLabel("Label6",9,"Arial",LightSteelBlue,28,156,"N");
  GObj.AddLabel("Label7",9,"Arial",LightSteelBlue,569,141,"0.00");
  GObj.AddLabel("Label8",9,"Arial",LightSteelBlue,569,191,"0.25");
  GObj.AddLabel("Label9",9,"Arial",LightSteelBlue,569,241,"0.50");
  GObj.AddLabel("Label10",9,"Arial",LightSteelBlue,569,291,"0.75");
  GObj.AddLabel("Label11",9,"Arial",LightSteelBlue,569,341,"1.00");
  GObj.AddLabel("Label12",9,"Arial",LightSteelBlue,569,358,"U");
  GObj.AddLabel("Label13",9,"Arial",DarkGray,490,86,"Y-axis Mode");
  GObj.AddLabel("Label14",9,"Arial",DarkGray,285,86,"Input Data");
  GObj.AddLabel("Label15",9,"Arial",DarkGray,75,86,"Level");
  GObj.AddLabel("Label16",9,"Arial",DarkGray,185,86,"N");
  GObj.AddLabel("Label17",8,"Courier",DarkOliveGreen,64,64);
  GObj.AddLabel("Label18",8,"Courier",DarkOliveGreen,64,51);
  GObj.AddLabel("Label19",8,"Courier",DarkOliveGreen,64,38);
  GObj.AddLabel("Label20",8,"Courier",DarkOliveGreen,64,25);
  GObj.AddLabel("Label21",8,"Courier",DarkOliveGreen,64,12);
  GObj.AddButton("Butt1",185,18,C'32,32,32',8,"Arial",SlateGray,612,79,"Amplitude (line)",0);
  GObj.AddButton("Butt2",185,18,C'32,32,32',8,"Arial",Chocolate,612,61,"Amplitude (log)",1);
  GObj.AddButton("Butt3",185,18,C'32,32,32',8,"Arial",SlateGray,612,43,"Power (line)",0);
  GObj.AddButton("Butt4",185,18,C'32,32,32',8,"Arial",SlateGray,612,25,"Power (log)",0);
  GObj.AddButton("Butt5",185,18,C'32,32,32',8,"Arial",SlateGray,403,79,"External Data",0);
  GObj.AddButton("Butt6",185,18,C'32,32,32',8,"Arial",SlateGray,403,61,"Test 1. SMA(3)",0);
  GObj.AddButton("Butt7",185,18,C'32,32,32',8,"Arial",Chocolate,403,43,"Test 2. SMA(32)",1);
  GObj.AddButton("Butt8",185,18,C'32,32,32',8,"Arial",SlateGray,403,25,"Test 3. LWMA(12)",0);
  GObj.AddButton("Butt9",14,34,C'32,32,32',8,"Wingdings",SlateGray,36,78,"\x0431",0);
  GObj.AddButton("Butt10",14,34,C'32,32,32',8,"Wingdings",SlateGray,36,44,"\x0432",0);
  GObj.AddEdit("Edit1",35,18,Black,9,"Arial",SlateGray,180,102);
  GObj.AddTrendLine("Trdline1",C'32,32,32');
  GObj.AddTrendLine("Trdline2",C'32,32,32');
  GObj.AddTrendLine("Trdline3",C'32,32,32');
  GObj.AddTrendLine("Trdline4",C'32,32,32');
  GObj.AddTrendLine("Trdline5",C'32,32,32');
  GObj.AddTrendLine("Trdline6",C'32,32,32');
  GObj.AddTrendLine("Trdline7",C'32,32,32');
  GObj.AddTrendLine("Trdline8",C'32,32,32');
  GObj.AddArrowline("Arrline1",LightSteelBlue);
  GObj.AddArrowline("Arrline2",LightSteelBlue);
  GObj.AddRectangle("Rect1",C'72,72,72');
  GObj.AddRectangle("Rect2",C'72,72,72');
  GObj.AddRectangle("Rect3",C'72,72,72');
  GObj.AddRectangle("Rect4",DarkGray);
  GObj.AddRectangle("Rect5",C'72,72,72');
  }
//---------- Set object coordinate for Trend Line, Arroved Line and Rectangle --
void gr_object_coordinate()
  {
  GObj.MoveGrObject("Trdline1",48,150,48,360);
  GObj.MoveGrObject("Trdline2",176,150,176,360);
  GObj.MoveGrObject("Trdline3",304,150,304,360);
  GObj.MoveGrObject("Trdline4",432,150,432,360);
  GObj.MoveGrObject("Trdline5",42,350,560,350);
  GObj.MoveGrObject("Trdline6",42,300,560,300);
  GObj.MoveGrObject("Trdline7",42,250,560,250);
  GObj.MoveGrObject("Trdline8",42,200,560,200);
  GObj.MoveGrObject("Arrline1",560,150,28,150);
  GObj.MoveGrObject("Arrline2",560,150,560,370);
  GObj.MoveGrObject("Rect1",0,1,208,110);
  GObj.MoveGrObject("Rect2",208,1,416,110);
  GObj.MoveGrObject("Rect3",416,1,624,110);
  GObj.MoveGrObject("Rect4",0,1,624,400);
  GObj.MoveGrObject("Rect5",20,10,195,80);
  }
//+------------------------------------------------------------------+

Pour donner accès aux fonctions de la classe AllGrObject, créez l'objet GObj de cette classe. Dans la fonction OnInit() de l'indicateur, incluez l'appel de la fonction gr_object_create(), qui crée tous les objets graphiques nécessaires qui déterminent l'apparence et la fonctionnalité du panneau de commande de l'indicateur.

Dans la fonction OnCalculate ajoutez des appels des fonctions MainChart.SetOwnProperty() et gr_object_coordinate(); ainsi, les propriétés du graphique et les coordonnées des objets dessinés dessus seront restaurés à chaque nouvelle tick. Une telle restauration est nécessaire lorsqu'une nouvelle barre est formée au niveau du graphique initial ou que le graphique est déplacé à l'aide du bouton gauche de la souris ou lorsqu'un utilisateur modifie les propriétés du graphique. Après avoir compilé et chargé cet exemple de test, nous verrons les interfaces du panneau de contrôle ; voir fig. 1.

Fig. 1. Interface du panneau de commande. 

Fig. 1. Interface du panneau de commande.

 Afin de vous montrer visuellement l'emplacement du panneau de contrôle en rapport avec la carte, activez l'affichage de l'échelle de la carte dans l'exemple ci-dessus ; voir fig. 2.

  .Fig. 2. L'échelle de la carte.

Figure 2. L’ Échelle de la Carte 

L'Analyseur de Spectre

L'analyse d'un spectre dans l'indicateur est réalisée par 1024 graduations de la séquence d'entrée. L’analyse du spectre est effectuée à l’aide de l’algorithme rapide de Fourier transformation La fonction qui implémente l'algorithme FFT est tirée des publications du site web www.mql4.com. Pour les calculs, nous utilisons la fonction FFT de séquence d’entrée en temps réel ; son code est placé dans le fichier SpecAnalyzer.mqh. Toutes les actions nécessaires à l'analyse spectrale sont implémentées dans la fonction fft_calc(). 

void fft_calc()
  {
  int i,k;

  realfastfouriertransform(InpData,ArraySize(InpData),false);          // FFT
  for(i=1;i<ArraySize(Spectrum);i++)
    {
    k=i*2;
    Spectrum[i]=InpData[k]*InpData[k]+InpData[k+1]*InpData[k+1];    
    }
  Spectrum[0]=0.0;                             // Clear constant component level
  }

Lorsque la fonction fft_calc() est appelée, le tableau InpData[] doit comporter une séquence d'entrée à analyser. Après l'exécution de realfastfouriertransform(), le résultat de FFT sera placé dans ce tableau. De plus, le carré du modulo est calculé pour chaque harmonique à partir de la partie réelle et imaginaire des estimations du spectre ; le résultat est écrit dans le tableau Spectrum[]. L'indice d'élément dans le tableau Spectrum[] correspond au numéro d'harmonique. Comme la valeur calculée de la composante constante n'est pas utilisée dans l'indicateur, la valeur zéro est toujours attribuée à l'élément Spectrum[0] du tableau.

Selon la valeur de la variable InputSource, le tableau InpData[] peut être rempli soit avec des séquences de test, soit avec des données obtenues à partir d'un indicateur externe. Les données d'entrée sont formées dans la fonction get_input_data().

void get_input_data()
  {
  int i;
  
  ArrayInitialize(InpData,0.0);
  switch(InputSource)
    {
    case 0:                                                    // External Data
      if(ExtHandle!=INVALID_HANDLE)
        CopyBuffer(ExtHandle,0,0,ArraySize(InpData),InpData);
      break;
    case 1:                                                    // Test 1. SMA(3)
      for(i=0;i<3;i++)InpData[i]=1;
      break;
    case 2:                                                   // Test 2. SMA(32)
      for(i=0;i<32;i++)InpData[i]=1;
      break;
    case 3:                                                  // Test 3. LWMA(12)
      for(i=0;i<12;i++)InpData[i]=12-i;
      break;
    }
  }

Si la valeur de InputSource est égale à zéro, 1024 valeurs seront copiées dans le tableau d'entrée InpData[] à partir du tampon zéro de l'indicateur SAInpData.mq5. Les données pour l'analyse peuvent être formées soit dans l'indicateur lui-même, soit en appelant d'autres indicateurs à partir de celui-ci. Pour donner accès à l'indicateur SAInpData.mq5, la ligne suivante est ajoutée à la fonction OnInit(), elle détermine la valeur de la variable ExtHandle.

int OnInit() 
 {
 button. button. button.

 ExtHandle=iCustom(NULL,0,"SAInpData");  // External indicator Handle

 return(0);
 }

L'indicateur SAInpData.mq5 doit être placé dans le répertoire \MQL5\Indicators du terminal client. L'indicateur SAInpData.mq5 joint à cet article à titre d'exemple transmet une séquence aléatoire à l'analyseur. Pour que SAInpData.mq5 passe une autre séquence à l'analyseur, modifiez son code source.

En tant que séquences de test pour les fonctions get_input_data(), les caractéristiques d'impulsion des moyennes mobiles SMA(3), SMA(32) et LWMA(12) sont générées. En tenant compte du fait que la transformation de Fourier d'une caractéristique impulsionnelle d'un filtre correspond aux caractéristiques amplitude-fréquence de ce filtre, nous pouvons constater les caractéristiques amplitude-fréquence des moyennes mobiles si nous les sélectionnons comme séquences de test.

Pour normaliser le résultat de l'estimation du spectre qui est stocké dans le tableau Spectrum[] et le préparer son affichage dans le mode spécifié, la fonction norm_and_draw() est utilisée ; voir le fichier SpecAnalyzer.mq5. Selon le mode d'affichage choisi, cette fonction remplace le marquage du texte de l'axe Y.

Le résultat de l'estimation du spectre de la séquence d'entrée est affiché non seulement sous forme graphique, mais également sous forme de texte. Pour la représentation des résultats sous forme de texte, cinq objets graphiques de type « Label » sont créés ; ils correspondent à cinq lignes de texte affichées. La fonction list_levels() assure le remplissage de ces lignes avec des informations. 

void list_levels()
  {
  int m;
  string str;
  
  if(YdBFlag==0) str="%3u    %.5f";                     // If Y-axis mode = Line
  else str="%3u  %6.1f dB";                               // If Y-axis mode = dB
  m=ArraySize(ListArray)-5;
  if(ListPointer<1)ListPointer=1;
  if(ListPointer>m)ListPointer=m;
  GObj.LabelTxt("Label17",StringFormat(str,ListPointer,ListArray[ListPointer]));
  GObj.LabelTxt("Label18",StringFormat(str,ListPointer+1,ListArray[ListPointer+1]));
  GObj.LabelTxt("Label19",StringFormat(str,ListPointer+2,ListArray[ListPointer+2]));
  GObj.LabelTxt("Label20",StringFormat(str,ListPointer+3,ListArray[ListPointer+3]));
  GObj.LabelTxt("Label21",StringFormat(str,ListPointer+4,ListArray[ListPointer+4]));
  }

Les lignes affichent les valeurs des niveaux du tableau ListArray[] formaté à l'aide de la fonction StringFormat(). Selon le mode d'affichage actuel, ce tableau est rempli d'informations au sein de la fonction norm_and_draw(); voir le fichier SpecAnalyzer.mq5. Les informations du tableau ListArray[] sont affichées à partir de l'index du tableau égal à la valeur stockée dans la variable ListPointer. Vous pouvez modifier la valeur de la variable ListPointer, et donc, l'index de départ des lignes à afficher, en appuyant sur les boutons situés à droite du champ de sortie ou en spécifiant l'index nécessaire dans le champ de saisie. Les événements liés à l'appui sur ces boutons et à la finition des modifications sur le champ de saisie sont gérés dans la fonction OnChartEvent() de l'indicateur ; voir le fichier SpecAnalyzer.mq5.

L'apparence de l'indicateur SpecAnalyzer est illustrée dans la figure ci-dessous.

  Fig. 3. L'apparition de l'indicateur SpecAnalyzer.

Fig. 3. L'apparition de l'indicateur SpecAnalyzer.  

Conclusion

Comme indiqué précédemment, l'indicateur SpecAnalyzer.mq5 n'est qu'un prototype d'un analyseur de spectre complet ; dans l'article, il est utilisé comme exemple d'utilisation des objets graphiques. Pour créer un indicateur complet, vous devrez probablement améliorer son apparence, implémenter une interface plus pratique et améliorer l'algorithme d'estimation du spectre.

Vous pouvez considérablement améliorer l'interface de l'indicateur en utilisant l'objet graphique « Bitmap » pour son ornement, en créant une image pour son panneau de commande frontal dans un éditeur graphique et l’utiliser en tant que sous-couche sur laquelle les éléments de commande seront affichés. Une telle approche peut être utilisée pour créer des indicateurs avec des habillages modifiables( skins).

Littérature

  1. Yukio Sato. Introduction à la Gestion des Signaux.
  2. L. Rabiner, B. Gold. Théorie et Application du Traitement Numérique du Signal.
  3. S.L. Marple, Jr. Analyse Spectrale Numérique avec Applications.

Dossiers

  1. SpecAnalyzer.mq5 – l'indicateur décrit dans cet article.
  2. SpecAnalyzer.mqh – le fichier d'inclusion pour SpecAnalyzer.mq5.
  3. SAInpData.mq5 – l'indicateur utilisé pour l'organisation de l'accès aux données externes.

 

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

Fichiers joints |
SAInpData.mq5 (3.29 KB)
SpecAnalyzer.mq5 (15.39 KB)
SpecAnalyzer.mqh (20.79 KB)
Indicateurs et Systèmes de Trading de William Blau en MQL5. partie 1: Indicateurs Indicateurs et Systèmes de Trading de William Blau en MQL5. partie 1: Indicateurs
L'article présente les indicateurs, décrits dans le livre de William Blau "Dynamique, Direction, and Divergence". L'approche de William Blau nous permet d'estimer rapidement et avec précision les fluctuations de la courbe des prix, de déterminer la tendance des mouvements de prix et des tournants, et d'éliminer le bruit des prix. Pendant ce temps, nous sommes également en mesure de détecter les états de surachat/survente du marché et des signaux indiquant la fin d'une tendance et l'inversion du mouvement des prix.
calcul de moyenne des Séries de Prix pour les Calculs Intermédiaires Sans Utiliser de Tampons Supplémentaires calcul de moyenne des Séries de Prix pour les Calculs Intermédiaires Sans Utiliser de Tampons Supplémentaires
Cet article concerne les algorithmes traditionnels et inhabituels de calcul de moyenne regroupés dans les classes les plus simples et à type unique. Ils sont destinés à une utilisation universelle dans presque toutes les élaborations d'indicateurs. J'espère que les classes proposées seront une bonne alternative aux appels « encombrants » d'indicateurs personnalisés et techniques.
Utilisez les canaux MQL5.community et les discussions de groupe Utilisez les canaux MQL5.community et les discussions de groupe
Le site MQL5.com rassemble des traders du monde entier. Les utilisateurs publient des articles, partagent des codes gratuits, vendent des produits sur le Market, effectuent des commandes auprès des Freelance et copient des signaux de trading. Vous pouvez communiquer avec eux sur le Forum, dans les chats des traders et dans les canaux MetaTrader.
Créez votre propre Veille du Marché en utilisant les classes de bibliothèque standard Créez votre propre Veille du Marché en utilisant les classes de bibliothèque standard
Le nouveau terminal client MetaTrader 5 et le langage MQL5 offrent de nouvelles opportunités pour présenter des informations visuelles au trader. Dans cet article, nous proposons un ensemble de classes universel et extensible, qui gère tout le travail d'organisation de l'affichage des informations textuelles arbitraires sur le graphique. L'exemple de l'indicateur Veille du Marché est présenté.