English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
L'indicateur ZigZag : Approche novatrice et nouvelles solutions

L'indicateur ZigZag : Approche novatrice et nouvelles solutions

MetaTrader 5Systèmes de trading | 13 janvier 2022, 10:42
632 0
Sergey Pavlov
Sergey Pavlov

Introduction

Chaque trader connaît sûrement l'indicateur ZigZag destiné à l'analyse des mouvements de prix d'amplitude donnée ou supérieure. Une ligne ZigZag est une ligne brisée dont les nœuds sont situés aux hauts et aux bas du graphique des prix.

Il existe de nombreuses variantes de cet indicateur : 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16. Pourtant, de nombreux développeurs de programmes MQL5 souhaitent créer leur propre ZigZag "idéal". Les principaux inconvénients de l'indicateur ZigZag sont les retards, les marquages incorrects des nœuds douteux (barre externe) et les performances insatisfaisantes.

À mon avis, l'implémentation ZigZag la plus élégante a été proposée par Yuri Kulikov (Yurich). En outre, il existe de très bons articles MQL4, tels que "Layman's Notes : ZigZag..." et "Show Must Go On, or Once Again about ZigZag". Le sujet semble avoir été largement exploré, avec un grand nombre de publications disponibles. Pourtant, il y a quelque chose de magnétisant là-dedans. Maintenant, cela a également attiré mon intérêt, notamment dans la possibilité de créer un indicateur ZigZag avancé.

Cet article décrit une méthode pour créer un ZigZag avancé à l'aide de l'indicateur Enveloppes. On suppose que nous pouvons trouver une certaine combinaison de paramètres d'entrée pour une série d'enveloppes, la plupart des nœuds ZigZag se trouvant dans les limites des bandes d'enveloppes.

 

Une méthode pour créer un indicateur ZigZag avancé

Nous nous fixerons un objectif : trouver les coordonnées de deux nœuds - le nœud courant et le nœud prédit (Fig. 1). Le nœud actuel est un nœud qui n'est pas encore terminé dont les coordonnées sont toujours recherchées ou ajustées. De plus, il est toujours sur la barre actuelle (zéro). Tout en étant dans le futur, un nœud prédit doit afficher le niveau estimé du prochain nœud ZigZag.

Prédiction de nouveaux nœuds de ZigZag

Fig. 1. Prédiction de nouveaux nœuds de ZigZag : le nœud actuel et le nœud suivant.

L'objectif est donc fixé et nous avons une idée de la façon d'utiliser les enveloppes de moyenne mobile comme base pour construire un indicateur avancé (Fig. 2). Nous allons rechercher des enveloppes dont l'écart par rapport aux nœuds de ZigZag est minime. Il semble tout à fait logique que les enveloppes pour les pics et les creux de ZigZag doivent être recherchées séparément.

Indicateurs de ZigZag et Enveloppes Moyennes Mobiles

Fig. 2. Indicateurs de ZigZag et enveloppes moyennes mobiles.

Pour augmenter la signification statistique de la prévision, au lieu d'utiliser seulement un ou même 10 indicateurs d'enveloppes, nous devrions utiliser un pool de 100 indicateurs ou plus avec des données d'entrée différentes. Ils différeront par la période de calcul de la moyenne de la ligne indicatrice principale et le prix utilisé (Haut pour les pics et Bas pour les creux). Introduisons les notations et formules suivantes :

  • ZZ - l'indicateur de ZigZag ;
  • ENV - la ligne principale de l'indicateur Enveloppes (coïncidant avec l'indicateur iMA) ;
  • Enveloppes(i) - valeur de la ligne principale de l'indicateur Enveloppes sur la ième barre ;
  • ZZ (élevé) - valeur de crête du zigzag ;
  • ZZ(Faible) - Valeur de creux du zigzag ;
  • ENV(High) - valeur de la ligne principale de l'indicateur Enveloppes correspondant à un pic de ZigZag ;
  • ENV(Low) - valeur de la ligne principale de l'indicateur Enveloppes correspondant à un creux de ZigZag ;
  • n_high- nombre de pics de ZigZag ;
  • n_low - nombre de creux de ZigZag.

