MQL5 : Créez votre propre indicateur
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.
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.
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.
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 :
- pour les valeurs mtm - tableau MTMBuffer[] ;
- pour les valeurs |mtm| - tableau AbsMTMBuffer[] ;
- pour EMA(mtm,r) - tableau EMA_MTMBuffer[] ;
- pour EMA(EMA(mtm,r),s) - tableau EMA2_MTMBuffer[] ;
- pour EMA(|mtm|,r) - tableau EMA_AbsMTMBuffer[] ;
- 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 !
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.
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
- Applications de trading gratuites
- Plus de 8 000 signaux à copier
- Actualités économiques pour explorer les marchés financiers
Vous acceptez la politique du site Web et les conditions d'utilisation