Création d'un indicateur avec plusieurs tampons d'indicateurs pour les débutants
Introduction
Dans mes articles précédents «Indicateurs personnalisés dans MQL5 pour les débutants» et «Implémentation Pratique des Fichiers Numériques dans MQL5 pour lesDébutants», je me suis concentré en détail sur la structure de l’indicateur avec un tampon d’indicateur.
Évidemment, une telle méthode peut être largement appliquée pour écrire des indicateurs personnalisés, mais la vie réelle peut à peine se limiter à leur utilisation, et il est donc temps d’aborder des méthodes plus complexes de construction du code de l’indicateur. Heureusement, les capacités de MQL5 sont vraiment inépuisables et ne sont limitées que par la RAM de nos PC.
L’indicateur Aroon comme exemple de doublement de code
La formule de cet indicateur contient deux composantes: les indicateurs haussiers et baissiers, qui sont tracés dans une fenêtre graphique distincte:
TAUREAUX = (1 - (bar - SHIFT(MAX(HIGH(), AroonPeriod)))/AroonPeriod) * 100
OURS = (1 - (bar - SHIFT(MIN (LOW (), AroonPeriod)))/AroonPeriod) * 100
Avec :
- BULLS - la force du taureau;
- OURS - la force de l’ours;
- SHIFT() - fonction de détermination de la position de l’indice de la barre;
- MAX() - fonction de recherche du maximum sur la période AroonPeriod;
- MIN() - fonction de recherche du minimum sur la période AroonPeriod;
- HIGH() et LOW() - les tableaux de prix pertinents;
Dès les formules de l’indicateur, nous pouvons conclure que pour construire un indicateur, nous ne devons avoir que deux tampons d’indicateurs, la structure de l’indicateur différera très peu de la structure du SMA_1.mq5, considéré dans l’article précédent.
Pratiquement, il s’agit simplement du même code dupliqué, avec différents nombres de tampons d’indicateurs. Ouvrons donc le code de cet indicateur dans le MetaEditor et enregistrons-le sous Aroon.mq5. Maintenant, dans les 11 premières lignes du code, qui se rapportent au droit d’auteur et à son numéro de version, nous allons uniquement remplacer le nom de l’indicateur:
//+------------------------------------------------------------------+ //| Aroon.mq5 | //| Copyright 2010, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ //---- copyright #property copyright "2010, MetaQuotes Software Corp." //---- link to the author's site #property link "http://www.mql5.com" //---- version number #property version "1.00"
Ensuite, dans la 12ème ligne de code, nous devons modifier le tracé de l’indicateur de la fenêtre de graphique de base à la fenêtre séparée:
//---- plot indicator in the separate window #property indicator_separate_window
Étant donné que cet indicateur dispose d’ une plage de valeurs complètement différente, son tracé sera effectué dans une fenêtre séparée.
Après cela, dans les 4 lignes suivantes du code (les propriétés générales de l’indicateur), nous modifions le nombre de tampons d’indicateur utilisés à deux:
//---- two buffers are used #property indicator_buffers 2 //---- two plots are used #property indicator_plots 2
Les 10 lignes de code suivantes sont liées au traçage de l’indicateur à partir d’un tampon d’indicateur spécifique, son étiquette doit être dupliquée, après quoi, nous devons remplacer tous les index de 1 à 2. Nous devons également modifier toutes les étiquettes des tampons d’indicateurs:
//+----------------------------------------------+ //| bullish strength indicator parameters | //+----------------------------------------------+ //---- drawing style = line #property indicator_type1 DRAW_LINE //---- drawing color = Lime #property indicator_color1 Lime //---- line style = solid line #property indicator_style1 STYLE_SOLID //---- line width = 1 #property indicator_width1 1 //---- label of the BullsAroon indicator #property indicator_label1 "BullsAroon" //+----------------------------------------------+ //| bearish strength indicator parameters | //+----------------------------------------------+ //---- drawing style = line #property indicator_type2 DRAW_LINE //---- drawing color = Red #property indicator_color2 Red //---- line style = solid line #property indicator_style2 STYLE_SOLID //---- line width = 1 #property indicator_width2 1 //---- label of the BearsAroon indicator #property indicator_label2 "BearsAroon"
Cet indicateur utilise trois niveaux horizontaux avec les valeurs de 30, 50 et 70.
Afin de tracer ces niveaux, nous devons ajouter cinq lignes de code supplémentaires au code de l’indicateur.
//+----------------------------------------------+ //| Horizontal levels | //+----------------------------------------------+ #property indicator_level1 70.0 #property indicator_level2 50.0 #property indicator_level3 30.0 #property indicator_levelcolor Gray #property indicator_levelstyle STYLE_DASHDOTDOT
Pour les paramètres d’entrée de l’indicateur, par rapport à l’indicateur précédent, tout reste le même, à l’exception de légères modifications dans les titres:
//+----------------------------------------------+ //| Indicator input parameters | //+----------------------------------------------+ input int AroonPeriod = 9; // Period input int AroonShift = 0; // Horizontal shift of the indicator in bars
Maintenant, cependant, il y aura deux tableaux, qui seront utilisés comme tampons d’indicateurs, et ils auront des noms appropriés:
//--- declare the dynamic arrays used further as indicator buffers double BullsAroonBuffer[]; double BearsAroonBuffer[];
Nous procédons dans une toute même affaire avec le code de la fonction OnInit().
Tout d’abord, nous modifions les lignes de code du zéroième tampon:
//--- set BullsAroonBuffer dynamic array as indicator buffer SetIndexBuffer(0, BullsAroonBuffer, INDICATOR_DATA); //--- horizontal shift (AroonShift) of the indicator 1 PlotIndexSetInteger(0, PLOT_SHIFT, AroonShift); //--- plot draw begin (AroonPeriod) of the indicator 1 PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, AroonPeriod); //--- label shown in DataWindow PlotIndexSetString(0, PLOT_LABEL, "BearsAroon");
Après cela, copiez le code entier dans le presse-papiers Windows et collez-le juste après le même code.
Ensuite, dans le code collé, nous modifions le numéro du tampon d’indicateur de 0 à 1, modifions le nom du tableau d’indicateurs et l’étiquette de l’indicateur:
//--- set BearsAroonBuffer dynamic array as indicator buffer SetIndexBuffer(1, BearsAroonBuffer, INDICATOR_DATA); //--- horizontal shift (AroonShift) of the indicator 2 PlotIndexSetInteger(1, PLOT_SHIFT, AroonShift); //--- plot draw begin (AroonPeriod) of the indicator 2 PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, AroonPeriod); //--- label shown in DataWindow PlotIndexSetString(1, PLOT_LABEL, "BullsAroon");
Le nom abrégé de l’indicateur a également subi de légères modifications :
//--- initialization of the variable for a short indicator name string shortname; StringConcatenate(shortname, "Aroon(", AroonPeriod, ", ", AroonShift, ")");
Maintenant, examinons la précision du traçage de l’indicateur. La plage réelle de l’indicateur est comprise entre 0 et 100, et cette plage est affichée tout le temps.
Dans cette situation, il est tout à fait possible d’utiliser uniquement les valeurs entières de l’indicateur, tracées sur le graphique. Pour cette raison, nous utilisons 0 pour les nombres après la virgule, pour le tracé de l’indicateur:
//--- set accuracy of drawing of indicator values IndicatorSetInteger(INDICATOR_DIGITS, 0);
Dans l’indicateur SMA_1.mq5, nous avons utilisé la première forme de l’appel de fonction OnCalculate().
Il ne convient pas à l’indicateur Aroon, en raison de son absence de tableaux de prix élevés et bas. Ces tableaux sont disponibles dans la deuxième forme d’appel de cette fonction. Et, par conséquent, il est nécessaire de modifier l’en-tête de la fonction:
int OnCalculate( const int rates_total, // total bars on the current tick const int prev_calculated,// total bars on the previous tick const datetime& time[], const double& open[], const double& high[], // price array of the maximum prices for the indicator calculations const double& low[], // price array of the minimum prices for the indicator calculations const double& close[], const long& tick_volume[], const long& volume[], const int& spread[] )
Après cette modification, l’utilisation du paramètre begin a perdu tout son sens, il doit donc être supprimé du code!
Le code de calcul des limites des modifications de variables du cycle de fonctionnement, la vérification des données pour la suffisance du calcul, est pratiquement resté inchangé.
//--- checking the number of bars if (rates_total < AroonPeriod - 1) return(0); //--- declare the local variables int first, bar; double BULLS, BEARS; //--- calculation of the first (staring index) for the main loop if (prev_calculated == 0) // checking for the first call of the OnCalculate function first = AroonPeriod - 1; // starting index for calculating all of the bars else first = prev_calculated - 1; // starting index for calculating new bars
Cependant, certains problèmes surgissent avec les algorithmes de calcul des valeurs des indicateurs. Le problème est que MQL5 ne dispose pas des fonctions intégrées pour déterminer les indices du maximum et du minimum, pour la période à partir de la barre actuelle, dans la direction de l’indice décroissant.
Une façon de sortir de cette situation est d’écrire ces fonctions nous-mêmes. Heureusement, de telles fonctions existent déjà dans l’indicateur ZigZag.mq5 dans le dossier se trouvant dans « MetaTrader5\MQL5\Indicators\Examples ».
Le moyen le plus simple de s’en sortir - est de sélectionner le code de ces fonctions dans l’indicateur ZigZag.mq5, de les copier dans le presse-papiers Windows et de les coller dans notre code, par exemple, juste après la description de la fonction OnInit(), au niveau global:
//+------------------------------------------------------------------+ //| searching index of the highest bar | //+------------------------------------------------------------------+ int iHighest(const double &array[], // array for searching for the index of the maximum element int count, // number of the elements in the array (in the decreasing order), int startPos // starting index ) { //---+ int index = startPos; //---- checking the starting index if (startPos < 0) { Print("Incorrect value in the function iHighest, startPos = ", startPos); return (0); } //---- checking the startPos values if (startPos - count < 0) count = startPos; double max = array[startPos]; //---- index search for(int i = startPos; i > startPos - count; i--) { if(array[i] > max) { index = i; max = array[i]; } } //---+ return of the index of the largest bar return(index); } //+------------------------------------------------------------------+ //| searching index of the lowest bar | //+------------------------------------------------------------------+ int iLowest( const double &array[], // array for searching for the index of the maximum element int count, // number of the elements in the array (in the decreasing order), int startPos // starting index ) { //---+ int index = startPos; //--- checking the stating index if (startPos < 0) { Print("Incorrect value in the iLowest function, startPos = ",startPos); return(0); } //--- checking the startPos value if (startPos - count < 0) count = startPos; double min = array[startPos]; //--- index search for(int i = startPos; i > startPos - count; i--) { if (array[i] < min) { index = i; min = array[i]; } } //---+ return of the index of the smallest bar return(index); }
Après cela, le code de la fonction OnCalculate() sera le suivant :
//+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate( const int rates_total, // total number of bars on the current tick const int prev_calculated,// number of calculated bars on the previous tick const datetime& time[], const double& open[], const double& high[], // price array for the maximum price for the indicator calculation const double& low[], // price array for the minimum price for the indicator calculation const double& close[], const long& tick_volume[], const long& volume[], const int& spread[] ) { //---+ //--- checking the number of bars if (rates_total < AroonPeriod - 1) return(0); //--- declare the local variables int first, bar; double BULLS, BEARS; //--- calculation of the starting bar number if (prev_calculated == 0) // checking for the first start of the indicator calculation first = AroonPeriod - 1; // starting number for the calculation of all of the bars else first = prev_calculated - 1; // starting number for the calculation of new bars //--- main loop for(bar = first; bar < rates_total; bar++) { //--- calculation of values BULLS = 100 - (bar - iHighest(high, AroonPeriod, bar) + 0.5) * 100 / AroonPeriod; BEARS = 100 - (bar - iLowest (low, AroonPeriod, bar) + 0.5) * 100 / AroonPeriod; //--- filling the indicator buffers with the calculated values BullsAroonBuffer[bar] = BULLS; BearsAroonBuffer[bar] = BEARS; } //---+ return(rates_total); } //+------------------------------------------------------------------+
Pour la symétrie des axes, j’ai légèrement corrigé dans le code, en ajoutant le décalage vertical de l’indicateur, par rapport à l’indicateur d’origine, en utilisant la valeur de 0,5.
Voici les résultats des travaux de cet indicateur sur le graphique :
Pour trouver la position de l’élément avec les valeurs maximales ou minimales sur une distance ne dépassant pas AroonPeriod de la barre actuelle, nous pouvons utiliser les fonctions ArrayMaximum() et ArrayMinimum() intégrées de MQL5, qui recherchent également les extremums, mais ces fonctions effectuent la recherche en utilisant l’ordre croissant.
Cependant, la recherche doit être menée dans l’ordre décroissant des index. Dans ce cas, la solution la plus simple consiste à modifier la direction de l’indexation dans les tampons d’indicateur et de prix, à l’aide de la fonction ArraySetAsSeries().
Mais nous devons également modifier la direction de l’ordre des barres dans la boucle de calcul et modifier l’algorithme du premier calcul de variable.
Dans ce cas, la fonction OnCalculate() résultante ressemblera à ceci :
//+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate( const int rates_total, // total number of bars on the current tick const int prev_calculated,// number of calculated bars on the previous tick const datetime& time[], const double& open[], const double& high[], // price array for the maximum price for the indicator calculation const double& low[], // price array for the minimum price for the indicator calculation const double& close[], const long& tick_volume[], const long& volume[], const int& spread[] ) { //---+ //--- checking the number of bars if (rates_total < AroonPeriod - 1) return(0); //--- set indexation as timeseries ArraySetAsSeries(high, true); ArraySetAsSeries(low, true); ArraySetAsSeries(BullsAroonBuffer, true); ArraySetAsSeries(BearsAroonBuffer, true); //--- declare the local variables int limit, bar; double BULLS, BEARS; //--- calculation of the starting bar index if (prev_calculated == 0) // check for the first call of OnCalculate function limit = rates_total - AroonPeriod - 1; // starting index for the calculation of all of the bars else limit = rates_total - prev_calculated; // starting index for the calculation of new bars //--- main loop for(bar = limit; bar >= 0; bar--) { //--- calculation of the indicator values BULLS = 100 + (bar - ArrayMaximum(high, bar, AroonPeriod) - 0.5) * 100 / AroonPeriod; BEARS = 100 + (bar - ArrayMinimum(low, bar, AroonPeriod) - 0.5) * 100 / AroonPeriod; //--- filling the indicator buffers with the calculated values BullsAroonBuffer[bar] = BULLS; BearsAroonBuffer[bar] = BEARS; } //----+ return(rates_total); } //+------------------------------------------------------------------+
J’ai modifié le nom de la variable « first » en « limit », c’est plus approprié dans ce cas.
Dans ce cas, le code de la boucle principale est similaire à celui qui a été fait dans MQL4. Ainsi, ce style d’écriture de la fonction OnCalculate() peut être utilisé pour la conversion d’indicateurs de MQL4 en MQL5 avec un minimum de modifications du code.
Conclusion
Alors, c’est fait! L’indicateur est rédigé, et même en deux versions.
Pour un cas de la bonne façon conservatrice et intelligente de résoudre de tels problèmes, les solutions s’avèrent légèrement plus compliquées que la construction d’un jouet utilisant le constructeur Lego pour enfants.
Traduit du russe par MetaQuotes Ltd.
Article original : https://www.mql5.com/ru/articles/48
- 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