English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
MQL5 : Créez votre propre indicateur

MQL5 : Créez votre propre indicateur

MetaTrader 5Exemples | 22 décembre 2021, 16:09
879 0
MetaQuotes
MetaQuotes

Introduction

Qu’est-ce qu’un indicateur? C’est un ensemble de valeurs calculées que nous voulons afficher à l’écran de manière pratique. Les ensembles de valeurs sont représentés dans les programmes sous forme de tableaux. Ainsi, la création d’un indicateur signifie écrire un algorithme qui gère certains tableaux (tableaux de prix) et enregistre les résultats de la manipulation sur d’autres tableaux (valeurs d’indicateur).

Malgré le fait qu’il existe de nombreux indicateurs disponibles, qui sont déjà devenus classiques, la nécessité de créer ses propres indicateurs existera toujours. Ces indicateurs que nous créons à l’aide de nos propres algorithmes sont appelés indicateurs personnalisés. Dans cet article, nous verrons comment créer un indicateur personnalisé simple.

Les indicateurs sont différents

Un indicateur peut être présenté sous forme de lignes ou de zones colorées, ou il peut être affiché sous forme d’étiquettes spéciales pointant vers des moments favorables pour la prise de position. De plus, ces types peuvent être combinés, ce qui donne encore plus de types d’indicateurs. Nous envisagerons la création d’un indicateur sur l’exemple du célèbre True Strength Index développé par William Blau.

Indice de force réelle

L’indicateur STI est basé sur la dynamique à double lissage pour identifier les tendances, ainsi que les zones de survente/surachat. L’explication mathématique de celui-ci peut être trouvée dans Momentum, Direction, and Divergence de William Blau. Ici, nous n’incluons que sa formule de calcul.

TSI(CLOSE,r,s) =100*EMA(EMA(mtm,r),s) / EMA(EMA(|mtm|,r),s)

Où :

  • mtm =CLOSE current – CLOSprev, tableau de valeurs indiquant la différence entre les prix de close de la barre actuelle et ceux de la barre précédente ;
  • EMA(mtm,r) = lissage exponentiel des valeurs mtm avec la durée de la période égale à r ;
  • EMA(EMA(mtm,r),s) = lissage exponentiel des valeurs EMA(mtm,r) avec s période ;
  • |mtm| = valeurs absolues mtm ;
  • r = 25,
  • s = 13.

De cette formule, nous pouvons extraire trois paramètres qui influencent le calcul de l’indicateur. Il s’agit des périodes r et s, ainsi que du type de prix utilisés pour les calculs. Dans notre cas, nous utilisons prix CLOSE.

Assistant MQL5

Affichons TSI comme une ligne bleue - ici, nous devons démarrer l’assistant MQL5. À la première étape, nous devons indiquer le type de programme que nous voulons créer - indicateur personnalisé. À la deuxième étape, définissons le nom du programme, les paramètres r et s et leurs valeurs.

Assistant MQL5 : Configuration du nom et du paramètre de l’indicateur

Après cela, définissons que l’indicateur doit être affiché dans une fenêtre séparée sous la forme d’une ligne bleue et définissons l’étiquette TSI pour cette ligne.

Assistant MQL5 : configuration du type d’indicateur

Toutes les données initiales ont été saisies, nous appuyons donc sur Terminé et obtenons un brouillon de notre indicateur. 