Nous avons deux pools d'indicateurs : un pour les pics et l'autre pour les creux (environ 100 indicateurs chacun). Nous calculerons l'écart des nœuds de ZigZag par rapport à la ligne principale de l'indicateur Enveloppes pour chaque indicateur du pool et trouverons la moyenne arithmétique des écarts pour chaque indicateur de pool en utilisant les formules ci-dessus. La figure suivante montre un diagramme des écarts par rapport aux nœuds identifiés ZZ de la ligne principale ENV pour un indicateur.

Diagramme des déviations des nœuds ZZ par rapport à ENV

Fig. 3. Diagramme des déviations des nœuds ZZ par rapport à ENV.

La moyenne arithmétique des écarts sera utilisée pour déterminer le niveau auquel la ligne principale de l'indicateur Enveloppes doit être déplacée pour tracer les bandes d'enveloppe. Ainsi, nous aurons besoin de la moyenne arithmétique des écarts par rapport aux pics ZigZag pour tracer la ligne supérieure et de la moyenne arithmétique des écarts par rapport aux creux pour tracer la ligne inférieure de l'indicateur Enveloppes.

Ce sont des lignes d'enveloppes supérieures et inférieures que nous allons utiliser pour trouver des points caractéristiques et prédire des nœuds ZigZag. Encore une fois, nous nous intéressons au pool d'enveloppes constitué d'un ensemble d'indicateurs Enveloppes. La moyenne arithmétique des écarts des nœuds de ZigZag par rapport à la ligne principale d'une enveloppe donnée est calculée pour chaque indicateur. Après avoir tracé les lignes résultantes (la ligne supérieure et inférieure) du pool dans le graphique, nous pourrons voir ce qui suit :

Les lignes Enveloppes dans l'avion

Fig. 4. Les lignes d'enveloppes sur l'avion.

Si nous supposons que chaque ligne se trouve sur un plan séparé, alors que toutes créent ensemble une surface, la figure ci-dessus ne montre que la projection de chaque indicateur sur le plan du graphique des prix. Une image 3D de ces lignes sera à peu près la suivante :

Les lignes Enveloppes en 3D

Fig. 5. Les lignes Enveloppes en 3D.

Faisons maintenant une petite leçon de géométrie. Imaginez que le pool de lignes de l'indicateur Enveloppes est une surface 3D. Prenez un plan perpendiculaire au tableau des prix et coupez la surface à la barre actuelle (zéro).

En conséquence, nous obtenons une section transversale de la surface représentant une courbe (les figures ci-dessus illustrent un cas particulier où la courbe est une ligne droite). Pour faire la prévision, il suffit d'avoir les coordonnées de chaque point de la courbe qui seront ensuite utilisées dans les calculs.

Nous aurons besoin des caractéristiques de section transversale suivantes : point maximum et minimum, ainsi que le centre de gravité de la section transversale (la moyenne arithmétique de toutes les valeurs des points). Les points caractéristiques obtenus seront projetés sur la barre actuelle (zéro), les données pertinentes étant stockées dans l'historique. Ces points caractéristiques serviront de base aux nœuds de ZigZag actuels et suivants.

Étant donné que la recherche des bandes d'enveloppe est effectuée séparément pour les pics et les creux, nous devrions donc obtenir deux sections efficaces : une pour les pics et l'autre pour les creux.

Pour obtenir la prévision, nous utiliserons le point caractéristique le plus proche. Par exemple, lors de la recherche d'un pic de ZigZag, on prend les points caractéristiques de la section transversale résultant de l'intersection de la surface des lignes supérieures de l'indicateur Enveloppes avec un plan de coupe. A l'inverse, pour trouver un creux, on prend les points caractéristiques de la section transversale résultant de l'intersection de la surface des lignes inférieures de l'indicateur Enveloppes avec un plan de coupe.

 

