Les indicateurs personnels en MQL5 – partie 1


Depuis la sortie Beta de Metatrader 5, nous pouvons commencer à tester petit à petit les nouvelles fonctionnalités. Le but de cet article n’est pas de voir tout ce qui a changé entre MQL4 et MQL5, mais seulement de partir sur un exemple particulier: celui des indicateurs personnels. Nous allons donc laisser de coté la programmation orientée objet qui nécessitera plus qu’un simple article. Cet article se veut plus particulièrement à destination de ceux qui ont une certaine expérience de la programmation MQL4 et souhaitent prendre connaissance des nouveautés et différences de la programmation d’indicateur entre MQL4 et MQL5. Etant donné sa taille, l’article est séparé en plusieurs parties.

Source : Step On New rails : Custom indicators in MQL5

I La structure générale

La structure générale des indicateurs n’a pas changé par rapport à MQL4. Comme auparavant, il y a 3 fonctions : pour l’initialisation, le traitement des données et la fermeture.

De la même manière que précédemment, beaucoup de propriétés des indicateurs peuvent être définies avec le mot clé #property. Les propriétés et les paramètres d’entrée sont comme autrefois définies dans un contexte global.

Prenons comme exemple l’implémentation de l’indicateur coloré RSI. Voici la version tronquée dont la versions entière peut se trouver dans le fichier Color_RSI.mq5 disponible sur l’article original.

Voyons les diverses parties du code :

{xtypo_code}//+——————————————————————+
//|                                                    Color_RSI.mq5 |
//+——————————————————————+

// information properties
#property copyright “TheXpert”
#property link      “theforexpert@gmail.com”
#property version   “1.00”

// Indicator description — the total length should not exceed 511 characters with CR symbols

#property description “Indicator programming demo in MQL5”
#property description “RSI indicator custom painting”{/xtypo_code}

 

Les propriétés spécifiées dans le code sont aussi accessibles via le le panel d’information de l’indicateur (l’onglet “common” de la table de propriétés). Cela ressemble à cela :

 

 

 

Ces propriétés sont celles des indicateurs classiques. Les autres peuvent être trouvées dans l’aide.

{xtypo_code}// the indicator properties
#property indicator_separate_window // indicator will be displayed in the separate subwindow

//#property indicator_minimum 0
//#property indicator_maximum 100

#property indicator_buffers 2 // buffers used
#property indicator_plots 1 // buffers displayed

#property indicator_color1 DarkSalmon, DeepSkyBlue // we use 2 colors
#property indicator_type1 DRAW_COLOR_LINE // and special color style{/xtypo_code}

 

Voici les paramètres d’entrée de l’indicateur (le mot clé input remplace le mot clé extern) et les variables golbales (à ne pas confondre avec les variables globales du terminal client). Les paramètres d’entrée sont donc spécifiés par le mot clé input.

Désormais il est possible de créer des énumérations pour les paramètres d’entrée ce qui est utile pour empêcher l’utilisateur de rentrer des données incorrectes.

Par exemple, le paramètre appelé AppliedPrice sera affiché dans une liste déroulante proposant les différentes valeurs possibles.

 

Par exemple, l’énumération suivante :

{xtypo_code}//…
enum DayOfWeek
{
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
};

input DayOfWeek Day;

//…{/xtypo_code}

 

sera affichée de la manière suivante :

 

{xtypo_code}int OnInit()
{

// set the indicator buffers
// set Values as a buffer for displaying
SetIndexBuffer(0, Values, INDICATOR_DATA);
// set ValuesPainting as buffer for colors
SetIndexBuffer(1, ValuesPainting, INDICATOR_COLOR_INDEX);

// Set beginning of Values buffer drawing
PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, RSIPeriod);
// Set indicator name
IndicatorSetString(INDICATOR_SHORTNAME, “Color RSI(” + string(RSIPeriod) + “)”);
// Set empty value for Values buffer
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
// Set colors for the buffer
PlotIndexSetInteger(0, PLOT_LINE_COLOR, 0, Down);
PlotIndexSetInteger(0, PLOT_LINE_COLOR, 1, Up);

RSIHandle = iRSI(NULL, 0, RSIPeriod, AppliedPrice);

ArrayResize(BufferForCopy, 3);

// Set the indexation order for buffers (as series)
ArraySetAsSeries(Values, true);
ArraySetAsSeries(ValuesPainting, true);
ArraySetAsSeries(BufferForCopy, true);

return(0);
}{/xtypo_code}


OnInit est la fonction d’initialisation de l’indicateur. Ici on configure les buffers et leurs propriétés ainsi que les variables qui ne peuvent être définies dans les propriétés générales ou qui doivent être allouées dynamiquement. Il y a aussi une initialisation des données initiales, incluant l’assignement des “handle” qui sont nécessaires aux indicateurs.

{xtypo_code}// Function for data calculation
// note that the function parameters can be renamed
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[])
{
int toCount = (int)MathMin(rates_total, rates_total – prev_calculated + 1);

if (prev_calculated < 0 || prev_calculated > rates_total)
{
toCount = rates_total;
}

int copied = CopyBuffer(RSIHandle, 0, 0, toCount, Values);
if (copied == -1)
{
Print(“Error while data copying. Error ?”, GetLastError());
return 0;
}

// Coloring. Yes, now it became so simple
for (int i = toCount – 2; i >= 0; –i)
{

if (Values[i + 1] != EMPTY_VALUE &&
Values[i] > Values[i + 1])   ValuesPainting[i] = 1;
else                             ValuesPainting[i] = 0;
}

return rates_total;
}{/xtypo_code}

 

OnCalculate est la fonction qui traite et calcule les données. Cette fonction peut être de deux types. Ici nous avons la forme standard. Les détails sont ci-dessous.