//+------------------------------------------------------------------+
//|                                          True Strength Index.mq5 |
//|                        Copyright 2009, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
//---- plot TSI
#property indicator_label1  "TSI"
#property indicator_type1   DRAW_LINE
#property indicator_color1  Blue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- input parameters
input int      r=25;
input int      s=13;
//--- indicator buffers
double         TSIBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,TSIBuffer,INDICATOR_DATA);
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
  {
//---
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

L’Assistant MQL5 crée l’en-tête de l’indicateur, dans lequel il écrit les propriétés de l’indicateur, à savoir :

  • L’indicateur s’affiche dans une fenêtre séparée ;
  • nombre de tampons d’indicateur, indicator_buffers= 1 ;
  • nombre de tracés, indicator_plots= 1 ;
  • nom du tracé n° 1, indicator_label1=« STI » ;
  • style du premier tracé - ligne, indicator_type1=DRAW_LINE ;
  • couleur du tracé n° 1, indicator_color1=Bleu ;
  • style d’une ligne, indicator_style1=STYLE_SOLID ;
  • largeur de ligne pour tracé 1, indicator_width1=1.

Tous les préparatifs sont prêts, maintenant nous pouvons affiner et améliorer notre code.

OnCalculate()

La fonction OnCalculate() est le gestionnaire de l’événement Calculate, qui apparaît lorsqu’il est nécessaire de recalculer les valeurs de l’indicateur et de le retracer sur le graphique. Il s’agit de l’événement d’une nouvelle réception de traits, d’une mise à jour de l’historique des symboles, etc. C’est pourquoi le code principal pour tous les calculs de valeurs d’indicateur doit être situé exactement dans cette fonction.

Bien sûr, les calculs auxiliaires peuvent être implémentés dans d’autres fonctions distinctes, mais ces fonctions doivent être utilisées dans le gestionnaire OnCalculate.

Par défaut, l’Assistant MQL5 crée le deuxième formulaire de OnCalculate(), qui permet d’accéder à tous les types de séries chronologiques :

  • Prix Open, High, Low, Close ;
  • volumes (réels et/ou trait) ;
  • spread ;
  • temps d’ouverture de période.

Mais dans notre cas, nous n’avons besoin que d’un seul tableau de données, c’est pourquoi changeons OnCalculate() le premier formulaire d’appel.

int OnCalculate (const int rates_total,      // size of the price[] array
                 const int prev_calculated,  // number of available bars at the previous call
                 const int begin,            // from what index in price[] authentic data start
                 const double& price[])      // array, on which the indicator will be calculated
  {
//---
//--- return value of prev_calculated for next call
   return(rates_total);
  }  

Cela nous permettra d’appliquer davantage l’indicateur non seulement aux données sur les prix, mais aussi de créer l’indicateur basé sur les valeurs d’autres indicateurs.

Spécification du type de données pour le calcul de l’indicateur personnalisé

Si nous sélectionnons Close dans l’onglet Paramètres (il est proposé par défaut), alors price[] transmis vers OnCalculate() contiendra les prix close. Si nous sélectionnons, par exemple, Typical Price, price[] contiendra des prix de (High+Low+Close)/3 pour chaque période.

Le paramètre rates_total indique la taille du tableau price[] ; il sera utile pour organiser les calculs dans un cycle. L’indexation des éléments dans le prix[] commence à partir de zéro et est dirigée du passé vers le futur. C’est-à-dire que l’élément price[0] contient la valeur la plus ancienne, tandis que price[rates_total-1] contient le dernier élément de tableau.

Organisation des tampons d’indicateurs auxiliaires

Une seule ligne sera affichée dans un graphique, c’est-à-dire les données d’un tableau d’indicateurs. Mais avant cela, nous devons organiser des calculs intermédiaires. Les données intermédiaires sont stockées dans des tableaux d’indicateurs marqués par l’attribut INDICATOR_CALCULATIONS. D’après le formulaire, nous voyons que nous avons besoin de tableaux supplémentaires :

  1. pour les valeurs mtm - tableau MTMBuffer[] ;
  2. pour les valeurs |mtm| - tableau AbsMTMBuffer[] ;
  3. pour EMA(mtm,r) - tableau EMA_MTMBuffer[] ;
  4. pour EMA(EMA(mtm,r),s) - tableau EMA2_MTMBuffer[] ;
  5. pour EMA(|mtm|,r) - tableau EMA_AbsMTMBuffer[] ;
  6. pour EMA(EMA(|mtm|,r),s) - tableau EMA2_AbsMTMBuffer[].

Au total, nous devons ajouter 6 tableaux supplémentaires de double type au niveau global et lier ces tableaux avec les tampons d’indicateur de la fonction Onlnit(). N’oubliez pas d’indiquer le nouveau nombre de tampons d’indicateurs ; la propriété indicator_buffers doit être égale à 7 (il y en avait 1, et 6 tampons supplémentaires ont été ajoutés).

#property indicator_buffers 7

Maintenant, le code de l’indicateur ressemble à ceci :

#property indicator_separate_window
#property indicator_buffers 7
#property indicator_plots   1
//---- plot TSI
#property indicator_label1  "TSI"
#property indicator_type1   DRAW_LINE
#property indicator_color1  Blue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- input parameters
input int      r=25;
input int      s=13;
//--- indicator buffers
double         TSIBuffer[];
double         MTMBuffer[];
double         AbsMTMBuffer[];
double         EMA_MTMBuffer[];
double         EMA2_MTMBuffer[];
double         EMA_AbsMTMBuffer[];
double         EMA2_AbsMTMBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,TSIBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,MTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,AbsMTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(3,EMA_MTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(4,EMA2_MTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(5,EMA_AbsMTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(6,EMA2_AbsMTMBuffer,INDICATOR_CALCULATIONS);
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate (const int rates_total,    // size of the price[] array;
                 const int prev_calculated,// number of available bars;
                                           // during the previous call;
                 const int begin,          // from what index in  
                                           // price[] authentic data start;
                 const double& price[])    // array, on which the indicator will be calculated;
  {
//---
//--- return value of prev_calculated for next call
   return(rates_total);
  }

Calculs intermédiaires

Il est très facile d’organiser le calcul des valeurs pour les tampons MTMBuffer[] et AbsMTMBuffer[]. Dans la boucle, un par un, passez par des valeurs allant de price[1] à price[rates_total-1] et écrivez la différence dans un tableau, et la valeur absolue de la différence dans le second.

//--- calculate values of mtm and |mtm|
   for(int i=1;i<rates_total;i++)
     {
      MTMBuffer[i]=price[i]-price[i-1];
      AbsMTMBuffer[i]=fabs(MTMBuffer[i]);
     }

L’étape suivante est le calcul de la moyenne exponentielle de ces tableaux. Il y a deux façons de le faire. Dans le premier cas, nous écrivons tout l’algorithme en essayant de ne pas faire des erreurs. Dans le second cas, nous utilisons des fonctions prêtes à l’emploi qui sont déjà déboguées et destinées exactement à ces fins.

Dans MQL5, il n’y a pas de fonctions intégrées pour calculer les moyennes mobiles par les valeurs de tableau, mais il existe une bibliothèque disponible de fonctions MovingAverages.mqh, dont le chemin complet est terminal_directory/MQL5/Include/MovingAverages.mqh, où le terminal_directory est un catalogue dans lequel le terminal MetaTrader 5 est installé. La bibliothèque est un fichier Include ; elle contient des fonctions de calcul de moyennes mobiles sur des tableaux utilisant l’une des quatre méthodes classiques :

  • Moyenne simple ;
  • Moyenne exponentielle ;
  • Moyenne lissée ;
  • Moyenne pondérée linéaire.

Pour utiliser ces fonctions, dans n’importe quel programme MQL5, ajoutez ce qui suit dans l’en-tête du code :

#include <MovingAverages.mqh>

Nous avons besoin de la fonction ExponentialMAOnBuffer(), qui calcule la moyenne mobile exponentielle sur le tableau de valeurs et enregistre les valeurs de la moyenne dans un autre tableau.

La fonction de lissage d’un tableau

Totalement, le fichier Include MovingAverages.mqh contient huit fonctions qui peuvent être divisées en deux groupes de fonctions du même type, chacun contenant 4 d’entre elles. Le premier groupe contient des fonctions qui reçoivent un tableau et renvoient simplement une valeur de moyenne mobile à une position spécifiée :

  • SimpleMA() - pour calculer la valeur d’une moyenne simple ;
  • ExponentialMA() - pour calculer la valeur d’une moyenne exponentielle ;
  • SmoothedMA() - pour calculer la valeur d’une moyenne lissée ;
  • LinearWeightedMA() - pour calculer la valeur d’une moyenne pondérée linéaire.

Ces fonctions sont destinées à obtenir la valeur d’une moyenne une fois pour un tableau et ne sont pas optimisées pour plusieurs appels. Si vous devez utiliser une fonction de ce groupe dans une boucle (pour calculer les valeurs d’une moyenne et écrire davantage chaque valeur calculée dans un tableau), vous devrez organiser un algorithme optimal.

Le deuxième groupe de fonctions est destiné à remplir le tableau des destinataires par les valeurs d’une moyenne mobile basée sur le tableau des valeurs initiales :

  • SimpleMAOnBuffer() - remplit le tampon du tableau de sortie[] par les valeurs d’une moyenne simple du tableau price[] ;
  • ExponentialMAOnBuffer() - remplit le tampon du tableau de sortie[] par les valeurs d’une moyenne exponentielle du tableau price[] ;
  • SmoothedMAOnBuffer() - remplit le tampon du tableau de sortie[] par les valeurs d’une moyenne lissée du tableau price[] ;
  • LinearWeightedMAOnBuffer() - remplit le tampon du tableau de sortie[] par les valeurs d’une moyenne pondérée linéaire à partir du tableau price[].

Toutes les fonctions spécifiées, à l’exception des tableaux buffer[], price[] et de la période de moyenne period, obtiennent 3 paramètres supplémentaires, dont le but est analogue aux paramètres de la fonction OnCalculate() - rates_total, prev_calculated et begin. Les fonctions de ce groupe traitent correctement les tableaux passés de price[] et buffer[], en tenant compte de la direction du drapeau d’indexation(AS_SERIES).

Le paramètre begin indique l’indice d’un tableau source, à partir duquel commencent des données significatives, c’est-à-dire des données qui doivent être traitées. Pour le tableau MTMBuffer[], les données réelles commencent par l’indice 1, parce que MTMBuffer[1]=price[1]-price[0]. La valeur de MTMBuffer[0] n’est pas définie, c’est pourquoi begin=1.

//--- calculate the first moving
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         1,  // index, starting from which data for smoothing are available 
                         r,  // period of the exponential average
                         MTMBuffer,       // buffer to calculate average
                         EMA_MTMBuffer);  // into this buffer locate value of the average
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         1,r,AbsMTMBuffer,EMA_AbsMTMBuffer);

Lors de la moyenne, la valeur de la période doit être prise en compte, car dans le tableau de sortie, les valeurs calculées sont remplies avec un petit délai, qui est plus important pour des périodes de moyenne plus longues. Par exemple, si period=10, les valeurs du tableau qui en résultent commenceront par begin+period-1=begin+10-1. Lors des appels ultérieurs de buffer[], il faut en tenir compte, le traitement devrait commencer avec l'indice begin+period-1.

Ainsi, nous pouvons facilement obtenir la deuxième moyenne exponentielle à partir des tableaux de MTMBuffer[] et AbsMTMBuffer :

//--- calculate the second moving average on arrays
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         r,s,EMA_MTMBuffer,EMA2_MTMBuffer);
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         r,s,EMA_AbsMTMBuffer,EMA2_AbsMTMBuffer);