Tester un nouvel indicateur

Maintenant que nous avons défini la méthode, créons l'indicateur. Nous allons d'abord trouver les derniers nœuds de l'indicateur ZigZag et les dessiner dans le graphique. À cette fin, nous utiliserons la classe AdvancedZigZag écrite pour la tâche à accomplir :

//+------------------------------------------------------------------+
//|                                               AdvancedZigZag.mqh |
//|                                           Copyright 2013, DC2008 |
//|                           https://www.mql5.com/ru/users/DC2008 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, DC2008"
#property link      "https://www.mql5.com/ru/users/DC2008"
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                 GetExtremums.mqh |
//+------------------------------------------------------------------+
#include <GetExtremums.mqh>   // author of the code Yurich
#property copyright "Copyright 2012, Yurich"
#property link      "https://www.mql5.com/ru/users/Yurich"
//+------------------------------------------------------------------+
//| ZigZag node structure                                            |
//+------------------------------------------------------------------+
struct MqlZigZag
  {
   double            price;   // Node coordinate
   datetime          t;       // Time
  };
//+------------------------------------------------------------------+
//| The AdvancedZigZag class                                         |
//+------------------------------------------------------------------+
class AdvancedZigZag
  {
private:
   MqlRates          rt[];
   dextremum         zz[];
   int               history;
   double            amplitude;
public:
   dextremum         zHL[];
   MqlZigZag         zzH[],zzL[];
   int               Count(const double range);
   int               Read(const int nodes);
                     AdvancedZigZag(const int bars);
                    ~AdvancedZigZag();
  };
//+------------------------------------------------------------------+
//| Class constructor                                                |
//+------------------------------------------------------------------+
AdvancedZigZag::AdvancedZigZag(const int bars)
  {
   history=bars;
   amplitude=0;
  }
//+------------------------------------------------------------------+
//| The Read method of the class                                     |
//+------------------------------------------------------------------+
int AdvancedZigZag::Read(const int nodes)
  {
   CopyRates(NULL,0,TimeCurrent(),history,rt);
   int cnt=GetExtremums(amplitude,rt,zHL,nodes);
   return(cnt);
  }
