English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Calcul des caractéristiques intégrales des émissions d’indicateurs

Calcul des caractéristiques intégrales des émissions d’indicateurs

MetaTrader 5Exemples | 13 janvier 2022, 09:37
138 0
Sergey Pavlov
Sergey Pavlov

Introduction

Les émissions d’indicateurs représentent une direction nouvelle et très prometteuse dans l’étude des séries chronologiques. Il se caractérise par le fait que l’analyse n’est pas axée sur les indicateurs en tant que tels, mais sur leurs émissions dans le futur ou le passé sur la base desquelles nous pouvons réellement faire une prévision de l’environnement du marché:

  • les niveaux de soutien et de résistance à l’avenir ;
  • la direction de la tendance (mouvement des prix) ;
  • la force de mouvement accumulée au cours du passé.

Mon article précédent intitulé "Drawing Indicator's Emissions in MQL5" traitait de l’algorithme de dessin des émissions et précisait ses principales caractéristiques. Permettez-moi de vous rappeler :

L’émission est un ensemble de points situés aux intersections de lignes propres aux indicateurs considérés.

Les points d’émission, à leur tour, présentent certaines particularités :

  • Les points d’émission du même type ont tendance à se regrouper.
  • Les grappes de points denses peuvent attirer ou, au contraire, repousser le prix.

Galerie d’émissions :

Émission de DCMV Émission d’iMA & iEnvelopes
Émission de DCMV Émission d’iMA & iEnvelopes

Fig. 1. Exemples de diagrammes d'émission d'indicateurs. A gauche : émission de l’indicateur DCMV. A droite: émission des indicateurs iMA et iEnvelopes..

Pour illustrer le calcul des caractéristiques intégrales des émissions, nous prendrons les enveloppes de moyennes mobiles (Envelopes) et les moyennes mobiles (Moving Average) elles-mêmes avec les paramètres d’entrée suivants :

//--- external variable for storing averaging period of the iEnvelopes indicator
input int   ma_period=140; // averaging period of the iEnvelopes indicator
//--- array for storing deviations of the iEnvelopes indicator
double      ENV[]={0.01,0.0165,0.0273,0.0452,0.0747,01234,0.204,0.3373,0.5576,0.9217,1.5237};
//--- array for storing iMA indicator periods
int         MA[]={4,7,11,19,31,51,85};

Nous allons donc rechercher des intersections de lignes propres aux indicateurs sélectionnés. Le nombre de lignes et leurs caractéristiques (périodes de moyenne et écarts) sont choisis au hasard. Les émissions peuvent en effet être tracées à l’aide de n’importe quel ensemble de paramètres pour ces indicateurs (tant qu’ils se croisent dans l’espace).

Maintenant que nous avons choisi les indicateurs, procédons à la création d’un Expert Advisor qui va servir de programme de base pour l’analyse des émissions. Nous devrons obtenir les données calculées à partir des indicateurs techniques iMA et iEnvelopes. Je propose d’utiliser une méthode décrite dans le Guide d’utilisation des indicateurs techniques dans Les Expert Advisors.

Pour tracer les lignes dont nous devons trouver les intersections, il suffit de définir deux points pour chacune des lignes. Ainsi, il suffit d’obtenir des valeurs d’indicateur pour deux barres (par exemple, la actuelle et la précédente) uniquement. Le prix sur la barre précédente est statique, tandis que le prix sur la barre actuelle est dynamique et donc de nouveaux points continuent d’être générés à chaque nouveau tick. Voici le code :

//+------------------------------------------------------------------+
//|                                      emission_of_MA_envelope.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 <GetIndicatorBuffers.mqh>
#include <Emission.mqh>
//--- external variable for storing averaging period of the iEnvelopes indicator
input int   ma_period=140;      // averaging period of the iEnvelopes indicator
//--- array for storing deviations of the iEnvelopes indicator
double      ENV[]={0.01,0.0165,0.0273,0.0452,0.0747,01234,0.204,0.3373,0.5576,0.9217,1.5237};
//--- array for storing the iMA indicator periods
int         MA[]={4,7,11,19,31,51,85};
//--- array for storing pointers to the iMA and iEnvelopes indicators
int         handle_MA[];
int         handle_Envelopes[];
//--- market data
datetime    T[],prevTimeBar=0;
double      H[],L[];
#define     HL(a, b) (a+b)/2
//--- class instances
CEmission      EnvMa(0,300);
PointEmission  pEmission;
//--- drawing styles for points of emission
#define     COLOR_UPPER  C'51,255,255'
#define     COLOR_LOWER  C'0,51,255'
#define     COLOR_MA     C'255,51,255'
color       colorPoint[]={COLOR_UPPER,COLOR_LOWER,COLOR_MA};
CodeColor   styleUpper={158,COLOR_UPPER,SMALL};
CodeColor   styleLower={158,COLOR_LOWER,SMALL};
CodeColor   styleMA={158,COLOR_MA,SMALL};
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   ArraySetAsSeries(T,true);
   ArraySetAsSeries(H,true);
   ArraySetAsSeries(L,true);
//---
   int size=ArraySize(MA);
   ArrayResize(handle_MA,size);
//--- create a pointer to the object - the iMA indicator
   for(int i=0; i<size; i++)
     {
      handle_MA[i]=iMA(NULL,0,MA[i],0,MODE_SMA,PRICE_MEDIAN);
      //--- if an error occurs when creating the object, print the message
      if(handle_MA[i]<0)
        {
         Print("The iMA object[",MA[i],"] has not been created: Error = ",GetLastError());
         //--- forced program termination
         return(-1);
        }
     }