La valeur de begin est maintenant égale à r, car begin=1+r-1 (r est la période de la moyenne exponentielle primaire, la manipulation commence par l’indice 1). Dans les tableaux de sortie de EMA2_MTMBuffer[] et EMA2_AbsMTMBuffer[], les valeurs calculées commencent par l’indice r+s-1, car nous avons commencé à gérer les tableaux d’entrée avec l’indice r, et la période de la deuxième moyenne exponentielle est égale à s.

Tous les pré-calculs sont prêts, nous pouvons maintenant calculer les valeurs de l’indicateur tampon TSIBuffer[], qui seront tracées dans le graphique.

//--- now calculate values of the indicator
   for(int i=r+s-1;i<rates_total;i++)
     {
      TSIBuffer[i]=100*EMA2_MTMBuffer[i]/EMA2_AbsMTMBuffer[i];
     }
Compilez le code en appuyant sur la touche F5 et démarrez-le dans le terminal MetaTrader 5. Ça marche !

La première version de True Strength Index

Il reste encore quelques questions.

Optimisation des calculs

En fait, il ne suffit pas d’écrire un indicateur fonctionnel. Si nous examinons attentivement la mise en œuvre actuelle de OnCalculate(), nous verrons qu’elle n’est pas optimale.

int OnCalculate (const int rates_total,    // size of the price[] array;
                 const int prev_calculated,// number of available bars;
                 // at the previous call;
                 const int begin,// from what index of the 
                 // price[] array true data start;
                 const double &price[]) // array, at which the indicator will be calculated;
  {
//--- calculate values of mtm and |mtm|
   MTMBuffer[0]=0.0;
   AbsMTMBuffer[0]=0.0;
   for(int i=1;i<rates_total;i++)
     {
      MTMBuffer[i]=price[i]-price[i-1];
      AbsMTMBuffer[i]=fabs(MTMBuffer[i]);
     }
//--- calculate the first moving average on arrays
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         1,  // index, starting from which data for smoothing are available 
                         r,  // period of the exponential average
                         MTMBuffer,       // buffer to calculate average
                         EMA_MTMBuffer);  // into this buffer locate value of the average
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         1,r,AbsMTMBuffer,EMA_AbsMTMBuffer);

