English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
L'Histogramme des prix (Profile du Marché) et son implémentation  en MQL5

L'Histogramme des prix (Profile du Marché) et son implémentation en MQL5

MetaTrader 5Exemples | 15 novembre 2021, 13:05
651 0
Dmitry Voronkov
Dmitry Voronkov

"Market Profile essaie de fournir cette logique interne dans le contexte du marché.
C'est une méthode d'analyse qui part du principe que le prix seul
ne communique pas d'informations à l’intervenant, tout comme les mots
sans syntaxe
ou le contexte peut ne pas avoir de sens Le volume fait partie intégrante de l'expression directe
du marché - comprenez-le et vous comprenez le langage du marché."
Robin Mesh

Introduction

A il y a longtemps, en parcourant un abonnement proposé par des revues, j'ai trouvé un article "Profile du Marché et compréhension du langage du marché" (octobre 2002) dans le journal russe "Valutny Spekulant" (à l'heure actuelle, il s'appelait "Active Trader"). L'article original a été publié dans "Nouvelle Pensée en Analyse Technique : Modèles trading des maîtres".

Le Market Profile a été élaboré par le brillantissime penseur Peter Steidlmayer. Il a trouvé l'expression naturelle du marché (le volume) et l'a organisé de manière lisible (la courbe en cloche), afin que les informations objectives générées par le marché soient accessibles aux intervenants dans le marché. Steidlmayer a suggéré de utiliser la représentation alternative de l'information sur les mouvements " horizontaux" et "verticaux" du marché qui conduisent à un ensemble complètement différent de modèles. Il a supposé qu'il existe une impulsion sous-jacente du marché ou un modèle fondamental appelé cycle d'équilibre et de déséquilibre.

Le Profil de Marché mesure le mouvement horizontal du marché à travers le mouvement vertical.  Appelons cela "équilibre" à travers "déséquilibre". Cette relation est le principe organisateur fondamental du marché. Le style de trading d'un trader peut basculer en fonction de la partie du cycle d'équilibre/déséquilibre dans laquelle se trouve le marché. Le Profile du Marché peut déterminer à la fois quand le marché va passer de l'équilibre au déséquilibre et quelle sera l'ampleur du mouvement.

Les deux concepts de base de Market Profile sont :

  1. Le marché est une enchère, et il évolue dans le sens de la fourchette de prix où l'offre et la demande sont plus ou moins égales.
  2. Le marché comporte deux phases : l'activité horizontale et l'activité verticale. Le marché se déplace verticalement lorsque l'offre et la demande ne sont pas égales ou en déséquilibre, et horizontalement lorsqu'elles sont en équilibre ou équitables

Le marché d'équilibre illustré à l'aide du Profil de Marché dans le graphique ci-dessous a tendance à former une courbe en forme de cloche presque parfaite, tournée de 90 degrés en raison de l'orientation du graphique :

 

Fig 1. Le Profil du Marché du marché d'équilibre

Le marché à tendance hors d’équilibré forme également une courbe en cloche, mais son centre est décalé vers le haut ou vers le bas. D'autres configurations qui forment deux pics de cloches, en fonction de l'évolution des prix et de la confiance des acteurs du marché, sont possibles.

Fig 2. Le Profile du Marché du marché de déséquilibre (tendance)

L'utilisation des formes de profil quotidien pour déterminer le degré d'équilibre/de déséquilibre du marché peut être utile, car elle vous offre un point de départ pour comprendre les mouvements entre les différents intervenants du marché.

Une opportunité de trading avec le plus grand bénéfice apparaît lorsque le passage de l'équilibre au déséquilibre est sur le point de se produire. De plus, si vous pouvez identifier cette opportunité de trading et estimer avec exactitude l'ampleur potentielle de ce changement, vous pouvez alors estimer la qualité de ce trade et le temps qui lui est nécessaire.

Il est nécessaire de noter que dans cet article, nous examinerons le code pour dessiner une version simplifiée du Profile du Marché, le soi-disant histogramme des prix basé sur la relation entre le prix et le temps.

Vous pouvez trouver l'exemple de méthodologie de travail avec cet outil disponible sur http://www.enthios.com/, où un groupe de traders a étudié l'Histogramme des Prix depuis 1998. Vous y trouverez également la stratégie Enthios Universal et un exemple de son utilisation.

1. Histogramme des Prix

L'histogramme des Prix est un outil très fiable. C'est un peu intuitif mais extrêmement efficace. L'histogramme des prix vous indique simplement les points de trading "les plus pratiques" du marché. C'est un indicateur avancé aa, car il indique les points où le marché peut changer de direction à l'avance. Les indicateurs tels que les moyennes mobiles ou les oscillateurs ne peuvent pas indiquer les points exacts de résistance et de soutien, ils ne peuvent qu’indiquer si le marché est suracheté ou surestimé.

D’habitude, l'Histogramme des Prix (ou Profil du Marché) est appliqué à 30 min. des grilles de prix pour étudier l'activité du marché pendant une journée. Je préfère utiliser le 5 min. graphiques pour les marchés boursiers et 15-30 min. graphiques pour le FOREX.

2. Point de contrôle