//+------------------------------------------------------------------+
//| The Count method of the class                                    |
//+------------------------------------------------------------------+
int AdvancedZigZag::Count(const double range)
  {
   amplitude=range;
   CopyRates(NULL,0,TimeCurrent(),history,rt);
   int cnt=GetExtremums(amplitude,rt,zz);
   ArrayResize(zzH,cnt);
   ArrayResize(zzL,cnt);
   int h=0;
   int l=0;
   for(int i=0; i<cnt; i++)
     {
      if(zz[i].type>0)
        {
         zzH[h]=(MqlZigZag)zz[i];
         h++;
        }
      else
        {
         zzL[l]=(MqlZigZag)zz[i];
         l++;
        }
     }
   ArrayResize(zzH,h);
   ArrayResize(zzL,l);
   return(cnt);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
AdvancedZigZag::~AdvancedZigZag()
  {
  }

Il existe au total deux méthodes :

  • La méthode Count trouve tous les nœuds de ZigZag sur une période de temps donnée (nombre de barres) et les enregistre dans divers tableaux, en séparant les pics des creux. De cette façon, il sera plus facile de faire l'analyse et le calcul des enveloppes ;
  • La méthode Read recherche les derniers nœuds et les enregistre dans un seul tableau. Nous avons besoin de cette méthode pour la visualisation de l'indicateur ZigZag ;

La bibliothèque GetExtremums (de Yury Kulikov) sera également nécessaire pour rechercher des nœuds.

Mettons l'indicateur à l'étude chez un Expert Advisor. Pourquoi un Expert Advisor et non un indicateur ? C'est bien sûr une question de goût mais cela me semble plus efficace ainsi. Les fonctionnalités graphiques d'Expert Advisor sont sans aucun doute plus faibles, mais nous gagnons en performances car les indicateurs de même symbole fonctionnent dans un seul flux, tandis que chaque EA fonctionne dans son propre flux distinct. Regardons le code :

//+------------------------------------------------------------------+
//|                                                   two_Comets.mq5 |
//|                                           Copyright 2013, DC2008 |
//|                           https://www.mql5.com/ru/users/DC2008 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, DC2008"
#property link      "https://www.mql5.com/ru/users/DC2008"
#property version   "1.00"
#include <AdvancedZigZag.mqh>
//--- Depth of history for the indicator calculation
input int      depth_stories=5000;  // Depth stories for calculating the indicator [bars]
//--- Minimum ZigZag amplitude value
input int      amplitude=100;        // The minimum value of the amplitude of the indicator [points]
//--- Declaring the class
AdvancedZigZag Azz(depth_stories);
//---
#define NUMBER_MA   227
#define START_MA    5
//--- macros
#define SIZE(i)                     (double)i*0.3<1?1:(int)(i*0.25)
#define ObjF1                       ObjectSetString(0,name,OBJPROP_FONT,"Wingdings")
#define ObjF2                       ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_CENTER)
#define ObjF3(T)                    ObjectSetInteger(0,name,OBJPROP_TIME,T)
#define ObjF4(P)                    ObjectSetDouble(0,name,OBJPROP_PRICE,P)
#define ObjF5(size)                 ObjectSetInteger(0,name,OBJPROP_FONTSIZE,size)
#define ObjF6(code)                 ObjectSetString(0,name,OBJPROP_TEXT,CharToString(code))
#define ObjF7(clr)                  ObjectSetInteger(0,name,OBJPROP_COLOR,clr)
#define ObjF8                       ObjectSetInteger(0,name,OBJPROP_COLOR,clrMagenta)
#define ObjF9                       ObjectSetInteger(0,name,OBJPROP_WIDTH,3)
#define ObjF10                      ObjectSetInteger(0,name,OBJPROP_BACK,true) 
#define ObjFont                     ObjF1;ObjF2;
#define ObjCoordinates(T,P)         ObjF3(T);ObjF4(P);
#define ObjProperty(size,code,clr)  ObjF5(size);ObjF6(code);ObjF7(clr);
#define ObjZZ                       ObjF8;ObjF9;ObjF10;
//---
double      MA[1],sumHi[NUMBER_MA],sumLo[NUMBER_MA];
int         handle_MA_H[NUMBER_MA],handle_MA_L[NUMBER_MA];
datetime    t[1];
int         H,L;
int         t_min,t_max;
int         err=-1;
double      sumH[2],maxH[2],minH[2];
double      sumL[2],maxL[2],minL[2];
string      name;
int         count;
int         shift;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   shift=PeriodSeconds()/30;
//--- calculation of ZigZag nodes using historical data
   Azz.Count(amplitude*Point());
   H=ArraySize(Azz.zzH);
   L=ArraySize(Azz.zzL);
   if(H<30 || L<30)
     {
      Print("Not enough data to calculate ZigZag nodes: "+
            "increase the depth of history; "+
            "or decrease the amplitude value.");
      return(-1);
     }
//---
   for(int i=0; i<NUMBER_MA; i++)
     {
      handle_MA_H[i]=iMA(NULL,0,i+START_MA,0,MODE_SMA,PRICE_HIGH);
      handle_MA_L[i]=iMA(NULL,0,i+START_MA,0,MODE_SMA,PRICE_LOW);
     }
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   ObjectsDeleteAll(0,-1,-1);
   for(int i=0; i<NUMBER_MA; i++)
     {
      IndicatorRelease(handle_MA_H[i]);
      IndicatorRelease(handle_MA_L[i]);
     }
//---
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+

void OnTick()
  {
//--- get the current bar's opening time value
   CopyTime(NULL,0,0,1,t);
//--- ZigZag: last 7 nodes
   count=Azz.Read(7);
   for(int i=1; i<count; i++)
     {
      name="ZZ"+(string)i;
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjectSetInteger(0,name,OBJPROP_COLOR,clrRed);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,10);
      ObjectSetInteger(0,name,OBJPROP_BACK,true);
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,Azz.zHL[i-1].value);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,Azz.zHL[i-1].time);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,Azz.zHL[i].value);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,Azz.zHL[i].time);
     }