//--- calculate the second moving average on arrays
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         r,s,EMA_MTMBuffer,EMA2_MTMBuffer);
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         r,s,EMA_AbsMTMBuffer,EMA2_AbsMTMBuffer);
//--- now calculate values of the indicator
   for(int i=r+s-1;i<rates_total;i++)
     {
      TSIBuffer[i]=100*EMA2_MTMBuffer[i]/EMA2_AbsMTMBuffer[i];
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }

À chaque démarrage de fonction, nous calculons des valeurs dans des tableaux de MTMBuffer[] et AbsMTMBuffer[]. Dans ce cas, si la taille du prix est égale à des centaines de milliers, voire des millions, des calculs répétés inutiles peuvent prendre toutes les ressources du processeur, quelle que soit sa puissance.

Pour organiser les calculs optimaux, nous utilisons le paramètre d’entrée prev_calculated, qui est égal à la valeur renvoyée par OnCalculate() lors de l’appel précédent. Dans le premier appel de la fonction, la valeur de prev_calculated est toujours égale à 0. Dans ce cas, nous calculons toutes les valeurs dans le tampon de l’indicateur. Lors du prochain appel, nous n’aurons pas à calculer l’ensemble du tampon - seule la dernière valeur sera calculée. Écrivons-le comme ceci :

