English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Canaux de traçage - Schéma intérieure et extérieure

Canaux de traçage - Schéma intérieure et extérieure

MetaTrader 5Indicateurs | 12 janvier 2022, 14:15
198 0
Dmitriy Skub
Dmitriy Skub

Introduction

J’estime que ce ne sera pas une exagération, si je dis que les canaux sont l'outil le plus populaire pour l'analyse du marché et la prise de décisions en trade après les moyennes mobiles. Dans le premier article de la série, consacré aux canaux, nous allons aborder la base mathématique et la implémentation théorique d'un indicateur qui trace un canal défini par trois extremums sur l'écran du terminal client.

A première vue, tracer un canal semble être une tâche facile, puisqu'elle est basée sur l'équation d'une ligne droite, qui est enseignée à l'école primaire. Cependant, son implémentation pratique dans le terminal client implique de nombreuses questions auxquelles il est impossible de répondre directement.

Comment organiser au mieux le réglage des extremum et le suivi de leurs évolutions ? Que faire et comment tracer un canal, si sa partie médiane repose sur les barres manquées ? Que se passe-t-il si l'extrémité gauche d'une chaîne est le vendredi et la droite est le lundi, donc les jours de congé sans barreaux sont entre eux ? Comment pouvons-nous obtenir les valeurs actuelles des bordures d'un canal ?

Ces questions et autres sont abordées dans le premier article de la série d'articles sur les chaînes. Ici vous pouvez également trouver l’implémentation du tracé des canaux par trois extremums déterminés en utilisant les classes standard et l'approche orientée-objet. Nous allons implémenter le tiroir de canaux sous la forme d'un indicateur.


Réglage des extremums

En fait, la position d'un canal sur un graphique est déterminée par au moins trois extremums. Si on donne une définition à un extremum alors on peut accepter celle-ci : c'est la valeur maximale ou minimale d'une fonction sur une plage donnée. Un point où un extremum est atteint est appelé unpoint extremum. Respectivement, si un minimum est atteint, le point extremum est appelé point minimum, et s'il s'agit d'un maximum, il est appelépoint maximum.

L'analyse mathématique définit un autre terme - un extremum local (le minimum et le maximum respectivement). Au point maximum (minimum), la valeur de la fonction est supérieure (inférieure) aux valeurs de tous les points adjacents. La définition est tirée de Wikipédia (traduit du russe).

Dans le but de tracer des canaux, nous avons besoin d'extremums locaux. Montrons-le graphiquement sans entrer dans les formules mathématiques. Sur la figure 1 située ci-dessous, il y a trois extremums locaux marqués avec les niveaux de prix rouges. Les points du rectangle indiquent deux maximums et un minimum :

Figure 1. Les exemples d’extremums locaux

Figure 1. Les exemples d'extremums locaux

Pas tous les extremums existants sont marqués sur le graphique, il n'y a que les plus importants. Pour un chandelier ou un graphique à barres, il est pratique d'utiliser le terme "fractal" pour définir les extremums - lorsque plusieurs barres adjacentes à gauche et à droite sont strictement descendantes ou ascendantes (voir fig.1).

Étant donné que nous n'avons pas pour objectif de créer un tiroir de canaux automatique, la position des extremums sera définie comme indiqué sur la fig. 1 - par la position sur les axes temps et prix. Les plus appropriés à cet effet sont les étiquettes de prix - les objets graphiques spéciaux du terminal client MetaTrader 5. Une étiquette de prix a les propriétés de coordonnées de temps et de prix, ce qui permet d'identifier définitivement un point extremum sur un graphique.


L'objet de stockage des extremums est la classe TExtremum

La première chose que nous devons faire est d’élaborer une classe conteneur pour stocker les extremums et une classe pour manipuler un groupe d'extremums. Puisque nous allons utiliser desclasses standard comprises dans le terminal autant que possible , la classe TExtremum sera héritée depuis la classe standard CObject. La description de notre classe est donnée ci-dessous:

class TExtremum : public CObject
{
private:
  datetime  extr_datetime;              // data/time in an extremum point
  double    extr_price;                 // price in an extremum point
        
protected:
  virtual int  Compare(const CObject* _node, int _mode = 0) const;

public:
  void      TExtremum();               // constructor
  void      ~TExtremum();              // destructor
  void      SetExtremum(datetime _time, double _price);  // change date/time and price in an extremum point
  void      SetDateTime(datetime _time);                 // change date/time in an extremum point
  void      SetPrice(double _price);  // change price in an extremum point

public:
  datetime  GetDateTime() const;      // get date/time in an extremum point
  double    GetPrice() const;         // get price in an extremum point

public:
  virtual bool  SaveExtremum(string _dt_name, string _p_name);  // save extremum
  virtual bool  LoadExtremum(string _dt_name, string _p_name);  // load extremum
  virtual bool  DeleteExtremum(string _dt_name, string _p_name);// delete extremum
};

La plupart des méthodes sont triviales et ne valent pas la peine de prêter attention à leur implémentation. La chose sur laquelle nous devrions nous attarder est la méthode TExtremum::Compare Cette méthode est déclarée dans la classeCObject et est utilisée pour le tri dans une liste. Nous avons implémenté de la manière suivante :