//--- check for integrity of preliminary calculations
   if(err<0)
     {
      //--- calculate the sums of deviations of the nodes from MA for ZigZag peaks
      ArrayInitialize(sumHi,0.0);
      for(int j=H-1; j>=0; j--)
        {
         for(int i=0; i<NUMBER_MA; i++)
           {
            err=CopyBuffer(handle_MA_H[i],0,Azz.zzH[j].t,1,MA);
            if(err<0) return;
            sumHi[i]+=Azz.zzH[j].price-MA[0];
           }
        }
      //--- calculate the sums of deviations of the nodes from MA for ZigZag troughs
      ArrayInitialize(sumLo,0.0);
      for(int j=L-1; j>=0; j--)
        {
         for(int i=0; i<NUMBER_MA; i++)
           {
            err=CopyBuffer(handle_MA_L[i],0,Azz.zzL[j].t,1,MA);
            if(err<0) return;
            sumLo[i]+=MA[0]-Azz.zzL[j].price;
           }
        }
     }
  }
//+------------------------------------------------------------------+

Nous devons clarifier certaines choses ici :

  • L'indicateur iEnvelopes est remplacé par l'indicateur iMA. Il n'y a rien de faux ou de trompeur là-dedans. Le fait est que la ligne principale d'iEnvelopes coïncide avec iMA ! Il est donc plus pratique d'utiliser l'indicateur de moyenne mobile.
  • Nous utilisons deux pools de moyennes mobiles, constitués de 227 lignes chacun, faisant ainsi 454 indicateurs iMA au total ! C'est beaucoup ou peu ? Fondamentalement, c'est un grand nombre. Mais, tout d'abord, nous pouvons changer le nombre d'indicateurs, si nécessaire, et deuxièmement, nous avons besoin de statistiques. Quel est l'intérêt de chercher des enveloppes pour une douzaine de nœuds ? Il nous en faut au moins une centaine.
  • Les valeurs des indicateurs sont chargées dans le bloc OnTick() au lieu de OnInit(). Si le bloc de chargement de données est placé dans OnInit(), il est très probable que certaines données soient en retard à charger et les indicateurs ne seront par conséquent pas calculés avec précision et dans leur intégralité. Une fois toutes les données pour les calculs obtenues, la valeur de la variable err deviendra positive et ce bloc sera exclu du fonctionnement.

Ainsi, l'indicateur résultant trace les sept derniers nœuds ZigZag et calcule les coordonnées de tous les autres nœuds sur un historique donné (Fig. 6). Le calcul n'est effectué qu'une seule fois et nous utilisons ensuite les données calculées. Vous pouvez bien sûr l'implémenter de manière à permettre une mise à jour régulière des données mais dans cet article nous nous en tiendrons à un seul passage.

L'indicateur ZigZag (7 nœuds)

Fig. 6. L'indicateur ZigZag (7 nœuds).

Ensuite, traçons les sections transversales des surfaces des indicateurs Enveloppes. Pour ce faire, nous allons ajouter les éléments suivants à la méthode OnTick() :