//--- if it is the first call 
   if(prev_calculated==0)
     {
      //--- set zero values to zero indexes
      MTMBuffer[0]=0.0;
      AbsMTMBuffer[0]=0.0;
     }
//--- calculate values of mtm and |mtm|
   int start;
   if(prev_calculated==0) start=1;  // start filling out MTMBuffer[] and AbsMTMBuffer[] from the 1st index 
   else start=prev_calculated-1;    // set start equal to the last index in the arrays 
   for(int i=start;i<rates_total;i++)
     {
      MTMBuffer[i]=price[i]-price[i-1];
      AbsMTMBuffer[i]=fabs(MTMBuffer[i]);
     }

Les blocs de calcul de EMA_MTMBuffer[], EMA_AbsMTMBuffer[], EMA2_MTMBuffer[] et EMA2_AbsMTMBuffer[] ne nécessitent pas d’optimisation des calculs, car ExponentialMAOnBuffer() est déjà écrit de manière optimale. Nous devons optimiser uniquement le calcul des valeurs pour le tableau TSIBuffer[]. Nous utilisons la même méthode que celle utilisée pour MTMBuffer[].

//--- now calculate the indicator values
   if(prev_calculated==0) start=r+s-1; // set the starting index for input arrays
   for(int i=start;i<rates_total;i++)
     {
      TSIBuffer[i]=100*EMA2_MTMBuffer[i]/EMA2_AbsMTMBuffer[i];
     }
//--- return value of prev_calculated for next call
   return(rates_total);

La dernière remarque pour la procédure d’optimisation : OnCalculate() renvoie la valeur de rates_total. Il s’agit du nombre d’éléments dans le tableau d’entrée price[] qui est utilisé pour les calculs d’indicateurs.