//---
   size=ArraySize(ENV);
   ArrayResize(handle_Envelopes,size);
//--- create a pointer to the object - the iEnvelopes indicator
   for(int i=0; i<size; i++)
     {
      handle_Envelopes[i]=iEnvelopes(NULL,0,ma_period,0,MODE_SMA,PRICE_MEDIAN,ENV[i]);
      //--- if an error occurs when creating the object, print the message
      if(handle_Envelopes[i]<0)
        {
         Print("The iEnvelopes object[",ENV[i],"] has not been created: Error = ",GetLastError());
         //--- forced program termination
         return(-1);
        }
     }
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- market data
   CopyTime(NULL,0,0,2,T);
   CopyHigh(NULL,0,0,2,H);
   CopyLow(NULL,0,0,2,L);
//--- fill the declared arrays with current values from all indicator buffers
   string name;
   uint GTC=GetTickCount();
//---- indicator buffers
   double   ibMA[],ibMA1[];      // arrays for the iMA indicator
   double   ibEnvelopesUpper[];  // array for the iEnvelopes indicator (UPPER_LINE)
   double   ibEnvelopesLower[];  // array for the iEnvelopes indicator (LOWER_LINE)
   for(int i=ArraySize(handle_MA)-1; i>=0; i--)
     {
      if(!CopyBufferAsSeries(handle_MA[i],0,0,2,true,ibMA))
         return;
      //---
      for(int j=ArraySize(handle_Envelopes)-1; j>=0; j--)
        {
         if(!GetEnvelopesBuffers(handle_Envelopes[j],0,2,ibEnvelopesUpper,ibEnvelopesLower,true))
            return;
         //--- find the intersection point of the iEnvelopes(UPPER_LINE) and iMA indicators
         pEmission=EnvMa.CalcPoint(ibEnvelopesUpper[1],ibEnvelopesUpper[0],ibMA[1],ibMA[0],T[0]);
         if(pEmission.real) // if the intersection point is found, draw it in the chart
           {
            name="iEnvelopes(UPPER_LINE)"+(string)j+"=iMA"+(string)i+(string)GTC;
            EnvMa.CreatePoint(name,pEmission,styleUpper);
           }
         //--- find the intersection point of the iEnvelopes(LOWER_LINE) and iMA indicators
         pEmission=EnvMa.CalcPoint(ibEnvelopesLower[1],ibEnvelopesLower[0],ibMA[1],ibMA[0],T[0]);
         if(pEmission.real) // if the intersection point is found, draw it in the chart
           {
            name="iEnvelopes(LOWER_LINE)"+(string)j+"=iMA"+(string)i+(string)GTC;
            EnvMa.CreatePoint(name,pEmission,styleLower);
           }
        }
      //---
      for(int j=ArraySize(handle_MA)-1; j>=0; j--)
        {
         if(i!=j)
           {
            if(!CopyBufferAsSeries(handle_MA[j],0,0,2,true,ibMA1))
               return;
            //--- find the intersection point of the iMA and iMA indicators
            pEmission=EnvMa.CalcPoint(ibMA1[1],ibMA1[0],ibMA[1],ibMA[0],T[0]);
            if(pEmission.real) // if the intersection point is found, draw it in the chart
              {
               name="iMA"+(string)j+"=iMA"+(string)i+(string)GTC;
               EnvMa.CreatePoint(name,pEmission,styleMA);
              }
           }
        }
     }
//--- deletion of the graphical objects of emission not to stuff the chart
   if(T[0]>prevTimeBar) // delete once per bar
     {
      int  total=ObjectsTotal(0,0,-1);
      prevTimeBar=T[0];
      for(int obj=total-1;obj>=0;obj--)
        {
         string obj_name=ObjectName(0,obj,0,OBJ_TEXT);
         datetime obj_time=(datetime)ObjectGetInteger(0,obj_name,OBJPROP_TIME);
         if(obj_time<T[0])
            ObjectDelete(0,obj_name);
        }
      Comment("Emission © DC2008       Objects = ",total);
     }
//---
  }

Je ne vais pas m’attarder sur tous les détails de cet Expert Advisor. La principale chose à noter ici est que pour tracer l’émission, nous utilisons une instance de classe CEmission responsable du calcul et de l’affichage des points d’intersection de deux lignes quelconques.

//+------------------------------------------------------------------+
//|                                                     Emission.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"
#define  BIG   7    // point size
#define  SMALL 3    // point size
//+------------------------------------------------------------------+
//| pMABB structure                                                  |
//+------------------------------------------------------------------+
struct PointEmission
  {
   double            x;       // X-coordinate of the time point
   double            y;       // Y-coordinate of the price point
   datetime          t;       // t-coordinate of the point's time
   bool              real;    // whether the point exists
  };
//+------------------------------------------------------------------+
//| CodeColor structure                                              |
//+------------------------------------------------------------------+
struct CodeColor
  {
   long              Code;    // point symbol code 
   color             Color;   // point color
   int               Width;   // point size
  };