Dans la figure ci-dessus, vous pouvez constater le niveau auquel le marché a été tradé pendant la durée maximale ; il est délimité par la ligne la plus longue de l'histogramme. C'est ce qu'on appelle le point de contrôle, ou POC. Parfois, comme on le constate sur la figure, l'histogramme a deux sommets, l'un d'eux est légèrement plus bas. Dans un tel cas, nous voyons que l'indicateur n’indique qu'un seul POC, mais en fait il y en a deux, et il devrait être pris en compte.

De plus, le niveau de pourcentage de la plage dans l'histogramme crée également des niveaux supplémentaires, appelés niveaux POC secondaires :

Fig 3. Points de contrôle

Qu’indique POC ? Le prix dont se rappelle la plupart des traders Plus le marché est tradé à ce prix, plus le marché s'en rappelle

Psychologiquement, POC agit comme un centre d'attraction.

Le graphique suivant indique ce qui s'est passé quelques jours plus tôt. C'est une bonne démonstration de la puissance de l'Histogramme des Prix.

Fig 4. Le point de contrôle n'est pas absolu ; il indique l’étendue du trade

Le point de contrôle n'est pas absolu ; il indique l’étendue du trading Ainsi, le trader doit être prêt à agir lorsque le marché approche du POC. Il permet d'optimiser les commandes, en utilisant les observations historiques.

Examinons la figure 4. Le POC du 29.12.2009 se situe au prix 68,87. Il est clair, même sans l'histogramme et la ligne POC, que le marché était dans la fourchette 68,82 ~ 68,96 presque toute la journée. Le marché a clôturé en fin de journée à 5 points en dessous du POC. Le lendemain, cela a provoqué l'ouverture du marché avec un écart en baisse.

Il est important de comprendre que nous ne pouvons pas prévoir si le marché va monter ou descendre. On ne peut que supposer que le marché reviendra à la ligne POC et à l'accumulation maximale des lignes de l’histogramme. Mais que se passera-t-il lorsque le prix touche le POC ? La même chose qui arrive avec un objet élastique qui tombe au sol, il va se retourner.  Si cela se produit rapidement, comme un retour de balle de tennis avec une raquette, le prix reviendra très rapidement au niveau initial.

Après l'ouverture du marché le 30.12.2009, nous constatons qu'il s'agissait d'un écart, puis le marché a touché le POC de la veille, puis est rapidement revenu au prix d'ouverture et a mis à jour le minimum.

Notez que le POC n'est pas tout a fait exact (les traders expérimentés savent qu'il n'y a pas de niveaux de résistance clairs lorsque le prix atteint un maximum, un minimum ou une plage de concentration). Ce qui se passe à ce stade là dépend des acteurs du marché. Si la volonté collective (par exemple, la publication d’informations) coïncide, alors le marché passera par le POC, mais c'est rare et il peut être utilisé pour élaborer un système de trading

Faites attention que l’attitude du marché était la même au 31.12.2009. Lorsque le prix a touché POC, les acheteurs ont cédé aux vendeurs.

3. Point de Contrôle Vierge

Le Virgin POC (Point de Contrôle Vierge) est un niveau que le prix n'a pas atteint dans les prochains jours.

La logique est simple, comme décrit ci-dessus, le POC est un point d'attraction pour le marché. Au fur et à mesure que le prix s'éloigne du POC, la force d'attraction croît. Et plus le prix s'éloigne du Virgin POC, plus grande est la possibilité que lorsqu'il reviendra à ce niveau, un rebond se produira et probablement un renversement de prix se produira également.

Fig 5. Ancien et actuel Virgin POC

Sur la figure 5, les anciens POC Virgin qui étaient les niveaux de support et de résistance sont marqués par des cercles. Les POC vierges en activité sont marqués avec des valeurs de prix.

Une fois que le prix a touché le Virgin POC, il cesse d'être un "vierge". Psychologiquement, le marché ne le considère plus comme un niveau substantiel de support ou de résistance. Les traders peuvent toujours voir les niveaux de prix, qui ont initialement formé le POC, mais comme un simple cumul de prix.

Vous pouvez trouver plus de détails sur les niveaux de prix dans le "Master-trading : Le livre X-Files" d'Eric Naiman (Chapitre 4, "Le niveau de prix est une ligne de base").

4. Implémentation de l'Histogramme des Prix dans MQL5