//--- PEAKS
   sumH[0]=0.0;
   maxH[0]=0.0;
   minH[0]=0.0;
   for(int i=0; i<NUMBER_MA; i++)
     {
      CopyBuffer(handle_MA_H[i],0,t[0],1,MA);
      double envelope=MA[0]+sumHi[i]/H;
      if(i==0 || envelope<minH[0])
        {
         minH[0]=envelope;
         t_min=SIZE(i);
        }
      if(envelope>maxH[0])
        {
         maxH[0]=envelope;
         t_max=SIZE(i);
        }
      sumH[0]+=envelope;
      name="H"+(string)i;
      ObjectCreate(0,name,OBJ_TEXT,0,0,0);
      ObjFont
      ObjCoordinates(t[0]-(NUMBER_MA-i*2)*shift,envelope)
      ObjProperty(SIZE(i),158,clrBlue)
     }
//--- TROUGHS
   sumL[0]=0.0;
   maxL[0]=0.0;
   minL[0]=0.0;
   for(int i=0; i<NUMBER_MA; i++)
     {
      CopyBuffer(handle_MA_L[i],0,t[0],1,MA);
      double envelope=MA[0]-sumLo[i]/L;
      if(i==0 || envelope<minL[0])
        {
         minL[0]=envelope;
         t_min=SIZE(i);
        }
      if(envelope>maxL[0])
        {
         maxL[0]=envelope;
         t_max=SIZE(i);
        }
      sumL[0]+=envelope;
      name="L"+(string)i;
      ObjectCreate(0,name,OBJ_TEXT,0,0,0);
      ObjFont
      ObjCoordinates(t[0]+(NUMBER_MA-i*2)*shift,envelope)
      ObjProperty(SIZE(i),158,clrGold)
     }
Remarque pour les programmeurs novices : les opérateurs à la fin des blocs Peaks et Troughs n'ont pas ';' à la fin de la chaîne. Ce n'est pas une erreur ou une faute de frappe. Ce sont des macros (voir la section données où elles sont déclarées) - elles sont très utiles ! Je vous recommande de les utiliser dans vos programmes.

Pour discerner les points de la section transversale de la surface formée par les lignes enveloppes, les points varient en taille : plus la période de moyennage de la ligne principale des indicateurs Enveloppes est grande, plus les points sont gros (Fig. 7). De plus, les sections transversales sont tournées autour d'un axe vertical passant par la barre de courant (zéro) dans différentes directions : les pics sont à 90 degrés vers la droite et les creux sont à 90 degrés vers la gauche.

Maintenant, ils peuvent être vus dans le plan du graphique des prix. Initialement, ils se trouvaient dans le plan de coupe (Fig. 5) et ne pouvaient pas être observés. Nous ne pouvions que nous les imaginer, sans avoir aucune idée de leur forme. Les lignes de section transversale se sont avérées être d'une forme très particulière. Ceci est également fait pour la commodité de l'analyse graphique. Visuellement, les sections transversales ressemblent à deux comètes volantes :

Coupe transversale du pool d'indicateurs Enveloppes

Fig. 7. Coupe transversale du pool d'indicateurs Enveloppes.

Passons au calcul des caractéristiques de la section : le maximum et le minimum, ainsi que le centre de gravité (la moyenne arithmétique). Les valeurs résultantes seront affichées sous forme de points sur la barre actuelle, la taille des points correspondant à la taille de la caractéristique pertinente. De plus, nous les enregistrerons dans l'historique pour une analyse plus approfondie. Nous allons donc ajouter ce qui suit au code existant :

//--- PEAKS

...

//--- midi
   string str=(string)t[0];
   name="Hmidi"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],sumH[0]/NUMBER_MA)
   ObjProperty(10,119,clrBlue)
//--- max
   name="Hmax"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],maxH[0])
   ObjProperty(t_max,158,clrBlue)
//--- min
   name="Hmin"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],minH[0])
   ObjProperty(t_min,158,clrBlue)

...

//--- TROUGHS

...

//--- midi
   name="Lmidi"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],sumL[0]/NUMBER_MA)
   ObjProperty(10,119,clrGold)
//--- max
   name="Lmax"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],maxL[0])
   ObjProperty(t_max,158,clrGold)
//--- min
   name="Lmin"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],minL[0])
   ObjProperty(t_min,158,clrGold)