//+------------------------------------------------------------------+
//| Base class for emissions                                         |
//+------------------------------------------------------------------+
class CEmission
  {
private:
   int               sec;
   int               lim_Left;   // limiting range of visibility in bars
   int               lim_Right;  // limiting range of visibility in bars

public:
   PointEmission     CalcPoint(double   y1,  // Y-coordinate of straight line 1 on bar [1]
                               double   y0,  // Y-coordinate of straight line 1 on bar [0]
                               double   yy1, // Y-coordinate of straight line 2 on bar [1] 
                               double   yy0, // Y-coordinate of straight line 2 on bar [0]
                               datetime t0   // t-coordinate of the current bar Time[0]
                               );
   bool              CreatePoint(string name,            // point name
                                 PointEmission &point,   // coordinates of the point
                                 CodeColor &style);      // point drawing style
                                 CEmission(int limitLeft,int limitRight);
                    ~CEmission();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CEmission::CEmission(int limitLeft,int limitRight)
  {
   sec=PeriodSeconds();
   lim_Left=limitLeft;
   lim_Right=limitRight;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CEmission::~CEmission()
  {
  }
//+------------------------------------------------------------------+
//| The CalcPoint method of the CEmission class                      |
//+------------------------------------------------------------------+
PointEmission CEmission::CalcPoint(double   y1, // Y-coordinate of straight line 1 on bar [1]
                                   double   y0, // Y-coordinate of straight line 1 on bar [0]
                                   double   yy1,// Y-coordinate of straight line 2 on bar [1]
                                   double   yy0,// Y-coordinate of straight line 2 on bar [0]
                                   datetime t0  // t-coordinate of the current bar Time[0]
                                   )
  {
   PointEmission point={NULL,NULL,NULL,false};
   double y0y1=y0-y1;
   double y1yy1=y1-yy1;
   double yy0yy1=yy0-yy1;
   double del0=yy0yy1-y0y1;
   if(MathAbs(del0)>0)
     {
      point.x=y1yy1/del0;
      if(point.x<lim_Left || point.x>lim_Right) return(point);
      point.y=y1+y0y1*y1yy1/del0;
      if(point.y<0) return(point);
      point.t=t0+(int)(point.x*sec);
      point.real=true;
      return(point);
     }
   return(point);
  }
//+------------------------------------------------------------------+
//| The CreatePoint method of the CEmission class                    |
//+------------------------------------------------------------------+
bool CEmission::CreatePoint(string name,            // point name
                            PointEmission &point,  // coordinates of the point
                            CodeColor &style)      // point drawing style
  {
   if(ObjectCreate(0,name,OBJ_TEXT,0,0,0))
     {
      ObjectSetString(0,name,OBJPROP_FONT,"Wingdings");
      ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_CENTER);
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,style.Width);
      ObjectSetString(0,name,OBJPROP_TEXT,CharToString((uchar)style.Code));
      ObjectSetDouble(0,name,OBJPROP_PRICE,point.y);
      ObjectSetInteger(0,name,OBJPROP_TIME,point.t);
      ObjectSetInteger(0,name,OBJPROP_COLOR,style.Color);
      return(true);
     }
   return(false);
  }

Il convient de noter que les points d’émission sont représentés au moyen d’objets graphiques tels que Text. Tout d’abord, cela vient du fait que les ancres d’objet doivent être alignées sur le centre du symbole. Deuxièmement, vous pouvez faire varier la taille de l’objet sur une large plage. Ces propriétés ponctuelles offrent un grand potentiel pour obtenir des émissions complexes.

Fig. 2. Émission initiale des indicateurs iMA et iEnvelopes

Fig. 2. Émission initiale des indicateurs iMA et iEnvelopes

 

Caractéristiques intégrales des émissions

Ainsi, après avoir placé l’Expert Advisor proposé sur le graphique, nous avons obtenu beaucoup de points de différentes couleurs (voir Fig. 2) :

  • Aqua - les intersections d’iMA et d’iEnvelopes, UPPER_LINE tampon.
  • Bleu - les intersections d’iMA et d’iEnvelopes, LOWER_LINE tampon.
  • Magenta - les intersections de iMA et iMA.

Ce chaos ne peut pas être utilisé dans le trading automatisé. Nous avons besoin de signaux, de niveaux et d’autres caractéristiques quantitatives du marché, alors qu’ici nous n’obtenons que des images visuelles pour la méditation et la chiromancie et aucun chiffre.

Les caractéristiques intégrales des émissions servent à généraliser les données obtenues à la suite des émissions d’indicateurs. 

La nécessité de caractéristiques intégrales des émissions est également motivée par le fait qu’elles offrent des opportunités d’études de marché utilisant de nouveaux types d’indicateurs: canaux intégraux, lignes, niveaux, signaux, etc. Pour déterminer les valeurs d’émission les plus typiques, nous allons commencer petit et calculer le prix moyen pour chaque type de point afin de tracer davantage des lignes horizontales à travers eux comme indiqué ci-dessous :

Fig. 3. Lignes horizontales du prix moyen pour chaque type de point

Fig. 3. Lignes horizontales du prix moyen pour chaque type de point

À cette fin, nous ajouterons quelques blocs de code supplémentaires au code existant. Vers la section des données :

//--- arrays for calculation and display of integral characteristics of emissions
#define     NUMBER_TYPES_POINT   3
double      sum[NUMBER_TYPES_POINT],sumprev[NUMBER_TYPES_POINT];
datetime    sum_time[NUMBER_TYPES_POINT];
int         n[NUMBER_TYPES_POINT],W[NUMBER_TYPES_POINT];
color       colorLine[]={clrAqua,clrBlue,clrMagenta};

Vers le module OnTick() :

//--- calculation of integral characteristics of emissions
   ArrayInitialize(n,0);
   ArrayInitialize(sum,0.0);
   ArrayInitialize(sum_time,0.0);
   for(int obj=total-1;obj>=0;obj--)
     {
      string   obj_name=ObjectName(0,obj,0,OBJ_TEXT);
      datetime obj_time=(datetime)ObjectGetInteger(0,obj_name,OBJPROP_TIME);
      if(obj_time>T[0])
        {
         color    obj_color=(color)ObjectGetInteger(0,obj_name,OBJPROP_COLOR);
         double   obj_price=ObjectGetDouble(0,obj_name,OBJPROP_PRICE);
         for(int i=ArraySize(n)-1; i>=0; i--)
            if(obj_color==colorPoint[i])
              {
               n[i]++;
               sum[i]+=obj_price;
               sum_time[i]+=obj_time;
              }
        }
     }