La valeur renvoyée par OnCalculate() est enregistrée dans la mémoire du terminal et, lors de l’appel suivant de OnCalculate(), elle est transmise à la fonction en tant que valeur du paramètre d’entrée prev_calculated.

Cela permet de toujours connaître la taille du tableau d’entrée lors de l’appel précédent de OnCalculate() et de commencer le calcul des tampons d’indicateurs à partir d’un indice correct sans recalculs inutiles.

Vérification des données d’entrée

Il y a encore une chose que nous devons faire pour que OnCalculate() fonctionne parfaitement. Ajoutons la vérification du tableau price[], sur lequel les valeurs des indicateurs sont calculées. Si la taille du tableau (rates_total) est trop petite, aucun calcul n’est nécessaire - nous devons attendre le prochain appel de OnCalculate(), lorsque les données sont suffisantes.

//--- if the size of price[] is too small
  if(rates_total<r+s) return(0); // do not calculate or draw anything
//--- if it's the first call 
   if(prev_calculated==0)
     {
      //--- set zero values for zero indexes
      MTMBuffer[0]=0.0;
      AbsMTMBuffer[0]=0.0;
     }

Étant donné que le lissage exponentiel est utilisé deux fois séquentiellement pour calculer l’indice de force réelle, la taille du prix[] doit être au moins égale ou supérieure à la somme des périodes r et s ; sinon, l’exécution est terminée et OnCalculate() renvoie 0. La valeur zéro renvoyée signifie que l’indicateur ne sera pas tracé dans le graphique, car ses valeurs ne sont pas calculées.

Configuration de la représentation

En ce qui concerne l’exactitude des calculs, l’indicateur est prêt à l’emploi. Mais si nous l’appelons à partir d’un autre programme mql5, il sera construit par les prix close par défaut. Nous pouvons spécifier un autre type de prix par défaut - spécifiez une valeur de l’énumération ENUM_APPLIED_PRICE dans la propriété indicator_applied_price de l’indicateur. 

Par exemple, afin de définir un prix typique ( (high+low+close)/3) pour un prix, écrivons ce qui suit :

#property indicator_applied_price PRICE_TYPICAL


Si nous prévoyons d’utiliser uniquement ses valeurs à l’aide des fonctions iCustom() ou IndicatorCreate(), aucun autre raffinement n’est nécessaire. Mais s’ils sont utilisés directement, c’est-à-dire tracés dans le graphique, des paramètres supplémentaires sont recommandés :

  • numéro de barre, à partir duquel un indicateur est tracé ;
  • Étiquette pour les valeurs dans TSIBuffer[], qui sera reflétée dans DataWindow ;
  • nom court de l’indicateur, affiché dans une fenêtre séparée et dans l’aide contextuelle lorsque vous pointez le curseur de la souris sur la ligne de l’indicateur ;
  • nombre de chiffres après la virgule décimale indiquée dans les valeurs de l’indicateur (cela n’affecte pas la précision).