Voyons maintenant à quoi cela ressemble lorsqu'il est représenté graphiquement :

Caractéristiques de la section transversale

Fig. 8. Caractéristiques de la section transversale : le maximum et le minimum, ainsi que le centre de gravité tracé pour les pics et les creux séparément.

Nous avons juste besoin d'ajouter la dernière touche finale en trouvant et en traçant des nœuds de ZigZag avancés. Nous améliorons le code en ajoutant les éléments suivants :

//--- ZigZag: advanced nodes
   if(Azz.zHL[0].type>0) // peak
     {
      ObjectDelete(0,"MIN");
      ObjectDelete(0,"MINfuture");
      name="MAX";
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjZZ
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,Azz.zHL[1].value);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,Azz.zHL[1].time);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,t[0]);
      double price=minH[0];
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
      if(Azz.zHL[0].value>minH[0])
        {
         price=sumH[0]/NUMBER_MA;
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
        }
      if(Azz.zHL[0].value>sumH[0]/NUMBER_MA)
        {
         price=maxH[0];
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
        }
      //--- into the future
      name="MAXfuture";
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjZZ
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,price);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,t[0]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,maxL[0]);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,t[0]+NUMBER_MA*shift);
      if(price<maxL[0])
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,sumL[0]/NUMBER_MA);
      if(price<sumL[0]/NUMBER_MA)
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,minL[0]);
     }
   if(Azz.zHL[0].type<0) // trough
     {
      ObjectDelete(0,"MAX");
      ObjectDelete(0,"MAXfuture");
      name="MIN";
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjZZ
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,Azz.zHL[1].value);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,Azz.zHL[1].time);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,t[0]);
      double price=maxL[0];
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
      if(Azz.zHL[0].value<maxL[0])
        {
         price=sumL[0]/NUMBER_MA;
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
        }
      if(Azz.zHL[0].value<sumL[0]/NUMBER_MA)
        {
         price=minL[0];
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
        }
      //--- into the future
      name="MINfuture";
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjZZ
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,price);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,t[0]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,minH[0]);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,t[0]+NUMBER_MA*shift);
      if(price>minH[0])
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,sumH[0]/NUMBER_MA);
      if(price>sumH[0]/NUMBER_MA)
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,maxH[0]);
     }

Nous avons donc le nouvel indicateur avancé de ZigZag qui prédit la position des nouveaux nœuds (Fig. 9). Les nœuds eux-mêmes sont situés aux points caractéristiques de la section transversale : le maximum, le minimum et le centre de gravité. Le titre provisoire de l'indicateur est "Deux comètes".

Il est à noter que le temps d'achèvement du nœud suivant, qui est dans le futur, est resté inconnu. Fondamentalement, nous ne pouvons prédire qu'une seule coordonnée de nœud - le prix.

Nœuds de ZigZag prédits

Fig. 9. L'indicateur de ZigZag avancé prédit les nœuds : le courant et le suivant.

 

Analyse des résultats et recommandations pour les développeurs

Les observations d’indicateur ont montré que :

  1. Les écarts des coordonnées des nœuds de ZigZag par rapport aux nœuds prédits se situent dans la zone de tolérance. Le grand nombre de nœuds se trouve dans l'ombre de la section correspondante. Il ne s'agit certainement que d'une évaluation qualitative. Des résultats plus précis suivront dans les prochains articles.
  2. Des coupes transversales des lignes d'enveloppes démontrent le comportement du marché et la dynamique des prix attendue ! Faites attention à la queue de la comète qui est constituée de points avec la plus petite période de moyenne (la plus petite en taille). Il est orienté dans le sens du prix. La queue de la comète se plie de la manière la plus complexe et plus elle est tournée dans la direction opposée, plus grandes sont les chances de voir la tendance changer. Observez simplement le comportement de l'indicateur sur différentes périodes avec différentes amplitudes. C'est extrêmement intéressant !
  3. Les points caractéristiques des sections transversales forment des lignes qui peuvent présenter une forte résistance au mouvement des prix. Par conséquent, ils peuvent être considérés comme des lignes de support et de résistance.
  4. Lorsque les points du centre de gravité de la section transversale le précèdent (comme les pics de la figure 9), cela indique la présence d'une tendance à la hausse.