//--- displaying integral characteristics of emissions
   for(int i=ArraySize(n)-1; i>=0; i--)
     {
      if(n[i]>0)
        {
         name="H.line."+(string)i;
         ObjectCreate(0,name,OBJ_HLINE,0,0,0,0);
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DASHDOT);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
         ObjectSetDouble(0,name,OBJPROP_PRICE,sum[i]/n[i]);
        }
     }

Nous passons à autre chose. Calculons maintenant la valeur de temps moyenne pour chaque ensemble de points et marquons-la sur la ligne correspondante du prix moyen (voir Fig. 4). Ainsi, nous avons obtenu les premières caractéristiques quantitatives d’émissions qui ne sont jamais statiques, toujours en mouvement dans l’espace.

Le graphique ne montre que leurs positions momentanées. Nous devons en quelque sorte les garder fixes dans l’histoire pour pouvoir les étudier par la suite. Jusqu’à présent, on ne sait toujours pas comment cela peut être fait et nous devons l’examiner attentivement... En attendant, nous allons encore améliorer et afficher le nombre de points impliqués dans le calcul à côté des marqueurs dans le graphique. Ce sont des sortes de poids des caractéristiques obtenues qui seront également utiles pour une analyse plus approfondie.

Fig. 4. Marqueurs aux points d’intersection du prix moyen et du temps moyen

Fig. 4. Marqueurs aux points d’intersection du prix moyen et du temps moyen

Cependant, pour faciliter l’analyse, nous utiliserons leurs ratios en pourcentage. Étant donné que les principaux points d’émission sont ceux résultant des intersections des indicateurs iMA et iEnvelopes, nous considérerons que leur somme est de 100%. Voyons ce que nous avons maintenant:

Fig. 5. Ratio en pourcentage pour chaque type de points d’émission

Fig. 5. Ratio en pourcentage pour chaque type de points d’émission

Si nous additionnons les trois valeurs, elles donneront plus de 100% au total. La valeur de 34,4 affichée en magenta est la propriété des points d’intersection de l’iMA et l’iMA à un certain moment, c’est-à-dire que l’indicateur s’est croisé, mais avec des données d’entrée différentes. Dans ce cas, il s’agit d’une valeur de référence et nous pourrions réfléchir plus tard à la façon dont elle peut être utilisée dans l’analyse de marché.

Cependant, un autre problème se pose lorsque nous obtenons des rapports en pourcentage du nombre de points: comment pouvons-nous également fixer des valeurs en pourcentage des caractéristiques d’émission dans l’histoire, d’autant plus qu’elles varient également ?!

 

Analyse graphique

Bien que nous ayons maintenant les caractéristiques intégrales des émissions, nous ne sommes pas encore assez proches de l’analyse et du développement d’une stratégie d’échange basée sur les données obtenues. Cependant, un lecteur attentif doit avoir déjà repéré une solution à ce problème (voir Fig. 1). La solution est la suivante : Je propose de dessiner des courbes intégrales en utilisant différentes épaisseurs qui seraient proportionnelles au rapport en pourcentage des principaux points d’émission.

La partie actuelle de la courbe sera tracée le long de la ligne de prix moyenne entre la barre actuelle et la barre précédente, en gardant à l’esprit que ces coordonnées sont en fait tirées du futur. C’est une sorte de canal intégral d’émissions d’indicateurs. Je sais que cela semble très déroutant en effet... Et vous devez vous demander si vous devriez lire la suite. Mais j’espère que cela deviendra de plus en plus intéressant au fur et à mesure que nous avancerons.

Fig. 6. Canal intégral des émissions d’indicateurs

Fig. 6. Canal intégral des émissions d’indicateurs

Nous semblons donc avoir trouvé une certaine utilisation pour l’émission "iMA & iMA" (affichée en magenta dans le graphique). Et nous avons obtenu un nouvel indicateur - la moyenne mobile intégrée.

Nous revenons maintenant au code de l’Expert Advisor pour voir quels changements ont eu lieu dans le module OnTick() :

//--- displaying integral characteristics of emissions
   ArrayInitialize(W,10);
   W[ArrayMaximum(n)]=20;
   W[ArrayMinimum(n)]=3;
   for(int i=ArraySize(n)-1; i>=0; i--)
     {
      if(n[i]>0)
        {
         //--- horizontal lines of mean prices
         name="H.line."+(string)i;
         ObjectCreate(0,name,OBJ_HLINE,0,0,0,0);
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DASHDOT);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
         ObjectSetDouble(0,name,OBJPROP_PRICE,sum[i]/n[i]);
         //--- markers
         name="P."+(string)i;
         ObjectCreate(0,name,OBJ_TEXT,0,0,0);
         ObjectSetString(0,name,OBJPROP_FONT,"Wingdings");
         ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_CENTER);
         ObjectSetInteger(0,name,OBJPROP_FONTSIZE,17);
         ObjectSetString(0,name,OBJPROP_TEXT,CharToString(163));
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         ObjectSetDouble(0,name,OBJPROP_PRICE,sum[i]/n[i]);
         ObjectSetInteger(0,name,OBJPROP_TIME,sum_time[i]/n[i]);
         //--- integral curves
         name="T"+(string)i+".line"+(string)T[1];
         ObjectCreate(0,name,OBJ_TREND,0,0,0);
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,W[i]);
         if(sumprev[i]>0)
           {
            ObjectSetDouble(0,name,OBJPROP_PRICE,0,sumprev[i]);
            ObjectSetInteger(0,name,OBJPROP_TIME,0,T[1]);
            ObjectSetDouble(0,name,OBJPROP_PRICE,1,(sum[i]/n[i]));
            ObjectSetInteger(0,name,OBJPROP_TIME,1,T[0]);
           }
         //--- numerical values of integral characteristics
         name="Text"+(string)i+".control";
         ObjectCreate(0,name,OBJ_TEXT,0,0,0);
         ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_LEFT_LOWER);
         ObjectSetInteger(0,name,OBJPROP_FONTSIZE,30);
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         string str=DoubleToString((double)n[i]/(double)(n[0]+n[1])*100,1);
         ObjectSetString(0,name,OBJPROP_TEXT,str);
         ObjectSetDouble(0,name,OBJPROP_PRICE,0,(sum[i]/n[i]));
         ObjectSetInteger(0,name,OBJPROP_TIME,0,sum_time[i]/n[i]);
        }
     }