Ces paramètres peuvent être réglés dans le gestionnaire OnInit(), à l’aide des fonctions du groupe Indicateurs personnalisés. Ajoutez de nouvelles lignes et enregistrez l’indicateur sous True_Strength_Index_ver2.mq5.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,TSIBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,MTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,AbsMTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(3,EMA_MTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(4,EMA2_MTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(5,EMA_AbsMTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(6,EMA2_AbsMTMBuffer,INDICATOR_CALCULATIONS);
//--- bar, starting from which the indicator is drawn
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,r+s-1);
   string shortname;
   StringConcatenate(shortname,"TSI(",r,",",s,")");
//--- set a label do display in DataWindow
   PlotIndexSetString(0,PLOT_LABEL,shortname);   
//--- set a name to show in a separate sub-window or a pop-up help
   IndicatorSetString(INDICATOR_SHORTNAME,shortname);
//--- set accuracy of displaying the indicator values
   IndicatorSetInteger(INDICATOR_DIGITS,2);
//---
   return(0);
  }

Si nous commençons les deux versions de l’indicateur et faisons défiler le graphique jusqu’au début, nous verrons toutes les différences.


La deuxième version de l’indicateur True Strength Index est meilleure

Conclusion

Sur la base de l’exemple de création de l’indicateur True Strength Index, nous pouvons décrire les moments de base dans le processus d’écriture de n’importe quel indicateur dans MQL5 :

  • Pour créer votre propre indicateur personnalisé, utilisez l’Assistant MQL5 qui vous aidera à effectuer des opérations de routine préliminaires sur la configuration de l’indicateur. Sélectionnez la variante nécessaire de la fonction OnCalculate().
  • Si nécessaire, ajoutez d’autres tableaux pour les calculs intermédiaires et liez-les avec les tampons d’indicateurs correspondants à l’aide de la fonction SetIndexBuffer(). Indiquez le type INDICATOR_CALCULATIONS pour ces tampons.
  • Optimisez les calculs dans OnCalculate(), car cette fonction sera appelée chaque fois que les données de prix changent. Utilisez des fonctions déboguées prêtes à l’emploi pour faciliter l’écriture de code et pour une meilleure lisibilité.
  • Effectuez un réglage visuel supplémentaire de l’indicateur, pour rendre le programme facile à utiliser à la fois pour les autres programmes mql5 et par les utilisateurs.

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

Appliquer un indicateur à un autre Appliquer un indicateur à un autre
Lors de l'écriture d'un indicateur qui utilise la forme abrégée de l'appel de fonction OnCalculate(), vous pourriez manquer le fait qu'un indicateur peut être calculé non seulement par les données de prix, mais également par les données d'un autre indicateur (qu'il s'agisse du type intégré ou personnalisé). Vous souhaitez améliorer un indicateur pour sa bonne application aux données de l'autre indicateur ? Dans cet article, nous passerons en revue toutes les étapes requises pour une telle modification.
Embarquement sur de nouveaux rails : Indicateurs personnalisés dans MQL5 Embarquement sur de nouveaux rails : Indicateurs personnalisés dans MQL5
Je ne vais pas énumérer toutes les nouvelles possibilités et fonctionnalités du nouveau terminal et du nouveau langage. Elles sont nombreuses, et certaines nouveautés méritent d'être discutées dans un article séparé. De plus, il n'y a aucun code d’écrit avec une programmation orientée objet, c'est un sujet trop sérieux pour être simplement mentionné dans un contexte comme des avantages supplémentaires pour les développeurs. Dans cet article, nous examinerons les indicateurs, leur structure, leur dessin, leurs types et leurs détails de programmation, par rapport à MQL4. J'espère que cet article sera utile aussi bien aux débutants qu'aux développeurs expérimentés, peut-être que certains d'entre eux trouveront quelques éléments d’apprentissage.
Limitations et vérifications dans Expert Advisors Limitations et vérifications dans Expert Advisors
Est-il permis d’échanger ce symbole lundi ? Y a-t-il assez d’argent pour ouvrir une position ? Quelle est l’ampleur de la perte si le Stop Loss se déclenche ? Comment limiter le nombre d’ordres en attente ? L’opération de trade a-t-elle été exécutée à la barre actuelle ou à la barre précédente ? Si un robot de trading ne peut pas effectuer ce type de vérifications, toute stratégie de trade risque de se transformer en une stratégie de perte. Cet article présente les exemples de vérifications utiles dans n’importe quel Expert Advisor.
Voici les nouveaux MetaTrader 5 et MQL5 Voici les nouveaux MetaTrader 5 et MQL5
Ceci n'est qu'un bref aperçu de MetaTrader 5. Je ne peux pas décrire toutes les nouvelles fonctionnalités du système sur une période aussi courte - les tests ont commencé le 09.09.2009. C'est une date symbolique, et je suis sûr que ce sera un chiffre porte-bonheur. Quelques jours se sont écoulés depuis que j'ai obtenu la version bêta du terminal MetaTrader 5 et MQL5. Je n'ai pas réussi à essayer toutes ses fonctionnalités, mais je suis déjà impressionné.