//---------------------------------------------------------------------
//  Comparing two extremums by time:
//---------------------------------------------------------------------
int TExtremum::Compare(const CObject* _node, int _mode = 0) const
{
  datetime  temp = ((TExtremum* )_node).GetDateTime();
  datetime  curr = GetDateTime();
  if(curr > temp)
  {
    return(_mode > 0 ? 1 : -1);
  }
  else if(curr < temp)
  {
    return(_mode > 0 ? -1 : 1);
  }

  return(0);
}

Le paramètre_mode est ici destiné à définir un sens de tri. S'il est supérieur à zéro, alors le tri est direct (croissant), dans le cas contraire, il est inversé (décroissant).

En plus de cela, il existe deux méthodes destinées à sauvegarder/charger un extremum. Stockons notre extremum dans des variables globales. Voici ces méthodes :

//---------------------------------------------------------------------
//  Save extremum (date/time):
//---------------------------------------------------------------------
bool TExtremum::SaveExtremum(string _dt_name, string _p_name)
{
  datetime  dt_result = GlobalVariableSet(_dt_name, (double)extr_datetime);
  datetime  p_result = GlobalVariableSet(_p_name, (double) extr_price);
  if(dt_result != 0 && p_result != 0)
  {
    return(true);
  }

  return(false);
}

//---------------------------------------------------------------------
//  Load extremum (date/time):
//---------------------------------------------------------------------
bool TExtremum::LoadExtremum(string _dt_name, string _p_name)
{
  double  dt_temp, p_temp;
  bool    result = GlobalVariableGet(_dt_name, dt_temp);
  result &= GlobalVariableGet(_p_name, p_temp);
  if(result != false)
  {
    extr_datetime = (datetime)dt_temp;
    extr_price = p_temp;
    return(true);
  }

  return(false);
}

Deux méthodes de lecture/écriture dans les variables globalesTExtremum::LoadExtremum et TExtremum::SaveExtremumenvoie vrai en cas d’exécution réussie.


Manipulation de la liste des extremums - la classe TExtremumList

Puisque nous avons besoin à la fois de stocker et de trier les extremums dans le temps, nous devons hériter de la classeTExtremumList depuis la classe standard CList. Avec cet héritage, nous obtenons un manipulateur universel d'extremums sans limites sur leur nombre et leur type. Cela permet d'étendre davantage le nombre de canaux qui sont tracés.. Par exemple, on peut ajouter le tracé du canal en cas de régression non linéaire de plusieurs extremums.

La description de cette classe est donnée ci-dessous :

class TExtremumList : public CList
{
private:
  string              channel_prefix;     // channel name (prefix)
  ENUM_TIMEFRAMES      chart_timeframe;    // current timeframe
  string              chart_symbol;       // work symbols of the chart

protected:
  string    MakeDTimeName(int _nmb);     // get name for saving/reading data/time of an extremum
  string    MakePriceName(int _nmb);     // get name for saving/reading price of an extremum

public:
  void      TExtremumList();             // конструктор
  void     ~TExtremumList();             // деструктор
  void     SetChannelParams(string _pref, string _symbol = NULL, ENUM_TIMEFRAMES _curr_tf = PERIOD_CURRENT);
  void     AddExtremum(datetime _time, double  _price);
  void     DeleteAllExtremum();
  void     SaveExtremumList();
  void     LoadExtremumList();
  int      FindExtremum(datetime _dt);  // search extremum by specified time

public:
  datetime GetDateTime(int _index);
  double   GetPrice(int _index);
};

La méthode principale de la classe est TExtremumList::AddExtremum. Il est destiné à ajouter un nouvel extremum à la liste. Le tri des extremums dans la liste par point d'extremum temps est effectué après ajout. Le code de cette méthode est donné ci-dessous :

void TExtremumList::AddExtremum(datetime _time, double  _price)
{
//  Create extremum:
  TExtremum*    extr = new TExtremum();
  extr.SetExtremum(_time, _price);

//  Add it in the list:
  Add(extr);

//  Sort:
  Sort(1);
}

Les méthodes suivantes de la classe de base sont utilisées ici : CList::Add - pour ajouter un nouvel élément à la liste, etCList::Sort- pour trier les éléments de la liste. La méthode TExtremum::Compare est utilisée dans CList::Sort.

Jetons un coup d'œil à la méthode de recherche d'un extremum avec l'heure donnée dans la listeTExtremumList::FindExtremum. Le code de la méthode est donné ci-dessous :

int TExtremumList::FindExtremum(datetime _dt)
{
  int           k = 0;
  TExtremum*    extr = (TExtremum*)(GetFirstNode());
  while(extr != NULL)
  {
    if(extr.GetDateTime() == _dt)
    {
      return(k);
    }
    extr = (TExtremum*)(GetNextNode());
  }
  return(-1);                     // extremum not found
}

Les méthodes suivantes de la classe de base sont utilisées ici : CList::GetFirstNode - pour obtenir le premier élément de la liste (si la liste est vide, elle renvoie un pointeur zéro), et CList::GetNextNode - pour obtenir l'élément suivant de la liste (s'il n'y a pas d'élément suivant et la liste est terminée, un pointeur zéro est renvoyé).