Poursuivons notre analyse graphique. Mais il manque quelque chose... Il semble que nous ayons manqué une autre caractéristique d’émission importante. Les courbes intégrales ont été tracées uniquement en fonction des prix moyens. Pourtant, nous devons tenir compte de la coordonnée du temps moyen. Jetez un coup d’œil à la figure ci-dessous et portez une attention particulière aux limites de canaux :

  • La ligne aqua est la limite supérieure du canal.
  • La ligne bleue est la limite inférieure du canal.

Nous devons identifier le marqueur qui était plus proche dans le temps de la barre zéro.

Limite supérieure principale du canal
Limite inférieure principale du canal

Fig. 7. Caractéristiques intégrales menant dans le temps. Gauche: limite supérieure principale du canal. Droite: limite inférieure principale du canal.

Ce problème peut être résolu comme suit: nous ajoutons la ligne de prix (PRICE_MEDIAN) au tableau des prix et faisons en sorte que la ligne change de couleur en fonction de la couleur du marqueur (aqua ou bleu) qui est plus proche de la dernière barre (voir Fig. 7). En outre, nous insérons le bloc de code suivant dans le code existant :

//---
   if(n[ArrayMinimum(n)]>0)
     {
      datetime d[2];
      for(int j=0;j<2;j++)
        {
         d[j]=sum_time[j]/n[j];
        }
      int i=ArrayMinimum(d);

      name="Price.line"+(string)T[1];
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,8);
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,HL(H[1],L[1]));
      ObjectSetInteger(0,name,OBJPROP_TIME,0,T[1]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,HL(H[0],L[0]));
      ObjectSetInteger(0,name,OBJPROP_TIME,1,T[0]);
      ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine1[i]);
     }
//---

Maintenant, préparez-vous pour la prochaine étape. Que se passe-t-il si nous essayons de tracer les émissions en fonction des caractéristiques intégrales des émissions d’origine, quelque chose comme des émissions de second ordre ? Après tout, ces lignes se croisent également et devraient, par conséquent, avoir des points d’émission. Voyons ce qu’il peut en découler. Améliorez le bloc de code précédent en ajoutant les lignes de code suivantes :

      //--- emissions of integral characteristics of the original emissions
      pEmission=EnvMa.CalcPoint(sumprev[0],sum[0]/n[0],sumprev[2],sum[2]/n[2],T[0]);
      if(pEmission.real) // if the intersection point is found, draw it in the chart
        {
         name="test/up"+(string)GTC;
         EnvMa.CreatePoint(name,pEmission,styleUpper2);
        }
      pEmission=EnvMa.CalcPoint(sumprev[1],sum[1]/n[1],sumprev[2],sum[2]/n[2],T[0]);
      if(pEmission.real) // if the intersection point is found, draw it in the chart
        {
         name="test/dn"+(string)GTC;
         EnvMa.CreatePoint(name,pEmission,styleLower2);
        }

Et insérez les lignes suivantes dans la section de données :

#define     COLOR_2_UPPER  C'102,255,255'
#define     COLOR_2_LOWER  C'51,102,255'
CodeColor   styleUpper2={178,COLOR_2_UPPER,BIG};
CodeColor   styleLower2={178,COLOR_2_LOWER,BIG};

Vous pouvez vérifier les résultats dans la figure ci-dessous. Nous pouvons voir de nouveaux points qui ne suggèrent rien jusqu’à présent.

Fig. 8. Émissions des lignes intégrales

Fig. 8. Émissions des lignes intégrales

Les caractéristiques intégrales peuvent évidemment également être calculées pour de nouveaux points (voir Fig. 9) avec leurs émissions tracées dans le graphique et ainsi de suite jusqu’à ce que cela devienne irréalisable!

Émission Émission
Émission Émission

Fig. 9. Caractéristiques intégrales des émissions

Nous avons donc tracé tout ce dont nous avions besoin et obtenu les caractéristiques intégrales des émissions. Nous pouvons maintenant procéder à leur analyse et à l’élaboration d’une stratégie de trading. Mais cela semble encore impossible ! Qu’est-ce qui nous bloque maintenant ?

 

Série chronologique des émissions

L’analyse graphique nous permet d’étudier les caractéristiques intégrales des émissions, mais elle est trop gourmande en ressources. Si nous essayons d’exécuter le code proposé dans le mode visuel du testeur de stratégie, la vitesse de test tombera bientôt à zéro ! Cela est dû au grand nombre d’objets graphiques dans le graphique.