Ma première version de Price Histogram est apparue en 2006, elle a été écrite en MQL4 dans MetaTrader4 pour un usage personnel. Au cours de l’élaboration de cet indicateur, j'étais confronté à quelques difficultés , en voici quelques-unes :

    1. nombre de barres très court dans l'histoire pour M5, sans parler de M1 ;
    2. la nécessité d’élaborer des fonctions spéciales pour travailler avec l'historique, telles que le retour d'un jour en tenant compte des jours fériés, la vérification de l'heure de clôture du marché le vendredi, la vérification de l'heure d'ouverture et de clôture du marché des CFD, etc.
    3. recalcul de l'indicateur lors des changements des délais et, par conséquent, des retards terminaux.

    Par conséquent, lorsque les tests bêta de МetaТrader5 et MQL5 ont commencé, j'ai décidé de le convertir en MQL5.

    Comme on dit, "la première crêpe est toujours un peu délicate", j'ai essayé de l’implémenter comme indicateur.

    Commençons par le bon : la présence de la longue histoire de minute cotations pour tous les symboles, la possibilité d'obtenir des données historiques pour une certaine période de temps à n'importe quelle plage de temps.

    Maintenant, je vais expliquer pourquoi il a pris fin Je n'ai pas pris en compte les caractéristiques des indicateurs MQL5 :

      1. la durée d'exécution de l'indicateur est cruciale ;
      2. les caractéristiques du travail de l'indicateur après la modification du calendrier.

      L'exécution de la fonction OnCalculate(), qui correspond au gestionnaire d'événements Calculate, dispose d’ un temps d'exécution crucial En conséquence, le traitement de 260 jours (période annuelle) à l'aide de l'historique des barres des minutes prend beaucoup de temps, jusqu'à plusieurs minutes. Bien sûr, nous pouvons l’admettre, si les calculs effectués à la fois après l'indicateur attaché au graphique. Mais ce n'est pas le cas pour les modifications de calendrier. Lorsque l'indicateur passe à une autre période, l'ancienne copie de l'indicateur est détruite et la nouvelle est créée. C'est pourquoi après les changements de calendrier nous devons recalculer à nouveau les mêmes niveaux et cela prend beaucoup de temps.

      Mais comme dit, si vous ne savez pas quoi faire - "Lire la documentation d'abord", dans notre cas, c'est la documentation de MQL5. La solution était très simple - Implémenter cet indicateur en tant qu'Expert Advisor qui ne trade pas.

      Les avantages d'Expert Advisor sont :

        1. le temps de traitement n'est pas critique pour le gestionnaire d'événements Init dans OnTick ();
        2. la possibilité d'obtenir les paramètres du gestionnaire OnDeinit (const int raison).

        Les Expert Advisors diffèrent des indicateurs suivants : après la modification de période, l'Expert Advisor génère simplement l'événement DeInit avec le paramètre de raison REASON_CHARTCHANGE, il ne décharge pas l'Expert Advisor de la mémoire et sert les valeurs des variables globales.. Il nous permet d'effectuer tous les calculs à la fois après l'attachement d'Expert Advisor, en modifiant ses paramètres et en faisant apparaître de nouvelles données, dans notre cas pour un nouveau jour de trading.

        Présentons quelques définitions qui seront nécessaires plus tard.

        La programmation orientée objet (POO) - est un style de programmation dont les concepts de base sont les concepts d'objets et de classes.

        L'Objet est une entité dans l'espace virtuel, avec un état et une attitude spécifiés ; il dispose de quelques valeurs de propriétés (appelées attributs) et des opérations avec elles (appelées en tant que méthodes).

        En POO, la classe est un type de données abstrait spécial, caractérisé par sa construction. La classe est un concept principal en POO. La classe est différente des autres types de données abstraits. La définition de données en classe contient également des méthodes de classe de son traitement de données (interface).

        En programmation, il existe un concept d'interface logicielle qui englobe une liste de calculs possibles pouvant être effectués par une partie du programme, y compris des algorithmes, une description des arguments et l'ordre des paramètres d'entrée à effectuer et ses valeurs de retour. L'interface de type de données abstrait a été élaborée pour une description formalisée d'une telle liste. Les algorithmes eux-mêmes et le code qui effectueront tous ces calculs ne sont pas indiqués et appelés comme implémentation d'interface.

        La création de classe est la création d'une structure avec des champs et des méthodes. La classe entière peut être considérée comme un modèle pour la création d'objets, qui sont des instances de classe. Les instances de classe sont créées à l'aide du même modèle, elles ont donc les mêmes champs et méthodes.

        Commençons...

        Le code source se trouve dans 4 fichiers. Le fichier principal est PriceHistogram.mq5, les autres fichiers sont : ClassExpert.mqh, ClassPriceHistogram.mqh et ClassProgressBar.mqh. Les fichiers avec l'extension .mqh contiennent la description et les méthodes des classes. Tous les fichiers doivent se trouver dans le même répertoire, Mon répertoire est : \MQL5\ Experts\PriceHistogram.

        4.1. PriceHistogram.mq5

        La première instruction dans le code source est :

        #include "ClassExpert.mqh"

        La directive du compilateur #include inclut le texte du fichier indiqué. Dans notre cas, il s'agit de la description de la classe CExpert (discutée ci-dessous).

        Le suivant est un bloc de variables d'entrée qui sont des paramètres d'Expert Advisor.

        // The block input parameters
        input int         DayTheHistogram   = 10;          // Days for histogram
        input int         DaysForCalculation= 500;         // Days for calculation(-1 all)
        input uint        RangePercent      = 70;          // Percent range
        input color       InnerRange        =Indigo;       // Inner range
        input color       OuterRange        =Magenta;      // Outer range
        input color       ControlPoint      =Orange;       // Point of Control
        input bool        ShowValue         =true;         // Show Values
        

        Après cela, la variable ExtExpert (de type classe CExpert) est déclarée.

        Le suivant est celui des gestionnaires d'événements standard qui se trouvent dans les programmes MQL5. Les gestionnaires d'événements appellent les méthodes correspondantes de la classe CExpert.

        Il existe une seule méthode qui effectue certaines opérations avant l'exécution de CExpert - c'est la méthode OnInit() :
        int OnInit()
          {
        //---
        // We check for symbol synchronization before the start of calculations
           int err=0;
           while(!(bool)SeriesInfoInteger(Symbol(),0,SERIES_SYNCRONIZED) && err<AMOUNT_OF_ATTEMPTS)
             {
              Sleep(500);
              err++;
             }
        // CExpert class initialization
           ExtExpert.RangePercent=RangePercent;
           ExtExpert.InnerRange=InnerRange;
           ExtExpert.OuterRange=OuterRange;
           ExtExpert.ControlPoint=ControlPoint;
           ExtExpert.ShowValue=ShowValue;
           ExtExpert.DaysForCalculation=DaysForCalculation;
           ExtExpert.DayTheHistogram=DayTheHistogram;
           ExtExpert.Init();
           return(0);
          }
        

        Lorsque j'ai rédigé la première version de l'Expert Advisor et que je l'ai exécutée, j'ai du mal à comprendre pourquoi elle se termine avec une erreur après le redémarrage du terminal client ou un changement de symbole. Et cela se produit lorsque le terminal client a été déconnecté ou qu'un symbole n'a pas été utilisé depuis longtemps.

        C'est bien que les développeurs aient ajouté le débogueur à MetaEditor5. Je me rappelle de beaucoup de commandes Print() et Comment(), utilisées pour vérifier les valeurs des variables dans MetaEditor4. Un grand merci aux développeurs de MetaEditor5.

        Dans mon cas, tout était facile ; l'expert démarre avant la connexion au serveur et la mise à jour des données historiques. Pour résoudre ce problème, j'ai dû utiliser le SeriesInfoInteger(Symbol(),0,SERIES_SYNCRONIZED), qui signale que les données sont synchronisées ou non, et le cycle while (), le cas de l'absence de connexion, il utilise la variable de compteur err.

        Une fois les données synchronisées, ou le cycle terminé à cause du compteur en l'absence de connexion, nous passons les paramètres d'entrée de notre classe experte CExpert, et appelons la méthode d'initialisation de classe Init().

        Comme vous le constatez, grâce au concept de classes dans MQL5, notre fichier PriceHistogram.mq5 s'est transformé en un simple modèle, et tout le traitement ultérieur se fait dans la classe CExpert, déclarée dans le fichier ClassExpert.mqh.

        4.2. ClassExpert.mqh

        Examinons sa description.

        //+------------------------------------------------------------------+
        //|   Class CExpert                                                  |
        //|   Class description                                              |
        //+------------------------------------------------------------------+
        class CExpert
          {
        public:
           int               DaysForCalculation; // Days to calculate (-1 for all)
           int               DayTheHistogram;    // Days for Histogram 
           int               RangePercent;       // Percent range
           color             InnerRange;         // Internal range color
           color             OuterRange;         // Outer range color
           color             ControlPoint;       // Point of Control (POC) Color
           bool              ShowValue;          // Show value
        

        La section publique est ouverte et accessible depuis les variables extérieures. Vous remarquerez que les noms des variables coïncident avec les noms de la section des paramètres d'entrée décrite dans PriceHistogram.mq5. Ce n'est pas nécessaire car les paramètres d'entrée sont globaux. Mais dans ce cas - est un hommage aux bonnes règles d'élevage, il est souhaitable d'éviter l’utilisation des variables externes au sein de la classe.

        private:
           CList             list_object;        // The dynamic list of CObject class instances
           string            name_symbol;        // Symbol name
           int               count_bars;         // Number of daily bars
           bool              event_on;           // Flag of events processing
        

        La section privée est clôturée de l'extérieur et est accessible uniquement à l'intérieur de la classe. Je voudrais décrire la variable list_object de type CList, qui est une classe de la bibliothèque MQL5 standard. La classe CList est une classe dynamique avec une liste d'instances de la classe CObject et de ses héritiers. J’ utiliserai cette liste pour le stockage des références pour les éléments de la classe CPriceHistogram, qui est un héritier de la classe CObject ; nous considérerons les détails ci-dessous. La description de la classe CList se trouve dans List.mqh, et elle est incluse à l'aide de la directive du compilateur #include <Arrays\List.mqh>.

        public:
           // Class constructor
                             CExpert();
           // Class destructor
                            ~CExpert(){Deinit(REASON_CHARTCLOSE);}
           // Initialization method
           bool              Init();
           // Deinitialization method
           void              Deinit(const int reason);
           // Method of OnTick processing
           void              OnTick();
           // Method of OnChartEvent() event processing
           void              OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
           // Method of OnTimer() event processing
           void              OnTimer();
        };

        Ce qui suit est une section de méthodes publiques. Comme vous l'avez deviné, ces méthodes (fonctions) sont disponibles en dehors de la classe.

        Et enfin, l'accolade avec un point-virgule complète la description de la classe.

        Examinons les méthodes de classe en détail.

        Le constructeur de classe est un bloc spécial d'instructions, appelé lors de la création de l'objet. Le constructeur est similaire à la méthode, mais diffère de la méthode du fait qu'il n'a pas explicitement un certain type de données renvoyées.

        En langage MQL5, les constructeurs ne peuvent pas avoir le moindre paramètre d'entrée, et chaque classe ne doit avoir qu'un seul constructeur. Dans notre cas, le constructeur est une initialisation primaire de variables.

        Le destructeur est une méthode de classe spéciale utilisée pour la désinitialisation de l'objet (par exemple, la mémoire libre). Dans notre cas, la méthode est appelée comme Deinit (REASON_CHARTCLOSE);

        L'Init() est une méthode d'initialisation de classe. C'est la méthode la plus importante de la classe CExpert ; la création d'objets d'histogramme y a été effectuée. veuillez jeter un œil sur les commentaires pour les détails. Mais je voudrais considérer là des points.

        Le premier, pour créer un Histogramme des Prix quotidien, nous avons besoin des données de temps d'ouverture des jours pour poursuivre Ici, je voudrais faire une digression et attirer votre attention sur les. caractéristiques du travail avec des séries chronologiques..  Pour la demande de données des autres périodes, nous avions besoin d'un temps, donc les fonctions Bars () et CopyTime (), ainsi que d'autres fonctions pour travailler avec des séries temporelles ne renvoient pas toujours les données souhaitées du premier appel.

        J'ai donc dû mettre cette fonction dans la boucle do (...) while (), mais pour la rendre finie, j'ai utilisé la variable counter.

         int err=0;
         do
           {
            // Calculate the number of days which available from the history
            count_bars=Bars(NULL,PERIOD_D1);
            if(DaysForCalculation+1<count_bars)
               count=DaysForCalculation+1;
            else
               count=count_bars;
            if(DaysForCalculation<=0) count=count_bars;
            rates_total=CopyTime(NULL,PERIOD_D1,0,count,day_time_open);
            Sleep(1);
            err++;
           }
         while(rates_total<=0 && err<AMOUNT_OF_ATTEMPTS);
         if(err>=AMOUNT_OF_ATTEMPTS)
           {
           Print("There is no accessible history PERIOD_D1");
           name_symbol=NULL;
           return(false);
           }

        Deuxièmement, l'historique minute de MetaTrader 5 est égal aux jours disponibles, donc cela peut prendre beaucoup de temps, il est donc nécessaire de visualiser le processus de calcul. La classe CProgressBar (#include "ClassProgressBar.mqh") a été élaboré à cet effet. Il crée la barre de progression dans la fenêtre du graphique et la met à jour pendant le processus de calcul.

         // We create the progress bar on the char to shot the loading process
         CProgressBar   *progress=new CProgressBar;
         progress.Create(0,"Loading",0,150,20);
         progress.Text("Calculation:");
         progress.Maximum=rates_total; 

        Le troisième, en cycle, à l'aide de l'instruction "new", on crée l'objet CPriceHistogram, on le configure à l'aide de ses méthodes et on l'initialise en appelant le Init(). En cas de succès, nous l'ajoutons à la liste list_object, par contre nous supprimons hist_obj en utilisant l'instruction delete. La description de la classe CPriceHistogram sera présentée plus loin, voir les commentaires dans le code.

         // In this cycle there is creation of object CPriceHistogram
         // its initialization and addition to the list of objects
         for(int i=0;i<rates_total;i++)
           {
            CPriceHistogram  *hist_obj=new CPriceHistogram();
            //         hist_obj.StepHistigram(step);
            // We set the flag to show text labels
            hist_obj.ShowLevel(ShowValue);
            // We set POCs colour
            hist_obj.ColorPOCs(ControlPoint);
            // We set colour for inner range
            hist_obj.ColorInner(InnerRange);
            // We set colour for outer range
            hist_obj.ColorOuter(OuterRange);
            // We set the percent range
            hist_obj.RangePercent(RangePercent);
            //  hist_obj.ShowSecondaryPOCs((i>=rates_total-DayTheHistogram),PeriodSeconds(PERIOD_D1));
            if(hist_obj.Init(day_time_open[i],day_time_open[i]+PeriodSeconds(PERIOD_D1),(i>=rates_total-DayTheHistogram)))
               list_object.Add(hist_obj);
            else
               delete hist_obj; // Delete object if there was an error
            progress.Value(i);
           }; 

        Le OnTick() est une méthode appelée lorsque vous recevez un nouveau tick pour un symbole. On compare les valeurs du nombre de jours stockées dans la variable count_bars avec le nombre de barres journalières retournées par Bars (Symbol(), PERIOD_D1) et si elles ne sont pas égales on appelle de force la méthode Init() pour l'initialisation de la classe, effaçant la liste list_object et en changeant la variable en NULL name_symbol . Si le nombre de jours n'a pas changé, la boucle parcourt tous les objets stockés dans la classe CPriceHistogram list_object, et exécute une méthode Redraw(), pour ceux qui sont Virgin ("vierge").

        Le Deinit() est une méthode de désinitialisation de classe. Dans le cas de REASON_PARAMETERS (les paramètres d'entrée ont été modifiés par l'utilisateur), nous effaçons la liste list_object et définissons la variable name_symbol sur NULL. Dans d'autres cas, l'expert ne fait rien, mais si vous souhaitez ajouter quelque chose, lisez les commentaires.

        Le OnEvent() est une méthode de traitement d’ événement du terminal client. Les événements sont générés par le terminal client lorsque l'utilisateur travaille avec un graphique. Les détails peuvent être trouvés dans la documentation du langage MQL5. Dans cet Expert Advisor, l'événement de graphique CHARTEVENT_OBJECT_CLICK a été utilisé. En cliquant sur l'élément d'histogramme, il affiche les niveaux de POC secondaires et inverse la couleur de l'histogramme.

        Le OnTimer(void) est une méthode de traitement des événements de minuterie. Il n'est pas utilisé dans mes programmes, mais si vous souhaitez ajouter des actions de minuterie (par exemple, pour afficher l'heure), c'est ici. Avant utilisation, il est nécessaire d'ajouter la ligne suivante au constructeur de classe :

        EventSetTimer(time in seconds);

        Et la ligne suivante au destructeur :

        EventKillTimer(); 

        avant d'appeler la méthode Deinit (REASON_CHARTCLOSE).

        Nous avons considéré la classe CExpert ; elle a été créée pour la démonstration des méthodes de la classe CPriceHistogram.

        4.3. ClassPriceHistogram.mqh
        //+------------------------------------------------------------------+
        //|   Class CPriceHistogram                                          |
        //|   Class description                                              |
        //+------------------------------------------------------------------+
        class CPriceHistogram : public CObject
          {
        private:
           // Class variables
           double            high_day,low_day;
           bool              Init_passed;      // Flag if the initialization has passed or not
           CChartObjectTrend *POCLine;
           CChartObjectTrend *SecondTopPOCLine,*SecondBottomPOCLine;
           CChartObjectText  *POCLable;
           CList             ListHistogramInner; // list for inner lines storage 
           CList             ListHistogramOuter; // list for outer lines storage
           bool              show_level;         // to show values of level
           bool              virgin;             // is it virgin
           bool              show_second_poc;    // show secondary POC levels
           double            second_poc_top;     // value of the top secondary POC level
           double            second_poc_bottom;  // value of the bottom secondary POC level
           double            poc_value;          // POC level value
           color             poc_color;          // color of POC level
           datetime          poc_start_time;
           datetime          poc_end_time;
           bool              show_histogram;     // show histogram  
           color             inner_color;        // inner color of the histogram
           color             outer_color;        // outer color of the histogram
           uint              range_percent;      // percent range
           datetime          time_start;         // start time for construction
           datetime          time_end;           // final time of construction
        public:
           // Class constructor
                             CPriceHistogram();
           // Class destructor
                            ~CPriceHistogram(){Delete();}
           // Class initialization
           bool              Init(datetime time_open,datetime time_close,bool showhistogram);
           // To level value
           void              ShowLevel(bool show){show_level=show; if(Init_passed) RefreshPOCs();}
           bool              ShowLevel(){return(show_level);}
           // To show histogram
           void              ShowHistogram(bool show);
           bool              ShowHistogram(){return(show_histogram);}
           // To show Secondary POC levels
           void              ShowSecondaryPOCs(bool show){show_second_poc=show;if(Init_passed)RefreshPOCs();}
           bool              ShowSecondaryPOCs(){return(show_second_poc);}
           // To set color of POC levels
           void              ColorPOCs(color col){poc_color=col; if(Init_passed)RefreshPOCs();}
           color             ColorPOCs(){return(poc_color);}
           // To set internal colour of histogram
           void              ColorInner(color col);
           color             ColorInner(){return(inner_color);}
           // To set outer colour of histogram
           void              ColorOuter(color col);
           color             ColorOuter(){return(outer_color);}
           // To set percent range
           void              RangePercent(uint percent){range_percent=percent; if(Init_passed)calculationPOCs();}
           uint              RangePercent(){return(range_percent);}
           // Returns value of virginity of POC level
           bool              VirginPOCs(){return(virgin);}
           // Returns starting time of histogram construction
           datetime          GetStartDateTime(){return(time_start);}
           // Updating of POC levels
           bool              RefreshPOCs();
        private:
           // Calculations of the histogram and POC levels
           bool              calculationPOCs();
           // Class delete
           void              Delete();
          }; 

        Dans la description de la classe, j'ai essayé de fournir des commentaires pour les variables et les méthodes de classe. Examinons certains d'entre eux en détail.

        //+------------------------------------------------------------------+
        //|   Class initialization                                           |
        //+------------------------------------------------------------------+
        bool CPriceHistogram::Init(datetime time_open,datetime time_close,bool showhistogram) 

        Cette méthode utilise trois paramètres d'entrée - l'ouverture du bâtiment, l'heure de fermeture de la construction et un drapeau indiquant la construction d’ un histogramme, ou seulement les niveaux de POC.

        Dans mon exemple (classe CExpert) les paramètres d'entrée sont transmis au jour d'ouverture et à l'heure d'ouverture le jour suivant day_time_open [i] + PeriodSeconds (PERIOD_D1). Mais lorsque vous utilisez cette classe, rien n'empêche de demander, par exemple, l'heure de la session européenne, américaine, ou la taille de l'écart dans la semaine, le mois, etc.

        //+---------------------------------------------------------------------------------------+
        //|   Calculations of the histogram and POCs levels                                       |
        //+---------------------------------------------------------------------------------------+
        bool CPriceHistogram::calculationPOCs() 

        Dans cette méthode, l'origine de tous les niveaux et des calculs de leur construction, c'est une méthode privée fermée, inaccessible de l'extérieur.

        // We get the data from time_start to time_end
           int err=0;
           do
             {
              //--- for each bar we are copying the open time
              rates_time=CopyTime(NULL,PERIOD_M1,time_start,time_end,iTime);
              if(rates_time<0)
                 PrintErrorOnCopyFunction("CopyTime",_Symbol,PERIOD_M1,GetLastError());
        
              //--- for each bar we are copying the High prices
              rates_high=CopyHigh(NULL,PERIOD_M1,time_start,time_end,iHigh);
              if(rates_high<0)
                 PrintErrorOnCopyFunction("CopyHigh",_Symbol,PERIOD_M1,GetLastError());
        
              //--- for each bar we are copying the Low prices
              rates_total=CopyLow(NULL,PERIOD_M1,time_start,time_end,iLow);
              if(rates_total<0)
                 PrintErrorOnCopyFunction("CopyLow",_Symbol,PERIOD_M1,GetLastError());
        
              err++;
             }
           while((rates_time<=0 || (rates_total!=rates_high && rates_total!=rates_time)) && err<AMOUNT_OF_ATTEMPTS&&!IsStopped());
           if(err>=AMOUNT_OF_ATTEMPTS)
             {
              return(false);
             }
           poc_start_time=iTime[0];
           high_day=iHigh[ArrayMaximum(iHigh,0,WHOLE_ARRAY)];
           low_day=iLow[ArrayMinimum(iLow,0,WHOLE_ARRAY)];
           int count=int((high_day-low_day)/_Point)+1;
        // Count of duration of a finding of the price at each level
           int ThicknessOfLevel[];    // create an array for count of ticks
           ArrayResize(ThicknessOfLevel,count);
           ArrayInitialize(ThicknessOfLevel,0);
           for(int i=0;i<rates_total;i++)
             {
              double C=iLow[i];
              while(C<iHigh[i])
                {
                 int Index=int((C-low_day)/_Point);
                 ThicknessOfLevel[Index]++;
                 C+=_Point;
                }
             }
           int MaxLevel=ArrayMaximum(ThicknessOfLevel,0,count);
           poc_value=low_day+_Point*MaxLevel;

        Tout d'abord, nous obtenons les données d'historique des barres de minutes pour une certaine période de temps (iTime [], iHigh[], iLow[]). Ensuite, nous trouvons l'élément maximum et minimum de iHigh[] et Low[]. Ensuite, nous calculons le nombre de points (compte) du minimum au maximum, et réservons le tableau ThicknessOfLevel avec les éléments ThicknessOfLevel. Dans le cycle, nous parcourons la bougie de chaque minute du bas en haut et en ajoutant les données de la présence de la période à ce niveau de prix. Ensuite nous trouvons l'élément maximal du tableau ThicknessOfLevel, ce sera le niveau auquel prix a été le plus longtemps. C'est notre niveau POC.

        // Search for the secondary POCs
           int range_min=ThicknessOfLevel[MaxLevel]-ThicknessOfLevel[MaxLevel]*range_percent/100;
           int DownLine=0;
           int UpLine=0;
           for(int i=0;i<count;i++)
             {
              if(ThicknessOfLevel[i]>=range_min)
                {
                 DownLine=i;
                 break;
                }
             }
           for(int i=count-1;i>0;i--)
             {
              if(ThicknessOfLevel[i]>=range_min)
                {
                 UpLine=i;
                 break;
                }
             }
           if(DownLine==0)
              DownLine=MaxLevel;
           if(UpLine==0)
              UpLine=MaxLevel;
           second_poc_top=low_day+_Point*UpLine;
           second_poc_bottom=low_day+_Point*DownLine;
        

        L'étape suivante consiste à trouver les niveaux de POC secondaires. Rappelons que notre diagramme est divisé. Rappelons que notre histogramme est divisé en deux gammes, la gamme interne et externe (affichées dans des couleurs différentes) et la gamme de taille est définie en pourcentage de temps du prix à ce niveau. La gamme des limites internes sont des niveaux de POC secondaires.

        Après avoir trouvé la plage de pourcentage POC secondaire - Bordures, avancez vers la construction de l'histogramme.

        // Histogram formation 
           if(show_histogram)
             {
              datetime Delta=(iTime[rates_total-1]-iTime[0]-PeriodSeconds(PERIOD_H1))/ThicknessOfLevel[MaxLevel];
              int step=1;
              
              if(count>100)
                 step=count/100// Calculate the step of the histogram (100 lines as max)
        
              ListHistogramInner.Clear();
              ListHistogramOuter.Clear();
              for(int i=0;i<count;i+=step)
                {
                 string name=TimeToString(time_start)+" "+IntegerToString(i);
                 double StartY= low_day+_Point*i;
                 datetime EndX= iTime[0]+(ThicknessOfLevel[i])*Delta;
        
                 CChartObjectTrend *obj=new CChartObjectTrend();
                 obj.Create(0,name,0,poc_start_time,StartY,EndX,StartY);
                 obj.Background(true);
                 if(i>=DownLine && i<=UpLine)
                   {
                    obj.Color(inner_color);
                    ListHistogramInner.Add(obj);
                   }
                 else
                   {
                    obj.Color(outer_color);
                    ListHistogramOuter.Add(obj);
                   }
                }
             }
        
        

        Il faut mentionner qu'afin de réduire la charge sur le terminal, j'apporte à l'écran un maximum de 100 lignes pour chaque histogramme. Les lignes de l'histogramme sont stockées dans deux listes, et ListHistogramInner ListHistogramOuter, qui sont les objets que nous connaissons déjà dans la classe CList. Mais ces pointeurs sont stockés dans une classe standard d'objets CChartObjectTrend. Pourquoi deux listes, je pense que vous pouvez deviner à partir du titre, pour pouvoir changer l'histogramme des couleurs.

        // We receive data beginning from the final time of the histogram till current time
           err=0;
           do
             {
              rates_time=CopyTime(NULL,PERIOD_M1,time_end,last_tick.time,iTime);
              rates_high=CopyHigh(NULL,PERIOD_M1,time_end,last_tick.time,iHigh);
              rates_total=CopyLow(NULL,PERIOD_M1,time_end,last_tick.time,iLow);
              err++;
             }
           while((rates_time<=0 || (rates_total!=rates_high && rates_total!=rates_time)) && err<AMOUNT_OF_ATTEMPTS);
        // If there isn't history, the present day, level is virgin, we hoist the colours
           if(rates_time==0)
             {
              virgin=true;
             }
           else
        // Otherwise we check history
             {
              for(index=0;index<rates_total;index++)
                 if(poc_value<iHigh[index] && poc_value>iLow[index]) break;
        
              if(index<rates_total)   // If level has crossed
                 poc_end_time=iTime[index];
              else
                 virgin=true;
             }
           if(POCLine==NULL)
             {     
              POCLine=new CChartObjectTrend();
              POCLine.Create(0,TimeToString(time_start)+" POC ",0,poc_start_time,poc_value,0,0);
             }
           POCLine.Color(poc_color);
           RefreshPOCs();

        J'ai essayé de concevoir le CPriceHistogram avec toutes les méthodes nécessaires, s'il est insuffisant, vous pouvez l'ajouter vous-même et je vous aiderai.

        Résumé

        Encore une fois, je voudrais rappeler que l'histogramme des prix est fiable, mais l'outil intuitif, les signaux de confirmation sont donc nécessaires à son utilisation.

        Merci pour votre intérêt. Je suis prêt à répondre à toutes vos questions.

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

        Comment Échanger des Données : Une DLL pour MQL5 en 10 minutes Comment Échanger des Données : Une DLL pour MQL5 en 10 minutes
        Maintenant, peu de développeurs se rappellent de la façon d'écrire une DLL simple et des caractéristiques spéciales des différentes liaisons système. À l'aide de plusieurs exemples, je vais tenter de montrer l'ensemble du processus de création de la DLL simple en 10 minutes, ainsi que de discuter de certains détails techniques de notre implémentation de liaison. Je vais montrer étape par étape le processus de la création de DLL dans Visual Studio avec des exemples d'échange de différents types de variables (nombres, tableaux, chaînes, etc.). En outre, je vais vous expliquer comment protéger votre terminal client des plantages dans les DLL personnalisées.
        Combinatoires et probabilités pour le trading (Partie V) : Analyse des courbes Combinatoires et probabilités pour le trading (Partie V) : Analyse des courbes
        Dans cet article, j'ai décidé de mener une étude sur la possibilité de réduire les états multiples à des systèmes à deux états. L'objectif principal de cet article est d'analyser et de tirer des conclusions utiles qui pourraient contribuer au développement d'algorithmes de trading évolutifs basés sur la théorie des probabilités. Bien entendu, ce sujet fait appel aux mathématiques. Mais au vu de l'expérience des articles précédents, je constate que les informations générales sont plus utiles que les détails.
        Échange de Données entre les Indicateurs : C'est facile Échange de Données entre les Indicateurs : C'est facile
        Nous souhaitons créer un tel environnement, qui donnerait accès aux données d'indicateurs attachés à un graphique, et aurait les propriétés suivantes : absence de copie de données ; modification minimale du code des méthodes disponibles, si nous devons les utiliser ; Le code MQL est préférable (bien sûr, nous devons utiliser des DLL, mais nous n'utiliserons qu'une douzaine de chaînes de code C++). L'article décrit une méthode simple pour élaborer un environnement de programme pour le terminal MetaTrader, qui fournirait des moyens d'accès aux tampons d'indicateurs d'autres programmes MQL.
        Combinatoires et probabilités pour le trading (Partie IV) : Logique de Bernoulli Combinatoires et probabilités pour le trading (Partie IV) : Logique de Bernoulli
        Dans cet article, j'ai décidé de mettre en avant le célèbre schéma de Bernoulli et de montrer comment il peut être utilisé pour décrire des tableaux de données liées au trading. Tous ces éléments seront ensuite utilisés pour créer un système de trading auto-adaptatif. Nous chercherons également un algorithme plus générique, dont un cas particulier est la formule de Bernoulli, et nous lui trouverons une application.