Fonction:

{xtypo_code}// the function is not obligatory in a code
/*
void
OnDeinit()
{}
*/{/xtypo_code}


OnDeinit est la fonction de fermeture de l’indicateur. Souvent il est nécessaire de libérer les ressources comme par exemple les “handles” vers des fichiers.

 

II Deux concepts d’indicateurs

Le premier est le standard, c’est à dire celui que nous connaissions de MQL4, avec seulement une petite différence. C’est la fonction OnCalculate qui est appelée en lieu et place de la fonction Start. Pour la forme standard, cela ressemble à :

{xtypo_code}int OnCalculate(const int rates_total, // Arrays size
const int prev_calculated, // Bars processed on the previous call
const datetime& time[], // Data for the current chart and timeframe
const double& open[],
const double& high[],
const double& low[],
const double& close[],
const long& tick_volume[],
const long& volume[],
const int& spread[])
{
return rates_total;
}{/xtypo_code}

 

Afin de réduire la quantité de code nécessaire à la copie de données, les données du graphique sont passées directement en tant que tableau dans les paramètres de la fonction. En outre, le nombre de bougies disponibles est passé en premier paramètre et le nombre de bougies traitées après le dernier appel (ou 0) est le second paramètre.

La valeur 0 peut être passée au premier appel de l’indicateur, ainsi que lorsque de nouvelles valeurs sont chargées ou en cas de manque de données. Ce paramètre est un remplacement (alternative ou équivalent, à vous d’en juger) de la fonction IndicatorCounted() qui était pratique pour de nombreux développeurs.

Le second concept est le remplacement et l’expansion des fonctions de type  i<…>OnArray de MQL4. Il y a un indicateur de ce type dans l’exemple forunir mar Metaquotes “Custom Moving Average”. Ce type d’indicateurs est destiné au traitement des données dépendant des choix de l’utilisateur, incluant donc les indicateurs personnels.

La fonction pour le traitement des données des indicateurs de ce type est la suivante :

{xtypo_code}int OnCalculate (const int rates_total, // the size of the price[] array
const int prev_calculated, // bars calculated in the previous call
const int begin, // where notional data start from
const double& price[] // data array for calculation
);
{
return rates_total;
}{/xtypo_code}

Le dernier paramètre de la fonction correspond aux données sélectionnées par l’utilisateur pour traitement. Si vous souhaitez réaliser un inidcateur avec de nombreux buffers, le premier buffer sera passé pour le traitement des données.

 

 

La valeur First Indicator’s Data de l’énumération signifie que l’indicateur sera appliqué sur le premier indicateur attaché à la fenêtre sélectionnée du graphique.

La valeur Previous Indicator’s Data signifie que l’indicateur sera appliqué sur le dernier indicateur attaché à la fenêtre sélectionnée du graphique.

Ces indicateurs peuvent être utilisés pour assembler des piles entières. Par exemple, l’indicateur Custom Moving Average a la possibilité de réaliser un triple lissage des cours en appliquant le premier indicateur sur les données du graphique, le second sur le premier et le troisième sur le second :

Il y a de nombreux indicateurs standards qui mettent en oeuvre ce concept particulier. C’est pourquoi, lorsque vous apercevez la demande de paramètre applied_price_or_handle :

cela signifie que l’indicateur en question peut traiter les données de l’utilisateur. Le handle de ces données doit être passée en paramètre applied_price_or_handle.

En utilisant la même méthode il est possible d’organiser le traitement des données directement dans le code de l’indicateur :

{xtypo_code}{
// …
RSIHandle = iRSI(NULL, 0, RSIPeriod, AppliedPrice);
SmoothHandle = iMA(NULL, 0, SmoothPeriod, 0, MODE_EMA, RSIHandle);
// …
}{/xtypo_code}

 

Il y a  une nouvelle application de ce concept : la possibilité d’écrire des indicateurs en tant que service unniversel. Un exemple d’un tel type est attaché dans le fichier Direction_Brush.mq5.

 

les résultats sont présentés dans le graphique ci dessus. La coloration de la direction est dans ce cas séparé comme une entité indépendante et implémentée dans un autre indicateur.

Leur universalité est certainement limitée dans la mesure où ils ne sont applicables seulement sur le buffer 0 de l’indicateur sur lequel ils sont attachés. Toutefois je pense qe ceci restera très utile.

Par conséquent, lorsque vous écrivez un indicateur personnel, vous devriez désormais le prendre en compte en mettant les données principales de l’indicateur dans le buffer 0 afin de le rendre compatible avec les services universels et vous permettre d’une certaine manière de ne plus avoir besoin de les recoder dans chaque indicateur. Outre les traitements propres de l’indicateur, la plupart des opérations externes pourront être réalisées les indicateurs universels.

L’étendue des applications n’est pas si faible que ce qu’il peut paraître :

  • colorier les caractéristiques des indicateurs (tops, directions, lniveaux, segments, etc.);
  • différent signaux dans différentes conditions;
  • collecter et afficher des statistiques – par exemple la distribution de données;
  • la construction d’indicateurs universels qui peuvent être calculés pour un buffer comme par exemple les moyennes mobiles, zigzag, etc.

 

Ceci n’est évidemment pas une liste exhaustive de toutes les possibilités mais seulement celles qui me viennent immédiatement à l’esprit. De nombreuses autres mises en oeuvre devraient voir le jour grâce à l’imagination collective de la communauté.

La suite dans la partie 2 de cet article si cela vous intéresse (commentaires…).

 

Traduction et Adaptation: Nicolas Vitale
“MQL5 and Metatrader  are trade marks of MetaQuotes Software Corp. and all related materials are reserved for MetaQuotes”

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>