On voudrait donc naturellement se débarrasser de toute cette abondance de points et ne laisser que les courbes intégrales. Pour résoudre ce problème, nous utiliserons des tableaux spéciaux (tampons).

Les séries chronologiques d’émissions sont des tableaux spécialement disposés où des informations sur les émissions sont accumulées.

Ils diffèrent des séries chronologiques standard en ce que les données qu’ils contiennent ne sont pas séquencées par le temps, même si le temps est le champ clé.

Série chronologique des émissions

Fig. 10. Série chronologique des caractéristiques des émissions

Ces tableaux sont disposés de manière à ce que les nouveaux éléments soient stockés dans des cellules vides ou dans des cellules remplies d’anciennes valeurs. À cette fin, nous utiliserons la classe CTimeEmission. Voici comment il est implémenté dans le code :

//+------------------------------------------------------------------+
//|                                                 TimeEmission.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"
//---
#include <Emission.mqh>
#define ARRMAX       64
#define ARRDELTA     8
//+------------------------------------------------------------------+
//| pIntegral structure                                              |
//+------------------------------------------------------------------+
struct pIntegral
  {
   double            y;       // Y-coordinate of the price point (mean price of the points with the same time)
   datetime          t;       // t-coordinate of the point's time
   int               n;       // n-number of points with the same time
  };