Note:

Il existe un pointeur vers un élément courant dans les données internes de la liste de classes CList Ce pointeur est modifié lors de l'appel de méthodes de déplacement dans la liste CList::GetFirstNode, CList::GetNextNode, CList::GetPrevNode, etc.). Si aucune de ces méthodes n'a été appelée auparavant, le pointeur vers un élément courant pointe vers le premier.

Dans le cas où un extremum avec le temps donné est trouvé avec succès, la méthode TExtremumList::FindExtremum indexe de l'élément trouvé. Si un tel élément n’existe pas, il renvoie -1.

Les méthodes TExtremum::MakeDTimeName etTExtremum::MakePriceName sont auxiliaires. Ils sont destinés à obtenir les noms des variables globales qui sont utilisées lors de l'enregistrement et de la lecture des extremums. Ces méthodes ont l'implémentation suivante :

string TExtremumList::MakeDTimeName(int _nmb)
{
  string    name;
  StringConcatenate(name, channel_prefix, "_", channel_symbol, "_", channel_timeframe, "_DTime_Extr", _nmb);
  return(name);
}

string TExtremumList::MakePriceName( int _nmb )
{
  string    name;
  StringConcatenate(name, channel_prefix, "_", channel_symbol, "_", channel_timeframe, "_Price_DTime_Extr", _nmb);
  return(name);
}

Un exemple de nom obtenu : "MainChannel_EURUSD_5_DTime_Extr1". Ce nom correspond à un point extremum temporaire du canal MainChannel (nom conventionnel), le symbole EURUSD, l'intervalle de temps 5M et l'extremum numéro 1. Le numéro d'un extremum est attribué par ordre croissant de son temps, à partir de 1. Pratiquement, il s'agit de l'index décalé sur 1 dans une liste triée ascendante.

Un exemple de valeur de trois extremums enregistrés dans le terminal est illustré dans la figure ci-dessous :

Figure 2. Les extremums stockés dans les variables globales

Figure 2. Les extremums stockés dans les variables globales

Les classes décrites ci-dessus sont jointes à l'article dans le fichierExtremumClasses.mqh.


Indicateur de Réglage Manuel des Extremums - ExtremumHandSet

Eh bien, nous avons tout le nécessaire pour élaborer le premier indicateur, à l'aide duquel nous allons définir la position des extremums en mode manuel. Le code de l'indicateur est joint à l'article dans le fichier ExtremumHandSet.MQ5. Analysons son tracé en détail.

Tout d'abord, imaginons visuellement ce que nous souhaitons voir à l'écran :

Figure 3. L'indicateur de réglage des extremums

Figure 3. L'indicateur de réglage des extremums

En utilisant les étiquettes de prix de gauche, nous définissons les positions des extremums sur les axes de temps et de prix du graphique. L'indicateur doit déterminer la position de ces étiquettes sur le graphique, afficher des points extremum temporaires à l'écran et les enregistrer dans les variables globales du terminal client au format décrit ci-dessus. De plus, l'indicateur doit suivre le déplacement des étiquettes de prix sur le graphique et corriger les points extremum temporaires chargés.

Le suivi du déplacement des étiquettes de prix sur le graphique sera effectué une fois par seconde. Cela permettra au système d'être indépendant de l’arrivée des cotations et des jours ouvrés/non ouvrés.

Tout d'abord, connectons les bibliothèques requises :

//---------------------------------------------------------------------
//  Included libraries:
//---------------------------------------------------------------------
#include  <TextDisplay.mqh>
#include  <ExtremumClasses.mqh>

La première bibliothèque comporte les classes d'organisation de l'affichage des informations textuelles à l'écran (voir l'article"Créer votre propre veille de marché en utilisant les classes de bibliothèques"). En l'utilisant, nous allons afficher les valeurs des points extremum temporaires.

Puis nous ajoutons les paramètres d’entrée de l'indicateur (seuls les principaux sont décrits ici) :

input string  PrefixString = "MainChannel";
//---------------------------------------------------------------------
input color   ExtremumPointColor = Yellow;
//---------------------------------------------------------------------
input bool    ShowInfo = true;

Le premier paramètrePrefixString définit un préfixe utilisé pour composer les noms de variables globales lors de l’écriture/lecture d'un extremum. Il offre également la possibilité d'utiliser plusieurs indicateurs de ce type sur un même graphique. La seule chose à faire est de leur définir des préfixes différents.

Le paramètreExtremumPointColor définit une couleur pour les étiquettes de prix de gauche qui déterminent la position des extremums. Les étiquettes de prix doivent être d'une couleur déterminée. Cette concordance est vérifiée dans l'indicateur. Les étiquettes avec des paramètres différents sont ignorées.

Le paramètreShowInfo contrôle l'affichage des informations textuelles sur les points extrêmes déterminés à l'écran.

Ensuite, créons les objets pour afficher des informations et manipuler les extremums :

TableDisplay    TitlesDisplay;    // displaying information on the screen
//---------------------------------------------------------------------
TExtremumList*  PrevExtr_List;    // list of previous extremums
TExtremumList*  CurrExtr_List;    // list of current extremums
TExtremumList*  NewExtr_List;     // list of new extremums