Nous avons donc obtenu un indicateur très intéressant qui peut être testé dans une stratégie de trading !

 

Conclusion

  • La méthode de prédiction des nœuds indicateurs de ZigZag examinée dans l'article nous a permis de créer le nouvel indicateur - "Deux comètes".
  • Le ZigZag avancé montre les coordonnées possibles de nouveaux nœuds, même s'il ne s'agit que d'une prévision.
  • L'algorithme considéré dans l'article peut être utilisé pour tracer des indicateurs avancés similaires, qui ne sont pas nécessairement des indicateurs ZigZag, par exemple des fractales ou des indicateurs de sémaphore.
  • Les programmeurs novices MQL5 peuvent trouver intéressant de voir comment ils peuvent créer des macros dans leurs programmes pour réduire la quantité de code répété.

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

Fichiers joints |
advancedzigzag.mqh (3.54 KB)
getextremums.mqh (5.24 KB)
two_comets.mq5 (10.16 KB)
MQL5 Cookbook : Développement d'un cadre pour un système de trading basé sur la stratégie du triple écran MQL5 Cookbook : Développement d'un cadre pour un système de trading basé sur la stratégie du triple écran
Dans cet article, nous allons développer un cadre pour un système de trading basé sur la stratégie Triple Screen dans MQL5. L’Expert Advisor ne sera pas développé à partir de zéro. Au lieu de cela, nous allons simplement modifier le programme de l’article précédent « MQL5 Cookbook : Utilisation des indicateurs pour définir les conditions de trading dans l’Expert Advisors" qui répond déjà largement à notre objectif. Ainsi, l’article montrera également comment vous pouvez facilement modifier des modèles de programmes prêts à l’emploi.
MQL5 Cookbook : Utilisation d'indicateurs pour définir les conditions de trading dans les Expert Advisors MQL5 Cookbook : Utilisation d'indicateurs pour définir les conditions de trading dans les Expert Advisors
Dans cet article, nous continuerons à modifier l'Expert Advisor sur lequel nous avons travaillé tout au long des articles précédents de la série MQL5 Cookbook. Cette fois, l'Expert Advisor sera enrichi d'indicateurs dont les valeurs serviront à vérifier les conditions d'ouverture des positions. Pour le pimenter, nous allons créer une liste déroulante dans les paramètres externes pour pouvoir sélectionner un des trois indicateurs de trading.
MQL5 Cookbook : Expert Advisor multi-devises - Approche simple, nette et rapide MQL5 Cookbook : Expert Advisor multi-devises - Approche simple, nette et rapide
Cet article décrira une mise en œuvre d'une approche simple adaptée à un Expert Advisor multi-devises. Cela signifie que vous pourrez configurer l'Expert Advisor pour les tests/trading dans des conditions identiques mais avec des paramètres différents pour chaque symbole. A titre d'exemple, nous allons créer un motif pour deux symboles mais de manière à pouvoir ajouter des symboles supplémentaires, si nécessaire, en apportant de petites modifications au code.
MQL5 Cookbook : L'historique des transactions et la bibliothèque de fonctions pour obtenir les propriétés de position MQL5 Cookbook : L'historique des transactions et la bibliothèque de fonctions pour obtenir les propriétés de position
Il est temps de résumer brièvement les informations fournies dans les articles précédents sur les propriétés de position. Dans cet article, nous allons créer quelques fonctions supplémentaires pour obtenir les propriétés qui ne peuvent être obtenues qu'après avoir accédé à l'historique des transactions. Nous nous familiariserons également avec les structures de données qui nous permettront d'accéder aux propriétés de position et de symbole de manière plus pratique.