//+------------------------------------------------------------------+
//| Base class for time series of emissions                          |
//+------------------------------------------------------------------+
class CTimeEmission
  {
private:
   pIntegral         time_series_Emission[]; // time series of emission
   int               size_ts; // number of elements in time series 
   datetime           t[1];
public:
   //--- method of writing new elements to time series of emission
   void              Write(PointEmission &point);
   //--- method of reading integral characteristics of emissions
   pIntegral         Read();
                     CTimeEmission();
                    ~CTimeEmission();
  };

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CTimeEmission::CTimeEmission()
  {
   ArrayResize(time_series_Emission,ARRMAX,ARRMAX);
   size_ts=ArraySize(time_series_Emission);
   for(int i=size_ts-1; i>=0; i--)
      time_series_Emission[i].t=0;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CTimeEmission::~CTimeEmission()
  {
  }
//+------------------------------------------------------------------+
//| The Write method of the CTimeEmission class                      |
//+------------------------------------------------------------------+
void CTimeEmission::Write(PointEmission &point)
  {
   CopyTime(NULL,0,0,1,t);
   size_ts=ArraySize(time_series_Emission);
   for(int k=0;k<size_ts;k++)
     {
      if(time_series_Emission[k].t<t[0]) // find the first empty cell
        {
         if(k>size_ts-ARRDELTA)
           {   // increase the array size, if necessary
            int narr=ArrayResize(time_series_Emission,size_ts+ARRMAX,ARRMAX);
            for(int l=size_ts-1;l<narr;l++)
               time_series_Emission[l].t=0;
           }
         time_series_Emission[k].y=point.y;
         time_series_Emission[k].t=point.t;
         time_series_Emission[k].n=1;
         return;
        }
      if(time_series_Emission[k].t==point.t) // find the first similar cell
        {
         time_series_Emission[k].y=(time_series_Emission[k].y*time_series_Emission[k].n+point.y)/(time_series_Emission[k].n+1);
         time_series_Emission[k].n++;
         return;
        }
     }
  }
//+------------------------------------------------------------------+
//| The Read method of the CTimeEmission class                       |
//+------------------------------------------------------------------+
pIntegral CTimeEmission::Read()
  {
   CopyTime(NULL,0,0,1,t);
   pIntegral property_Emission={0.0,0,0};
   size_ts=ArraySize(time_series_Emission);
   for(int k=0;k<size_ts;k++)
     {
      if(time_series_Emission[k].t>=t[0])
        {
         property_Emission.y+=time_series_Emission[k].y*time_series_Emission[k].n;
         property_Emission.t+=(time_series_Emission[k].t-t[0])*time_series_Emission[k].n;
         property_Emission.n+=time_series_Emission[k].n;
        }
     }
   if(property_Emission.n>0)
     {
      property_Emission.y=property_Emission.y/property_Emission.n;
      property_Emission.t=property_Emission.t/property_Emission.n+t[0];
     }
   return(property_Emission);
  }

Ici, nous pouvons voir la mise en œuvre de deux méthodes de classe: écrire des points d’émission dans des séries chronologiques et lire des valeurs de caractéristiques intégrales des émissions.

 

Calcul parcimonieux des caractéristiques intégrales

Maintenant que nous avons la série chronologique des émissions, nous pouvons commencer à créer un algorithme parcimonieux pour le calcul des caractéristiques intégrales afin de développer davantage une stratégie de trading. Mettons à jour l’Expert Advisor d’origine :

//+------------------------------------------------------------------+
//|                                   emission_of_MA_envelope_ts.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 <GetIndicatorBuffers.mqh>
#include <Emission.mqh>
#include <TimeEmission.mqh>
//--- number of point types
#define     NUMBER_TYPES_POINT   3
//--- array for storing the iMA indicator periods
int      MA[]={4,7,11,19,31,51,85};
//--- external variable for storing averaging period of the iEnvelopes indicator
input int ma_period=140; // averaging period of the iEnvelopes indicator
//--- array for storing deviations of the iEnvelopes indicator
double   ENV[]={0.01,0.0165,0.0273,0.0452,0.0747,01234,0.204,0.3373,0.5576,0.9217,1.5237};
//--- array for storing pointers to the iMA indicator
int      handle_MA[];
//--- array for storing pointers to the iEnvelopes indicator
int      handle_Envelopes[];
//--- market data
datetime    T[],prevTimeBar=0;
double      H[],L[];
#define     HL(a, b) (a+b)/2
//--- class instances
CEmission      EnvMa(0,200);
PointEmission  pEmission;
CTimeEmission  tsMA[NUMBER_TYPES_POINT];
pIntegral      integral[NUMBER_TYPES_POINT];
//--- drawing styles for points of emission
#define     DEL            500
//--- arrays for calculation and display of integral characteristics of emissions
double      sumprev[NUMBER_TYPES_POINT];
int         n[NUMBER_TYPES_POINT],W[NUMBER_TYPES_POINT];
color       colorLine[]={clrAqua,clrBlue,clrMagenta};
int         fontPoint[]={30,30,30};
int         fontMarker[]={16,16,16};
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   ArraySetAsSeries(T,true);
   ArraySetAsSeries(H,true);
   ArraySetAsSeries(L,true);
   ArrayInitialize(sumprev,0.0);
//---
   int size=ArraySize(MA);
   ArrayResize(handle_MA,size);
//--- create a pointer to the object - the iMA indicator
   for(int i=0; i<size; i++)
     {
      handle_MA[i]=iMA(NULL,0,MA[i],0,MODE_SMA,PRICE_MEDIAN);
      //--- if an error occurs when creating the object, print the message
      if(handle_MA[i]<0)
        {
         Print("The iMA object[",MA[i],"] has not been created: Error = ",GetLastError());
         //--- forced program termination
         return(-1);
        }
     }
//+------------------------------------------------------------------+
   size=ArraySize(ENV);
   ArrayResize(handle_Envelopes,size);
//--- create a pointer to the object - the iEnvelopes indicator
   for(int i=0; i<size; i++)
     {
      handle_Envelopes[i]=iEnvelopes(NULL,0,ma_period,0,MODE_SMA,PRICE_MEDIAN,ENV[i]);
      //--- if an error occurs when creating the object, print the message
      if(handle_Envelopes[i]<0)
        {
         Print("The iEnvelopes object[",ENV[i],"] has not been created: Error = ",GetLastError());
         //--- forced program termination
         return(-1);
        }
     }
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- market data
   CopyTime(NULL,0,0,2,T);
   CopyHigh(NULL,0,0,2,H);
   CopyLow(NULL,0,0,2,L);
//--- fill the declared arrays with current values from all indicator buffers
   string name;
   uint GTC=GetTickCount();
//---- indicator buffers
   double   ibMA[],ibMA1[];      // arrays for the iMA indicator
   double   ibEnvelopesUpper[];  // array for the iEnvelopes indicator (UPPER_LINE)
   double   ibEnvelopesLower[];  // array for the iEnvelopes indicator (LOWER_LINE)
   for(int i=ArraySize(handle_MA)-1; i>=0; i--)
     {
      if(!CopyBufferAsSeries(handle_MA[i],0,0,2,true,ibMA))
         return;
      //---
      for(int j=ArraySize(handle_Envelopes)-1; j>=0; j--)
        {
         if(!GetEnvelopesBuffers(handle_Envelopes[j],0,2,ibEnvelopesUpper,ibEnvelopesLower,true))
            return;
         //--- find the intersection point of the iEnvelopes(UPPER_LINE) and iMA indicators
         pEmission=EnvMa.CalcPoint(ibEnvelopesUpper[1],ibEnvelopesUpper[0],ibMA[1],ibMA[0],T[0]);
         if(pEmission.real) // if the intersection point is found, add it to the time series of emission
            tsMA[0].Write(pEmission);
         //--- find the intersection point of the iEnvelopes(LOWER_LINE) and iMA indicators
         pEmission=EnvMa.CalcPoint(ibEnvelopesLower[1],ibEnvelopesLower[0],ibMA[1],ibMA[0],T[0]);
         if(pEmission.real) // if the intersection point is found, add it to the time series of emission
            tsMA[1].Write(pEmission);
        }
      //---
      for(int j=ArraySize(handle_MA)-1; j>=0; j--)
        {
         if(i!=j)
           {
            if(!CopyBufferAsSeries(handle_MA[j],0,0,2,true,ibMA1))
               return;
            //--- find the intersection point of the iMA and iMA indicators
            pEmission=EnvMa.CalcPoint(ibMA1[1],ibMA1[0],ibMA[1],ibMA[0],T[0]);
            if(pEmission.real) // if the intersection point is found, add it to the time series of emission
               tsMA[2].Write(pEmission);
           }
        }
     }
//--- deletion of the graphical objects of emission not to stuff the chart
   if(T[0]>prevTimeBar)
     {
      prevTimeBar=T[0];
      //---
      for(int i=ArraySize(n)-1; i>=0; i--)
         sumprev[i]=integral[i].y;
      //---
      for(int obj=ObjectsTotal(0,0,-1)-1;obj>=0;obj--)
        {
         string obj_name=ObjectName(0,obj,0,OBJ_TREND);
         datetime obj_time=(datetime)ObjectGetInteger(0,obj_name,OBJPROP_TIME);
         if(obj_time<T[0]-DEL*PeriodSeconds())
            ObjectDelete(0,obj_name);
        }
      Comment("Emission © DC2008   Graphical objects = ",ObjectsTotal(0,0,-1));
     }
//--- calculation of integral characteristics of emission
   for(int i=ArraySize(n)-1; i>=0; i--)
      integral[i]=tsMA[i].Read();
//--- displaying integral characteristics of emission
   ArrayInitialize(W,5);
   if(integral[0].n>integral[1].n)
     {
      W[0]=20;
      W[1]=10;
     }
   else
     {
      W[0]=10;
      W[1]=20;
     }
   for(int i=ArraySize(n)-1; i>=0; i--)
     {
      //--- horizontal lines of mean prices
      name="H.line."+(string)i;
      ObjectCreate(0,name,OBJ_HLINE,0,0,0,0);
      ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
      ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DASHDOT);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
      ObjectSetDouble(0,name,OBJPROP_PRICE,integral[i].y);
      //--- markers
      name="P."+(string)i;
      ObjectCreate(0,name,OBJ_TEXT,0,0,0);
      ObjectSetString(0,name,OBJPROP_FONT,"Wingdings");
      ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_CENTER);
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,fontMarker[i]);
      ObjectSetString(0,name,OBJPROP_TEXT,CharToString(163));
      ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,integral[i].y);
      ObjectSetInteger(0,name,OBJPROP_TIME,integral[i].t);
      //--- integral curves
      name="T"+(string)i+".line"+(string)T[1];
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,W[i]);
      if(sumprev[i]>0)
        {
         ObjectSetDouble(0,name,OBJPROP_PRICE,0,sumprev[i]);
         ObjectSetInteger(0,name,OBJPROP_TIME,0,T[1]);
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,integral[i].y);
         ObjectSetInteger(0,name,OBJPROP_TIME,1,T[0]);
        }
      //--- numerical values of integral characteristics
      if(integral[0].n+integral[1].n>0)
        {
         name="Text"+(string)i+".control";
         ObjectCreate(0,name,OBJ_TEXT,0,0,0);
         ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_LEFT_LOWER);
         ObjectSetInteger(0,name,OBJPROP_FONTSIZE,fontPoint[i]);
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         string str=DoubleToString((double)integral[i].n/(double)(integral[0].n+integral[1].n)*100,1);
         ObjectSetString(0,name,OBJPROP_TEXT,str);
         ObjectSetDouble(0,name,OBJPROP_PRICE,0,integral[i].y);
         ObjectSetInteger(0,name,OBJPROP_TIME,0,integral[i].t);
        }
     }
  }