Ces objets sont initialisés comme suit :

PrevExtr_List = new TExtremumList();
PrevExtr_List.SetChannelParams(PrefixString, Symbol(), Period());
PrevExtr_List.LoadExtremumList();

CurrExtr_List = PrevExtr_List;

NewExtr_List = new TExtremumList();
NewExtr_List.SetChannelParams(PrefixString, Symbol(), Period());

Dans la listePrevExtr_Listnous chargeons les extremums à partir des variables globales en utilisant la méthodeTExtremumList::LoadExtremumList. Cette liste stockera les extremums pour les comparer avec les nouveaux, qui seront lus à partir d'un graphique en faisant glisser les étiquettes de prix sur l'écran.

La listeCurrExtr_List est utilisée comme liste courante, elle stocke les actuels extremums. Puisqu’au début nous n'avons que les extremums lus à partir des variables globales, ils sont considérés comme les réels.

Dans la liste NewExtr_List nous allons rédiger les nouveaux extremums trouvés sur le graphique.

Jetons un coup d'œil aux principales fonctions utilisées dans l'indicateur. La première fonctionFindExtremumPoints est utilisée pour lire et vérifier les paramètres des étiquettes de prix qui déterminent la position des extremums :

bool FindExtremumPoints(long _chart_id)
{
  string  name;

//  1. Search for the total number of objects with specified parameters and write them to the list:
  int total_objects = ObjectsTotal(_chart_id, -1, OBJ_ARROW_LEFT_PRICE);
  if(total_objects <= 0)
  {
    return(false);
  }

  NewExtr_List.Clear();
  for(int i = 0; i < total_objects; i++)
  {
    name = ObjectName(_chart_id, i, -1, OBJ_ARROW_LEFT_PRICE);

    if( IsGraphicObjectGood(_chart_id, name, OBJ_ARROW_LEFT_PRICE, ExtremumPointColor) == true)
    {
      NewExtr_List.AddExtremum(ObjectGetInteger( _chart_id, name, OBJPROP_TIME),
                               ObjectGetDouble(_chart_id, name, OBJPROP_PRICE));
    }
  }

//  2. If three extremums are found, we can try to draw a channel:
  if(NewExtr_List.Total() == 3)
  {

//  Save the list of new extremums:
    NewExtr_List.SaveExtremumList();
    return(true);
  }

  NewExtr_List.Clear();
  return(false);
}

Tout d'abord, la listeNewExtr_List est effacée en appelant la méthodeTExtremumList::Clear , puis tous les points extremums trouvés, qui disposent des paramètres spécifiés, y sont ajoutés. Si le nombre de points trouvés est de trois, alors la liste est enregistrée dans les variables globales et la fonction renvoie 'true'.

L'autre fonctionCheakExtremumMoving suit le déplacement des points extrêmes sur le graphique Si au moins un point est déplacé le long de l'axe temporel du graphique, cette fonction renvoie « vrai ».

Son code est donné ci-dessous :

//---------------------------------------------------------------------
//  Check whether extremums have been moved on the screen:
//---------------------------------------------------------------------
bool CheakExtremumMoving()
{
  if(FindExtremumLines(0) == true)
  {
    int  count = NewExtr_List.Total();
    int  index;
    for(int i = 0; i < count; i++)
    {
      index = CurrExtr_List.FindExtremum(NewExtr_List.GetDateTime(i));

//  If a new extremum is found:
      if(index == -1)
      {
        PrevExtr_List = CurrExtr_List;
        CurrExtr_List = NewExtr_List;
        return(true);
      }
    }
    CurrExtr_List = PrevExtr_List;
  }

  return(false);
}

Nous avons réfléchi à la manière de définir les points extrêmes en mode manuel. Nous avons l'indicateur prêt qui permet de contrôler ce processus et de rédiger les points dans les variables globales. Le code complet de l'indicateur se trouve dans le fichier joint ExtremumHandSet.mq5. Nous pouvons maintenant passer à la partie principale - tracer un canal.


Tracer un canal - Un peu de théorie

Un canal linéaire se compose de deux lignes parallèles qui passent strictement par des points extrêmes. De plus, une ligne doit passer par deux points et l'autre doit passer par celui qui reste parallèle à la première ligne. Cela peut être indiqué dans une image simple:

Tracer un canal à l'aide de trois points extrêmes

Figure 4. Tracer un canal à l'aide de trois points extremum

De par note connaissance en géométrie, une seule ligne droite peut être tracée à travers deux points. Cette ligne est de couleur rouge dans la fig. 4. On pense à deux points qui ont les coordonnées suivantes - (T1, P1) et (T2, P2) ; les points sont marqués des lettres A et B. L'équation de cette droite est :

(1) P(t) = P1 + (t - T1)*(P2 - P1) / (T2 - T1) ; P(t) ici est le prix calculé à l'instant 't'.


A travers le point C (le troisième extremum), nous devons tracer une autre ligne droite parallèle à la première. Cette ligne est de couleur verte dans la fig. 3. Les points T1 et T2 étant les mêmes pour les deux lignes, nous devrions trouver les valeurs de P1' et P2' (cf. fig. 4).