Le code est devenu plus court, tandis que la vitesse de calcule a augmenté. Vous pouvez maintenant tester et optimiser vos robots de trading sans visualisation ! 

 

Utilisation des caractéristiques intégrales dans le trading

Les caractéristiques intégrales peuvent être utilisées comme générateur de signaux pour :

  • le percée du canal,
  • l'intersection entre eux ou le prix,
  • le changement de direction.
Par exemple, la figure ci-dessous montre comment les caractéristiques intégrales des émissions peuvent hypothétiquement être utilisées aux intersections avec le prix. Les signaux de vente sont générés lorsque le prix est franchi vers le haut par la courbe bleue et les signaux d’achat sont générés au croisement vers le bas du prix avec la courbe aqua.

Fig.  11. Signaux de trading aux intersections des caractéristiques intégrales des émissions

Fig.  11. Échange de signaux aux intersections des caractéristiques intégrales des émissions

 

Conclusion

  1. Le calcul des caractéristiques intégrales des émissions d’indicateurs fournit de nouveaux outils et méthodes d’analyse du marché (séries chronologiques).
  2. En utilisant des séries chronologiques, nous avons réussi à augmenter la vitesse de calcul des caractéristiques intégrales.
  3. Et cela nous a ouvert la possibilité de développer des stratégies d’échange automatisées qui utilisent les émissions.

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

Informations générales sur les signaux de trading pour MetaTrader 4 et MetaTrader 5 Informations générales sur les signaux de trading pour MetaTrader 4 et MetaTrader 5
Les signaux de trading pour MetaTrader 4 et MetaTrader 5 est un service permettant aux traders de copier les opérations de trading d’un fournisseur de signaux. Notre objectif était de développer le nouveau service massivement utilisé en protégeant les abonnés et en les soulageant des coûts inutiles.
Les bases de la programmation MQL5 : Temps Les bases de la programmation MQL5 : Temps
L’article se concentre sur les fonctions MQL5 standard pour travailler avec le temps, ainsi que sur les techniques de programmation et les fonctions pratiques utiles pour travailler avec le temps nécessaire à la création d’Expert Advisors et d’indicateurs. Une attention particulière est accordée à la théorie générale de la mesure du temps. Cet article devrait intéresser principalement les programmeurs MQL5 novices.
Widgets de signaux de trading MetaTrader 4 et MetaTrader 5 Widgets de signaux de trading MetaTrader 4 et MetaTrader 5
Récemment, les utilisateurs de MetaTrader 4 et MetaTrader 5 ont eu l'opportunité de devenir un fournisseur de signaux et de réaliser des bénéfices supplémentaires. Maintenant, vous pouvez afficher votre succès de trading sur votre site Web, votre blog ou votre page de réseau social à l'aide des nouveaux widgets. Les avantages de l'utilisation des widgets sont évidents : ils augmentent la popularité des fournisseurs de signaux, établissent leur réputation de traders prospères et attirent de nouveaux abonnés. Tous les traders qui placent des widgets sur d'autres sites Web peuvent profiter de ces avantages.
Comment devenir un fournisseur de signaux pour MetaTrader 4 et MetaTrader 5 Comment devenir un fournisseur de signaux pour MetaTrader 4 et MetaTrader 5
Voulez-vous offrir vos signaux de trading et gagner de l’argent ? Inscrivez-vous sur le site MQL5.com en tant que vendeur, spécifiez votre compte de trading et proposez aux traders un abonnement pour copier vos transactions.