Avant d'aller de l'avant, nous devons faire une remarque importante. Le graphique du terminal n'affiche pas les "trous" temporels. Par exemple, les jours de congé, lorsque les cotations ne parviennent pas au terminal, doivent être affichées comme des ruptures de prix. Et c'est dommage qu'ils ne le soient pas. Quel est l'intérêt de regarder un graphique vide ? Cependant, si nous utilisons le temps absolu dans l'équation ci-dessus, nous obtiendrons un mauvais canal.

Heureusement, la situation n'est pas désespérée. Si nous modifions le temps absolu en nombre relatif d'une barre, nous pourrons alors utiliser ces coordonnées pour tracer un canal, car l'énumération des barres ne peut pas avoir de pauses (en pratique, il s'agit d'un indice dans un tableau de prix).

Si nous allons plus loin et admettons que le point A de la fig. 4 se trouve toujours sur une coordonnée zéro (barre zéro) de l'axe du temps, alors notre équation deviendra encore plus facile. So, T1=0, T3=B3,Т2=В2. В3 et В2 sont ici les numéros d'une barre par rapport au point Т1 (c'est-à-dire le point zéro). Il est clair que cette hypothèse ne conduit pas à une inclinaison de la ligne. On obtient alors l'équation suivante d'une droite passant par les points A et B :

(2) P(n) = P1 + n * (P2-P1) / B2, où P(n) est le prix calculé pour une barre portant le numéro 'n'.


Ainsi, nous connaissons les valeurs P1, P2, P3 et B2, B3. Maintenant, nous devons trouver les valeurs P1' et P2'. En combinant deux équations et en les résolvant, nous obtenons les formules suivantes, à l'aide desquelles nous pouvons trouver les valeurs inconnues :

(3)   P1' = P3 - B3 * (P2 - P1) / B2

(4)   P2' = P2 - P1 + P1'


Comme nous trouvons la valeur P1' et la substituons à la formule(4), nous obtiendrons la valeur P2'. Nous avons maintenant la base théorique pour tracer un canal. Commençons son implémentation


Tracer les bordures des canaux - la classe TChannelBorderObject

Cette classe est dérivée de la classe standard CChartObjectTrend. Son but est de stocker tous les paramètres liés aux bordures d'un canal ainsi que de tracer/supprimer les lignes de bordure et de contrôler les paramètres graphiques de ces lignes.

La description de cette classe est donnée ci-dessous :

class TChannelBorderObject : public CChartObjectTrend
{
//  General properties of a border:
private:
  bool             is_created;       // whether the graphical object is created on the screen
  long             chart_id;         // identifier of the chart window
  int              window;           // identifier of the subwindow

//  Parameters of a border line:
private:
  string           border_name;      // name of the border line
  color            border_color;     // color of the border line
  int              border_width;     // thickness of the border line
  ENUM_LINE_STYLE   border_style;     // style of the border line

//  Coordinates of a border:
private:
  datetime         point_left;       // time of the left point (T1)
  datetime         point_right;      // time of the right point (T2)
  double           price_left;       // price of the left point (P1)
  double           price_right;      // price of the right point (P2)

public:
  void     TChannelBorderObject();  // constructor
  void    ~TChannelBorderObject();  // destructor
  bool     IsCreated();             // check whether the line is created

//  Creating/deleting a line:
public:
  bool     CreateBorder(long _chart_id, int _window, string _name, datetime _t_left, datetime _t_right, 
                           double _p_left, double _p_right, color _color, int _width, ENUM_LINE_STYLE _style);
  bool     CreateBorder(long _chart_id, int _window, string _name, datetime _t_left, datetime _t_right, 
                           double _p_left, double _p_right);
  bool     CreateBorder(datetime _t_left, datetime _t_right, double _p_left, double _p_right);
  bool     RemoveBorder();          // delete line from the chart

//  Setting parameters of the line:
public:
  void     SetCommonParams(long _chart_id, int _window, string _name);
  bool     SetBorderParams(color _color, int _width, ENUM_LINE_STYLE _style);
  bool     SetBorderColor(color _color);
  bool     SetBorderWidth(int _width);
  bool     SetBorderStyle(ENUM_LINE_STYLE _style);

//  Getting values on the line:
  double   GetPrice(datetime _dt); // get price value in the specified position of the border line
};

Cette classe n'a pas besoin de commentaires particuliers.

Ne prêtons attention qu'à la méthode d'obtention du prix frontière dans un point spécifié :

//---------------------------------------------------------------------
//  Get price value in the specified position of the border line:
//---------------------------------------------------------------------
double TChannelBorderObject::GetPrice(datetime _dt)
{
//  If the graphical object is created:
  if(is_created == true)
  {
    return(ObjectGetValueByTime( chart_id, border_name, _dt));
  }
  return(0.0);
}

La fonction du terminal ObjectGetValueByTime est utilisée ici ; il renvoie la valeur du prix pour une durée déterminée. Il est pratique d'utiliser les possibilités du terminal au lieu de calculer la valeur à l'aide d'une formule mathématique.


Tracer un canal - la classe TSlideChannelObject

Cette classe est dérivée de la classe standardCList. Son but est le suivant :

  • stocker des objets de la classeTChannelBorderObject et effectuer différentes actions avec eux ;
  • calculer des points pour tracer les lignes requises qui composent un canal ;
  • mémoriser et modifier les paramètres d'un canal ;
  • obtenir des valeurs calculées qui décrivent un canal tracé (sa hauteur, les valeurs de prix sur les frontières, etc.);

Le code qui décrit cette classe est trop gros pour être montré ici complètement. Ceux qui le souhaitent peuvent le voir dans le fichierSlideChannelClasses.mqh joint à l'article. Analysons-en quelques parties principales.

Tout d'abord, il s'agit d'obtenir des valeurs B2 et B3 aux points T2 et T3 respectivement (voir fig.4). Le code suivant est utilisé :

//  Get relative shifts in bars relatively to the extremum points:
  total_bars = Bars(symbol, time_frame);     // total number of bars in history
  if(total_bars == 0)
  {
    return(false);                           // channel cannot be drawn
  }
  double  B2 = Bars(symbol, time_frame, point_left, point_right);
  double  B3 = Bars(symbol, time_frame, point_left, point_middle);

Pour éviter une situation d'appel de barres absentes, nous utilisons la fonction du terminal Bars qui renvoie le nombre de barres dans l'historique pour un symbole et une période spécifiés. Si l'information n'est pas encore formée, la fonction renverra une valeur zéro ; il sert à vérifier.

Si la fonction renvoie une valeur non nulle, alors nous pouvons obtenir les valeurs В2 et В3. Cela se fait en utilisant la même fonction Bars mais en l'appelant sous l'autre forme. Nous fixons des limites de temps et obtenons le nombre de barres dans cette plage. Puisque notre bordure gauche est la même, nous obtenons le décalage en barres pour les points Т2 et Т3. Le décalage pour le point Т1 est toujours égal à zéro.

Nous pouvons maintenant calculer tous les points des lignes de canal. Il peut y en avoir au maximum de neuf, puisque notre canal affichera (en plus des bordures supérieure et inférieure) la ligne médiane et les lignes de zones de pourcentage autour des bordures et de la ligne médiane.


Analysons la partie essentielle du calcul. L'intégralité du calcul est dans la méthodeTSlideChannelObject::CalcChannel.

//  Coefficient of the line inclination:
  koeff_A = (price_right - price_left) / B2;

//  Price value on the AB line in the point T3:
  double  P3_AB = price_left + B3 * koeff_A;

// Determine the channel type - 2MAX_1MIN или 1MAX_2MIN:
  if(P3_AB > price_middle)              // 2MAX_1MIN
  {
    channel_type = CHANNEL_2MAX_1MIN;

    left_prices[BORDER_UP_INDEX] = price_left;
    right_prices[BORDER_UP_INDEX] = price_right;
        
    left_prices[BORDER_DN_INDEX] = price_middle - B3 * koeff_A;
    right_prices[BORDER_DN_INDEX] = left_prices[BORDER_DN_INDEX] + (price_right - price_left);
  }
  else if(P3_AB < price_middle)         // 1MAX_2MIN
  {
    channel_type = CHANNEL_1MAX_2MIN;

    left_prices[BORDER_DN_INDEX] = price_left;
    right_prices[BORDER_DN_INDEX] = price_right;
        
    left_prices[BORDER_UP_INDEX] = price_middle - B3 * koeff_A;
    right_prices[BORDER_UP_INDEX] = left_prices[BORDER_UP_INDEX] + (price_right - price_left);
  }
  else
  {
    return( false );                      // channel cannot be drawn (all extremums are on the same line)
  }

left_prices et right_prices ici sont les tableaux qui stockent les coordonnées de prix des neuf lignes du canal. Les coordonnées temporelles de toutes les lignes du canal sont déjà connues.

Dans un premier temps, déterminez le coefficient d'inclinaison de la ligne (voir la formule(2)) koeff_A. Ensuite, nous calculons la valeur du prix de la ligne AB au point T3 (voir fig. 4). Il est fait pour déterminer quel type de canal est spécifié pour le tracé - par deux maximums et un minimum ou par deux minimums et un maximum. Nous vérifions quel point est le plus haut sur l'axe des prix - le point C ou le point qui a les coordonnées (P3', T3). En fonction de leur position, nous déterminons si le canal dispose du premier ou du deuxième type.

Dès que les coordonnées des deux lignes principales du canal (supérieure et inférieure) sont déterminées, le calcul des coordonnées des sept autres lignes n'est pas difficile à faire. Par exemple, nous calculons les coordonnées de la ligne médiane en utilisant les coordonnées des bords supérieur et inférieur du canal de la manière suivante :

  left_prices[BORDER_MD_INDEX] = (left_prices[BORDER_DN_INDEX] + left_prices[BORDER_UP_INDEX ]) / 2.0;
  right_prices[BORDER_MD_INDEX] = (right_prices[BORDER_DN_INDEX] + right_prices[BORDER_UP_INDEX]) / 2.0;

Il suffit de prendre la valeur moyenne des bordures supérieure et inférieure du canal.


Indicateur de tracé d'un canal par extremums déterminés - SlideChannel

Eh bien, nous avons déjà la classe pour tracer un canal. Écrivons maintenant un indicateur qui lira les paramètres des extremums à partir des variables globales et tracera un canal sur un graphique. Il ressemblera à ceci :

Figure 5.L’exemple d’un canal tracè à l’aide d’extremums

Figure 5. L'exemple d'un canal tracé à l'aide d'extremums

Les informations sur le canal tracé sont également affichées ici - sa largeur, la distance en points du prix actuel et les bords du canal et la ligne médiane.

Connectons les bibliothèques requises :

#include  <TextDisplay.mqh>
#include  <SlideChannelClasses.mqh>

La première bibliothèque comporte les classes d'organisation de l'affichage des informations textuelles à l'écran (voir l'article"Créer votre propre veille de marché en utilisant les classes de bibliothèques"). En l'utilisant, nous allons afficher les valeurs des points extremum temporaires.

Ajoutez ensuite les paramètres d'entrée de l'indicateur (seuls les principaux sont décrits ici) :

input string          PrefixString = "MainChannel";
//---------------------------------------------------------------------
input ENUM_TIMEFRAMES  ExtremumTimeFrame = PERIOD_CURRENT;
//---------------------------------------------------------------------
input bool            ShowInfo = true;

Le premier paramètrePrefixString, identique à celui de l'indicateur ExtremumHandSet, définit un préfixe utilisé pour composer le nom des variables globales lors de la lecture des extremums. Il offre également la possibilité d'utiliser plusieurs indicateurs de ce type sur un même graphique. La seule chose à faire est de leur définir des préfixes différents.

Le paramètre ExtremumTimeFrame définit un délai, qui sera utilisé pour lire les points extremum à partir des variables globales. C'est un paramètre très utile. Il permet de tracer des canaux synchrones sur différents intervalles de temps Par exemple, si vous définissez les extremums de H1, vous pouvez tracer le même canal sur l’intervalle de temps M5. Pour le faire, il suffit d'ajouter notre indicateur de tracé des canaux au graphique M5 ; et il affichera de manière synchrone toutes les modifications.

Le paramètreShowInfo contrôle l'affichage des informations textuelles sur les paramètres du canal à l'écran.

Ensuite, créez des objets pour afficher les informations et tracer le canal :

TableDisplay         ChannalDisplay;  // displaying of general information about a channel on the screen
TableDisplay         BordersDisplay;  // displaying information about the borders of a channel on the screen
//---------------------------------------------------------------------
TSlideChannelObject  Channel;         // drawing of a channel

L'objet de tracé d'un canal est initialisé de la manière suivante :

  Channel.CreateChannel(PrefixString, 0, 0, Symbol(), period_current, curr_left_point, curr_middle_point, 
                        curr_right_point, curr_left_price, curr_middle_price, curr_right_price);
  Channel.SetBorderWidth(BorderWidth );
  Channel.SetmiddleWidth(middleLineWidth);
  Channel.SetUpBorderColor(UpBorderColor);
  Channel.SetDnBorderColor(DnBorderColor);
  Channel.SetmiddleColor(middleLineColor );
  Channel.ShowBorderZone(ShowBorderPercentageLines);
  Channel.BorderZonePercentage( PercentageZoneSize);
  Channel.Showmiddle(ShowmiddleLine);
  Channel.ShowmiddleZone( ShowmiddlePercentageLines);
  Channel.middleZonePercentage(PercentagemiddleZoneSize);

Ici, dans un premier temps, nous créons un canal en appelant la méthodeTSlideChannelObject::CreateChannel , puis nous définissons les paramètres requis de la ligne de canal. L’ordre d’établissement n'a pas d'importance, vous pouvez le faire vice versa - définissez les paramètres, puis créez le canal.

Le paramètreperiod_current est la période utilisée lors de la lecture des extremums des variables globales. Elle peut être différente de la période d'un graphique actuel.

Jetons un coup d'œil aux principales fonctions utilisées dans l'indicateur. La première fonctionGetExtremums est utilisée dans la lecture de la position des extremums et l’actualisation du canal en fonction des valeurs obtenues :

void GetExtremums()
{
  double  temp;
  string  name;

  StringConcatenate(name, PrefixString, "_", Symbol(), "_", period_current, "_DTime_Extr1");
  if( GlobalVariableGet(name, temp) != false)
  {
    curr_left_point = (datetime)temp;
  }

  StringConcatenate(name, PrefixString, "_", Symbol(), "_", period_current, "_DTime_Extr2");
  if( GlobalVariableGet(name, temp) != false)
  {
    curr_middle_point = (datetime)temp;
  }

  StringConcatenate(name, PrefixString, "_", Symbol(), "_", period_current, "_DTime_Extr3");
  if( GlobalVariableGet(name, temp) != false)
  {
    curr_right_point = (datetime)temp;
  }

  StringConcatenate(name, PrefixString, "_", Symbol(), "_", period_current, "_Price_Extr1");
  if( GlobalVariableGet(name, temp) != false)
  {
    curr_left_price = temp;
  }

  StringConcatenate(name, PrefixString, "_", Symbol( ), "_", period_current, "_Price_Extr2");
  if( GlobalVariableGet(name, temp) != false )
  {
    curr_middle_price = temp;
  }

  StringConcatenate(name, PrefixString, "_", Symbol(), "_", period_current, "_Price_Extr3");
  if( GlobalVariableGet(name, temp) != false)
  {
    curr_right_price = temp;
  }

//  Update the position of channel:
  Channel.SetExtremums(curr_left_point, curr_middle_point, curr_right_point, 
                       curr_left_price, curr_middle_price, curr_right_price);
}

Pour actualiser le canal à l'écran, nous utilisons la méthodeTSlideChannelObject::SetExtremums. Cette méthode recalcule les coordonnées des lignes du canal et retrace le canal à l'écran.

Un exemple de tracé d'une chaîne sur différents intervalles de temps est présenté dans la vidéo ci-dessous :


L’ordre des indicateurs de départ n'a pas vraiment d'importance, mais il est logique de démarrer l'indicateurExtremumHandSet dans un premier temps, puis d'ajouter trois left price labels de la couleur jaune (la couleur des étiquettes est déterminée dans les paramètres de l'indicateur, la couleur jaune est déterminée par défaut) et le début de l'indicateur SlideChannel qui trace le canal par les extremums déterminés.

Pour qu'un canal soit tracé de manière synchrone avec les extremums du premier graphique, vous devez définir l’intervalle de temps dans le paramètre ExtremumTimeFrame de l'indicateur SlideChannel de la même manière que celui du graphique où les extremums sont définis.

C’est la conséquence de la séparation de la fonction de réglage des points extrêmes du canal de la fonction de son tracé sur l'écran du terminal.


Conclusion

Nous avons considéré le cycle complet - du réglage de la position d'un canal sur l'écran à son tracé. Tout ne semblait pas si compliqué, notamment lors de l'utilisation des classes standard et de la OOP

Mais il y a une quête : comment utiliser les canaux pour travailler sur le marché. Premièrement, ils sont nécessaires à l'analyse technique de l'état actuel d'un instrument financier. Et deuxièmement, après l'analyse, ils sont nécessaires dans la prise de décisions. Les canaux peuvent grandement y contribuer.

Il est possible d’élaborer un Expert Advisor semi-automatique qui analysera les frontières d'un canal pour ouvrir ou clôturer une position. Cela peut fonctionner à la fois en cassant une frontière ou en la faisant reculer. Ca sera le thème du prochain article - Les méthodes de travail avec un Canal- Roll Back et Break Through.

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

Fichiers joints |
extremumclasses.mqh (12.58 KB)
extremumhandset.mq5 (11.89 KB)
slidechannel.mq5 (13.7 KB)
textdisplay.mqh (15.21 KB)
Création d’Expert Advisors Multiples sur la base de Modèles de Trading Création d’Expert Advisors Multiples sur la base de Modèles de Trading
L'utilisation de l'approche orientée-objet dans MQL5 simplifie considérablement la création d'Expert Advisors multidevises/multisystèmes/multi-périodes. Imaginez seulement, votre seul EA trade sur plusieurs dizaines de stratégies de trading, sur tous les instruments disponibles et sur tous les intervalles de temps possibles ! De plus, l' EA est facilement testé dans le testeur, et pour toutes les stratégies, comprises dans sa composition, il dispose d'un ou plusieurs systèmes fonctionnels de gestion de l'argent.
Calculs Parallèles dans MetaTrader 5 Calculs Parallèles dans MetaTrader 5
Le temps a été une grande valeur tout au long de l'histoire de l'humanité, et nous nous efforçons de ne pas le gaspiller inutilement. Cet article vous indiquera comment accélérer le travail de votre Expert Advisor si votre ordinateur dispose d'un processeur multi-noyau. De plus, l’implémentation de la méthode proposée ne nécessite la connaissance d'aucun autre langage que MQL5.
Les indicateurs des tendances micro, moyenne et principale Les indicateurs des tendances micro, moyenne et principale
Le but de cet article est d'étudier les possibilités de l'automatisation du trade et de l'analyse, sur la base de quelques idées d'un livre de James Hyerczyk "Pattern, Price & Time: Utilisation de la théorie de Gann dans les systèmes de trading" sous forme d'indicateurs et d'Expert Advisor. Sans prétendre à l'exhaustivité, nous n'étudions ici que le Modèle - la première partie de la théorie de Gann.
Concevoir et implémenter de nouveaux widgets GUI axés sur la classe CChartObject Concevoir et implémenter de nouveaux widgets GUI axés sur la classe CChartObject
Après avoir écrit un article précédent sur l'Expert Advisor semi-automatique avec interface graphique, il s'est avéré qu'il serait souhaitable d'améliorer l'interface avec de nouvelles fonctionnalités pour des indicateurs et des Expert Advisors plus complexes. Après m'être familiarisé avec les classes de bibliothèque standard MQL5, j'ai implémenté de nouveaux widgets. Cet article décrit un processus de conception et d’implémentation de nouveaux widgets d'interface graphique MQL5 pouvant être utilisés dans des indicateurs et des Expert Advisors. Les widgets présentés dans l'article sont CChartObjectSpinner, CChartObjectProgressBar et CChartObjectEditTable.