English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Création d'indicateurs à graduations dans MQL5

Création d'indicateurs à graduations dans MQL5

MetaTrader 5Indicateurs | 22 décembre 2021, 16:23
236 0
Denis Zyatkevich
Denis Zyatkevich

Introduction

En trading, il serait souhaitable d'avoir une information autant que possible, pour voir l'image détaillée des changements de prix. Vous pouvez utiliser le graphique à graduations. Essayons de créer un graphique à graduations dans MQL5.

Cet article décrit la création de deux indicateurs : un graphique des prix à graduations et un graphique « Tick Candles », qui dessine les bougies contenant un nombre spécifié de graduations. Chacun des indicateurs considérés écrit les valeurs de prix reçues dans le fichier de construction des données de l'indicateur après redémarrage du terminal client (ces données peuvent également être utilisées par les autres programmes).

Création d'indicateur à graduations

Écrivons un indicateur dans MQL5, qui dessine des données à graduations sur le graphique. Un exemple d'un tel indicateur est présenté à la Fig. 1 :

Figure 1. Exemple de graphique à graduations

L'indicateur trace deux lignes : Prix d'offre et de demande. Le dessin de chacun d'eux peut être désactivé dans les options de l'indicateur.

L'indicateur enregistre les prix du symbole actuel, reçus du courtier dans un fichier texte au format suivant : Heure du serveur, prix acheteur et prix vendeur :

2010.03.26 19:43:02 1.33955 1.33968

Le nom du fichier correspond au nom de l'instrument financier (par exemple, EURUSD.txt). Les fichiers se trouvent dans le chemin d'accès suivant : MT5_Folder\MQL5\Files. Le répertoire supplémentaire d'un préfixe de fichier et de nom de fichier peut être précisé dans les options de l'indicateur (cela peut être utile s'il y a plusieurs indicateurs rattachés aux graphiques avec le même symbole).

Pour créer un indicateur, lancez le terminal client MetaTrader 5 et lancez MetaQuotes Language Editor en appuyant sur la touche F4. Commençons à écrire le code d'un programme.

Nous préciserons que l'indicateur doit être tracé dans une fenêtre séparée sous le tableau des prix :

// indicator in a separate window
#property indicator_separate_window

Les deux lignes indicatrices (prix Bid et Ask respectivement) doivent être dessinées, nous devons donc utiliser deux tracés graphiques :

// two graphic plots are used: for Bid and Ask lines
#property indicator_plots 2

Nous devons spécifier deux marges d'indicateur, contenant les données à tracer sur le graphique :

// two indicator's buffers
#property indicator_buffers 2

Pour chacune des lignes de l'indicateur, définissons le type de dessin DRAW_LINE (ligne), le style de dessin STYLE_SOLID (ligne continue) et les libellés de texte « Bid » et « Ask » :

// drawing type of a Bid line
#property indicator_type1 DRAW_LINE
// drawing color of a Bid line
#property indicator_color1 Red
// drawing style of a Bid line
#property indicator_style1 STYLE_SOLID
// text label of a Bid line
#property indicator_label1 "Bid"
// drawing type of an Ask line
#property indicator_type2 DRAW_LINE
// drawing color of an Ask line
#property indicator_color2 Blue
// drawing style of an Ask line
#property indicator_style2 STYLE_SOLID
// text label of an Ask line
#property indicator_label2 "Ask"

 Précisons les input variables, dont les valeurs peuvent être modifiées par l'utilisateur dans le menu d'options de l'indicateur.

// the BidLineEnable indicates showing of a Bid line
input bool BidLineEnable=true; // Show Bid Line
// the AskLineEnable indicates showing of an Ask line
input bool AskLineEnable=true; // Show Ask Line
// the path_prefix defines a path and file name prefix
input string path_prefix=""; // FileName Prefix

Les variables BidLineEnable  et AskLineEnable vous permettent d'activer et de désactiver l'affichage des lignes Bid et Ask dans l'indicateur. La variable path_prefix vous permet de spécifier le préfixe du nom de fichier, situé avant le nom de fichier. En utilisant cette variable, vous pouvez également spécifier le chemin d'accès à un sous-répertoire, par exemple, si path_prefix = « MyBroker/test_ », le chemin d'accès des fichiers sera le suivant : « MetaTrader5_Folder\MQL5\Files\MyBroker », pour le symbole « EURUSD » le nom du fichier sera « test_EURUSD.txt ».

Au niveau global, déclarons les variables, qui seront utilisées dans diverses fonctions de l'indicateur, les valeurs de ces variables sont enregistrées entre les appels de l'indicateur :

// the tick_stored variable is a number of served quotes
int ticks_stored;
// the BidBuffer[] and AskBuffer[] arrays - are indicator's buffers
double BidBuffer[],AskBuffer[];

La variable tick_stored sera utilisée pour stocker le nombre de cotations disponibles. Les BidBuffer[] et AskBuffer[]  sont des tableaux dynamiques, utilisés comme marges indicatrices, les données de prix, tracées sur le graphique en tant que lignes Bid et ask, sont stockées dans ces marges.

La fonction OnInit  indique que les tableaux BidBuffer[]  et AskBuffer[]  contiennent les données de traçage. Précisons que les données avec des valeurs de marge indicatrice, égales à zéro, ne doivent pas être tracées sur le graphique.

void OnInit()
  {
   // the BidBuffer[] is an indicator buffer
   SetIndexBuffer(0,BidBuffer,INDICATOR_DATA);
   // the AskBuffer[] is an indicator buffer
   SetIndexBuffer(1,AskBuffer,INDICATOR_DATA);
   // setting EMPTY_VALUE for a Bid line
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0);
   // setting EMPTY_VALUE for an Ask line
   PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0);
  }

Maintenant, nous créons la fonction OnCalculate, et listons tous les paramètres passés à la fonction quand elle a appelé : 

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[])

Déclarons les variables :

// the file_handle variable is a file handle
// the BidPosition and AskPosition - are positions of Bid and Ask prices in the string;
// the line_string_len is a length of a string, read from the file, i is a loop counter;
int file_handle,BidPosition,AskPosition,line_string_len,i;
// the last_price_bid is the last Bid quote
double last_price_bid=SymbolInfoDouble(Symbol(),SYMBOL_BID);
// the last_price_ask is the last Ask quote
double last_price_ask=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
// the filename is a name of a file, the file_buffer is a string, 
// used as a buffer for reading and writing of string data
string filename,file_buffer;

La variable file_handle  d'un type entier sera utilisée pour stocker le descripteur du fichier dans les opérations de fichier, les BidPosition et AskPosition - seront utilisés pour un stockage des positions de départ des prix Bid et Ask dans la chaîne, le line_string_len - sera utilisé pour la longueur de la chaîne, lu à partir du fichier, la variable i  sera utilisée comme compteur de boucles. Les valeurs des derniers prix Bid et Ask reçus sont stockées dans les variables last_price_bid et last_price_ask. La variable de chaîne de nom de fichier est utilisée pour stocker le nom de fichier, le file_buffer est une chaîne utilisée pour lire et écrire sur le fichier.

Le nom de fichier est construit à partir de la variable path_prefix, du nom de l'instrument financier et de l'extension de fichier « .txt ». L'utilisation de la fonction StringConcatenate est plus préférable que la concaténation d'une chaîne en utilisant l'opérateur d'addition, car elle fonctionne plus rapidement et plus économiquement en mémoire.

// File name formation from the path_prefix variable, name
// of financial instrument and ".Txt" symbols
StringConcatenate(filename,path_prefix,Symbol(),".txt");

Nous ouvrons le fichier à l'aide de la fonction FileOpen pour son utilisation ultérieure :

// Opening a file for reading and writing, codepage ANSI, shared reading mode
file_handle=FileOpen(filename,FILE_READ|FILE_WRITE|FILE_ANSI|FILE_SHARE_READ);

Nous utilisons les drapeaux FILE_READ et FILE_WRITE, car nous allons lire et écrire les données sur le fichier, le drapeau FILE_ANSI indique que la page de codes ANSI sera utilisée (la valeur par défaut est Unicode), le drapeau FILE_SHARE_READ signifie que l'accès partagé est autorisé à la lecture par les autres applications tout en travaillant avec elle.

Au premier lancement de l'indicateur, il n'y a aucune donnée (ou la période du graphique a été modifiée) :

 // At first execution of OnCalculate function, we are reading the quotes from a file
 if(prev_calculated==0)
  {
   // Reading the first line from the file and determine the length of a string
   line_string_len=StringLen(FileReadString(file_handle))+2;
   // if file is large (contains more quotes than rates_total/2)
   if(FileSize(file_handle)>(ulong)line_string_len*rates_total/2)
     {
      // Setting file pointer to read the latest rates_total/2 quotes
      FileSeek(file_handle,-line_string_len*rates_total/2,SEEK_END);
      // Moving file pointer to the beginning of the next line
      FileReadString(file_handle);
     }
   // if file size is small
   else
     {
      // Moving file pointer at the beginning of a file
      FileSeek(file_handle,0,SEEK_SET);
     }
   // Reset the counter of stored quotes
   ticks_stored=0;
   // Reading until the end of the file
   while(FileIsEnding(file_handle)==false)
    {
      // Reading a string from the file
      file_buffer=FileReadString(file_handle);
      // Processing of string if its length is larger than 6 characters
      if(StringLen(file_buffer)>6)
        {
         // Finding the start position of Bid price in the line
         BidPosition=StringFind(file_buffer," ",StringFind(file_buffer," ")+1)+1;
         // Finding the start position of Ask price in the line
         AskPosition=StringFind(file_buffer," ",BidPosition)+1;
         // If the Bid line should be plotted, adding this value to BidBuffer[] array
         if(BidLineEnable) 
         BidBuffer[ticks_stored]=StringToDouble(StringSubstr(file_buffer,BidPosition,AskPosition-BidPosition-1));
         // If the Ask line should be plotted, adding this value to AskBuffer[] array
         if(AskLineEnable) 
         AskBuffer[ticks_stored]=StringToDouble(StringSubstr(file_buffer,AskPosition));
         // Increasing the counter of stored quotes
         ticks_stored++;
        }
     }
  }

Nous limiterons le nombre de cotations, qui doivent être lues à partir du fichier par la moitié d'un nombre de barres sur le graphique. D’abord, nous lisons la chaîne du fichier et déterminons sa longueur. À la fin d'une ligne il y a deux caractères supplémentaires avec les codes 10 et 13 (« newline » et « carriage return »), donc nous devons augmenter la longueur de la ligne de 2.

Nous supposons que la longueur moyenne des lignes restantes du fichier est la même. Si la longueur du fichier est supérieure au produit de la longueur d'une ligne sur le nombre de rates_total/2 (c'est-à-dire, si le fichier contient plus de cotations que rates_total/2), nous ne lirons que les dernières cotations rates_total/2. Faites-le, nous plaçons le pointeur de fichier à la distance égale au produit d'une longueur de chaîne par rates_total/2 (à partir de la fin du fichier) et lisons une ligne du fichier pour aligner le pointeur de fichier au début d'une ligne.

Notez que nous comparons deux valeurs en utilisant l'opérateur if, elles comportent des types différents : la longueur du fichier est de type ulong, l'expression sur le côté droit est de type int. Par conséquent, nous effectuons la typographie explicite de l'expression du côté droit sur le type ulong.

Si le fichier contient moins de cotations que rates_total/2, alors nous déplaçons le pointeur du fichier au début du fichier. 

Nous mettons le compteur de cotations à zéro et lisons les lignes d'un fichier, jusqu'à atteindre la fin d'un fichier. Le traitement des chaînes est effectué pour les chaînes dont la longueur est supérieure à six caractères - c'est une longueur de chaîne minimale, qui contient un caractère pour la date, l'heure, l'offre et la demande et des séparateurs entre eux. Nous extrayons les valeurs Bid et Ask d'une chaîne, lisons à partir du fichier si la ligne correspondante doit être tracée et augmentons le compteur de cotations.

Si les données ont déjà été lues, nous déplaçons le pointeur de fichier à la fin du fichier en utilisant la fonction FileSeek (les nouvelles données sont écrites dans le fichier). En utilisant la fonction StringConcatenate, nous générons la chaîne, qui sera écrite dans un fichier à l'aide de la fonction FileWrite. Nous ajoutons les nouvelles valeurs des prix Bid et Ask aux tableaux BidBuffer[] et AskBuffer[], si la ligne correspondante doit être tracée et augmentons le compteur de cotations.

  // If the data have been read before
else
  {
   // Moving file pointer at the end of the file
   FileSeek(file_handle,0,SEEK_END);
   // Forming a string, that should be written to the file
   StringConcatenate(file_buffer,TimeCurrent()," ",DoubleToString(last_price_bid,_Digits)," ",DoubleToString(last_price_ask,_Digits));
   // Writing a string to the file
   FileWrite(file_handle,file_buffer);
   // If the Bid line should be plotted, adding the last Bid price to the BidBuffer[] array
   if(BidLineEnable) BidBuffer[ticks_stored]=last_price_bid;
   // If the Ask line should be plotted, adding the last Ask price to the AskBuffer[] array
   if(AskLineEnable) AskBuffer[ticks_stored]=last_price_ask;
   // Increasing the quotes counter
   ticks_stored++;
  }

On pourrait se demander pourquoi vous ne lisez pas les données d'un fichier à l'intérieur de la fonction OnInit ? La raison est la suivante : la longueur des tableaux dynamiques BidBuffer[] et AskBuffer[]  n'a pas été définie, elle a été spécifiée lors de l'appel de la fonction OnCalculate.

Nous fermons le fichier précédemment ouvert :

// Closing the file
FileClose(file_handle);

Dans le cas où le compteur de cotations sera égal ou supérieur au nombre de barres sur le graphique après la lecture du fichier ou après l'ajout aux tableaux BidBuffer[] et AskBuffer[] la moitié des anciennes cotations seront supprimées et le reste sera expédié où elles appartiennent.

// If number of quotes is more or equal than number of bars in the chart
if(ticks_stored>=rates_total)
  {
   // Removing the first tick_stored/2 quotes and shifting remaining quotes
   for(i=ticks_stored/2;i<ticks_stored;i++)
     {
      // If the Bid line should be plotted, shifting the values of BidBuffer[] array on tick_stored/2
      if(BidLineEnable) BidBuffer[i-ticks_stored/2]=BidBuffer[i];
      // If the Ask line should be plotted, shifting the values of AskBuffer[] array on tick_stored/2
      if(AskLineEnable) AskBuffer[i-ticks_stored/2]=AskBuffer[i];
     }
   // Changing the value of a counter
   ticks_stored-=ticks_stored/2;
  }

Les tableaux BidBuffer[] et AskBuffer[] des marges indicatrices ne sont pas des séries temporelles, donc l'élément récent a un index égal à ticks_stored-1, le graphique récent a un index égal à rates_total-1. Pour les combiner au même niveau, décalons la ligne de l'indicateur à l'aide de la fonction PlotIndexSetInteger:

// Shifting the Bid line to align with the price chart
PlotIndexSetInteger(0,PLOT_SHIFT,rates_total-ticks_stored);
// Shifting the Ask line to align with the price chart
PlotIndexSetInteger(1,PLOT_SHIFT,rates_total-ticks_stored);

Les valeurs des prix récemment reçus sont stockées sur BidBuffer[] et AskBuffer[] avec l’ indice égal à rates_total-1 (si les lignes correspondantes doivent être tracées) pour les afficher dans le coin supérieur gauche de la fenêtre de l’indicateur.

// If the Bid line should be plotted, placing the value to the last element 
// of BidBuffer [] array to show the last Bid price in the indicator's window  
if(BidLineEnable) BidBuffer[rates_total-1]=last_price_bid;
// If the Ask line should be plotted, placing the value to the last element 
// of AskBuffer [] array to show the last Ask price in the indicator's window
if(AskLineEnable) AskBuffer[rates_total-1]=last_price_ask;

L'exécution de la fonction OnCalculate est terminée par le retour de rates_total (vous pouvez retourner n'importe quel nombre, différent de zéro), le code de la fonction se termine par un crochet.

// Return from OnCalculate(), return a value, different from zero   
return(rates_total);
}

L'indicateur Tick a été écrit. Le code source complet de l'indicateur peut être téléchargé sur le lien, situé à la fin de l'article.

Création de l'indicateur « Tick Candles »

Maintenant, écrivons un indicateur qui trace le concept « tick candles ». Contrairement à la carte à bougies classique, où chaque bougie correspond à la période spécifiée, la carte « Tick Candles » a une structure différente : chaque bougie a un nombre prédéfini de traits, reçus du courtier (bougies d'équivolume). Cet indicateur est tel que présenté à la figure 2 :


Figure 2. L'indicateur « Tick Candles »

L'indicateur « Tick Candles », ainsi que l'indicateur à graduations, considéré ci-dessus, écrit toutes les cotations entrantes dans le fichier. Le format des données et les détails de l'emplacement du fichier sont les mêmes. Le chemin du fichier, le préfixe du nom, le nombre de traits pour une bougie et le type de prix (Bid ou Ask) peuvent être spécifiés dans les options de l'indicateur.

Pour créer un indicateur, lancez le terminal client MetaTrader 5 et lancez MetaQuotes Language Editor en appuyant sur la touche F4.

Précisons qu'il doit être tracé dans une fenêtre séparée :

// Indicator is plotted in a separate window
#property indicator_separate_window

L'indicateur n'a qu'un seul tracé graphique : les bougies de couleur.

// One graphic plot is used, color candles
#property indicator_plots 1

Nous avons besoin de quatre marges pour afficher les bougies colorées et pour stocker les valeurs des données de prix (ouvert, haut, bas et clos) des valeurs du prix pour chaque bougie. Nous avons également besoin d'une marge supplémentaire pour stocker les indices de couleur des bougies.

// We need 4 buffers for OHLC prices and one - for the index of color
#property indicator_buffers 5

Précisons le type de dessin : Bougies de couleur - DRAW_COLOR_CANDLES.

// Specifying the drawing type - color candles
#property indicator_type1 DRAW_COLOR_CANDLES

Précisons les couleurs, qui seront utilisées pour les bougies :

// Specifying the colors for the candles
#property indicator_color1 Gray,Red,Green

Créons le price_types du type d'énumérations, contenant l'une des valeurs suivantes : Offrir ou demander :

/ / Declaration of the enumeration
enum price_types
  (
   Bid,
   Ask
  )

Nous spécifions les paramètres d'entrée, qui peuvent être modifiés par l'utilisateur à partir du menu d'options de l'indicateur :

// The ticks_in_candle input variable specifies the number of ticks,
// corresponding to one candle
input int ticks_in_candle=16; //Tick Count in Candles
// The applied_price input variable of price_types type indicates 
// the type of the data, that is used in the indicator: Bid or Ask prices.
input price_types applied_price=0; // Price
// The path_prefix input variable specifies the path and prefix to the file name
input string path_prefix=""; // FileName Prefix

La variable ticks_in_candle spécifie le nombre de traits correspondant à une bougie. La variable applied_price indique le type d’un prix utilisé pour la construction des bougies : Offrir ou demander. Le préfixe de répertoire et de nom de fichier pour les données de traits historiques peut être spécifié dans la variable path_prefix.

Les variables avec des valeurs, qui doivent être enregistrées entre les appels de l'indicateur, sont déclarées au niveau global.

// The ticks_stored variable contains the number of stored quotes
int ticks_stored;
// The TicksBuffer [] array is used to store the incoming prices
// The OpenBuffer [], HighBuffer [], LowBuffer [] and CloseBuffer [] arrays
// are used to store the OHLC prices of the candles
// The ColorIndexBuffer [] array is used to store the index of color candles
double TicksBuffer[],OpenBuffer[],HighBuffer[],LowBuffer[],CloseBuffer[],ColorIndexBuffer[];

La variable ticks_stored est utilisée pour stocker le nombre de cotations disponibles. Le tableau TicksBuffer[] est utilisé pour un stockage des cotations reçues, les tableaux OpenBuffer[], HighBuffer[], LowBuffer[] et CloseBuffer[] sont utilisés pour un stockage des prix des bougies (à l’ouverture, plus haut, plus bas et à la clôture), qui seront tracés sur le graphique. Le tableau ColorIndexBuffer[] est utilisé pour le stockage de l'indice de couleur des bougies.

La fonction OnInit indique que les tableaux OpenBuffer[], HighBuffer[], LowBuffer[] et CloseBuffer[] sont utilisés comme marges indicatrices, le tableau ColorIndexBuffer[] contient un indice de couleur des bougies, le tableau TicksBuffer[] sert aux calculs intermédiaires :

void OnInit()
  {
   // The OpenBuffer[] array is an indicator buffer
   SetIndexBuffer(0,OpenBuffer,INDICATOR_DATA);
   // The HighBuffer[] array is an indicator buffer
   SetIndexBuffer(1,HighBuffer,INDICATOR_DATA);
   // The LowBuffer[] array is an indicator buffer
   SetIndexBuffer(2,LowBuffer,INDICATOR_DATA);
   // The CloseBuffer[] array is an indicator buffer
   SetIndexBuffer(3,CloseBuffer,INDICATOR_DATA);
   // The ColorIndexBuffer[] array is the buffer of the color index
   SetIndexBuffer(4,ColorIndexBuffer,INDICATOR_COLOR_INDEX);
   // The TicksBuffer[] array is used for intermediate calculations
   SetIndexBuffer(5,TicksBuffer,INDICATOR_CALCULATIONS);

La chose suivante est que nous définissons les tableaux OpenBuffer[], HighBuffer[], LowBuffer[], CloseBuffer[] et ColorIndexBuffer[] comme des séries temporelles (c'est-à-dire que les données les plus récentes ont l'indice 0) :

   // The indexation of OpenBuffer[] array as timeseries
   ArraySetAsSeries(OpenBuffer,true);
   // The indexation of HighBuffer[] array as timeseries
   ArraySetAsSeries(HighBuffer,true);
   // The indexation of LowBuffer[] array as timeseries
   ArraySetAsSeries(LowBuffer,true);
   // The indexation of CloseBuffer[] array as timeseries
   ArraySetAsSeries(CloseBuffer,true);
   // The indexation of the ColorIndexBuffer [] array as timeseries
   ArraySetAsSeries(ColorIndexBuffer,true);

Les valeurs des marges indicatrices égales à 0, ne doivent pas être tracées sur le graphique :

   // The null values of Open prices (0th graphic plot) should not be plotted
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0);
   // The null values of High prices (1st graphic plot) should not be plotted
   PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0);
   // The null values of Low prices (2nd graphic plot) should not be plotted
   PlotIndexSetDouble(2,PLOT_EMPTY_VALUE,0);
   // The null values of Close prices (3rd graphic plot) should not be plotted
   PlotIndexSetDouble(3,PLOT_EMPTY_VALUE,0);

Une fois que l'écriture de la fonction OnInit est terminée, nous fermons la fonction à l'aide d'un crochet.

Il est temps d'écrire la fonction OnCalculate. Spécifiez tous les paramètres transmis à la fonction :

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[])
  {

Nous déclarons les variables qui seront utilisées dans la fonction OnInit.

// the file_handle variable is a file handle
// the BidPosition and AskPosition - are positions of Bid and Ask prices in the string;
// the line_string_len is a length of a string, read from the file, 
// CandleNumber - number of candle, for which the prices OHLC are determined,
// i - loop counter;
int file_handle,BidPosition,AskPosition,line_string_len,CandleNumber,i;
// The last_price_bid variable is the recent received Bid price
double last_price_bid=SymbolInfoDouble(Symbol(),SYMBOL_BID);
// The last_price_ask variable is the recent received Ask price
double last_price_ask=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
// the filename is a name of a file, the file_buffer is a string, 
// used as a buffer for reading and writing of string data
string filename,file_buffer;

La variable file_handle de type entier est utilisée pour stocker le descripteur de fichier dans les opérations de fichier, les BidPosition et AskPosition sont utilisées pour un stockage des positions de départ des prix Bid et Ask dans la chaîne, la line_string_len est une longueur de chaîne, lue à partir d'un fichier, le CandleNumber - est l'indice de la bougie calculée, la variable i  est utilisée comme compteur de boucles.

Les prix d'offre et de demande récemment reçus sont stockés dans les variables de type double last_price_bid et last_price_ask. La variable filename d'un type chaîne est utilisée pour le stockage d'un nom de fichier, le file_buffer  est une chaîne, utilisée dans les opérations de fichier.

La taille du tableau TicksBuffer[] n'est pas définie automatiquement, contrairement aux tableaux OpenBuffer[], HighBuffer[], LowBuffer[], CloseBuffer[] et ColorIndexBuffer[], qui sont des marges indicatrices, alors définissons la taille d'un tableau TicksBuffer[] comme pareille à la taille des tableaux OpenBuffer[], HighBuffer[], LowBuffer[], CloseBuffer[] et ColorIndexBuffer[] :

// Setting the size of TicksBuffer[] array
ArrayResize(TicksBuffer,ArraySize(CloseBuffer));

Préparez le nom du fichier à partir de la variable path_prefix du nom de l'instrument financier et de l'extension « .txt » :

// File name formation from the path_prefix variable, name
// of financial instrument and ".Txt" symbols
StringConcatenate(filename,path_prefix,Symbol(),".txt");

Ouvrons le fichier avec les paramètres décrits ci-dessus pour l'indicateur précédent.

// Opening a file for reading and writing, codepage ANSI, shared reading mode
file_handle=FileOpen(filename,FILE_READ|FILE_WRITE|FILE_ANSI|FILE_SHARE_READ);

Si la fonction OnCalculate est appelée la première fois et qu'il n'y a pas de données dans le tableau TicksBuffer[] la lecture de celles-ci s’effectue à partir du fichier:

if(prev_calculated==0)
  {
   // Reading the first line from the file and determine the length of a string
   line_string_len=StringLen(FileReadString(file_handle))+2;
   // if file is large (contains more quotes than rates_total/2)
   if(FileSize(file_handle)>(ulong)line_string_len*rates_total/2)
     {
      // Setting file pointer to read the latest rates_total/2 quotes
      FileSeek(file_handle,-line_string_len*rates_total/2,SEEK_END);
      // Moving file pointer to the beginning of the next line
      FileReadString(file_handle);
     }
   // if file size is small
   else
     {
      // Moving file pointer at the beginning of a file
      FileSeek(file_handle,0,SEEK_SET);
     }
   // Reset the counter of stored quotes
   ticks_stored=0;
   // Reading until the end of the file
   while(FileIsEnding(file_handle)==false)
     {
      // Reading a string from thefile
      file_buffer=FileReadString(file_handle);
      // Processing of string if its length is larger than 6 characters
      if(StringLen(file_buffer)>6)
        {
         // Finding the start position of Bid price in the line
         BidPosition=StringFind(file_buffer," ",StringFind(file_buffer," ")+1)+1;
          //Finding the start position of Ask price in the line
         AskPosition=StringFind(file_buffer," ",BidPosition)+1;
         // If the Bid prices are used, adding the Bid price to TicksBuffer[] array
         if(applied_price==0)
         TicksBuffer[ticks_stored]=StringToDouble(StringSubstr(file_buffer,BidPosition,AskPosition-BidPosition-1));
         // If the Ask prices are used, adding the Ask price to TicksBuffer[] array
         if(applied_price==1)
         TicksBuffer[ticks_stored]=StringToDouble(StringSubstr(file_buffer,AskPosition));
         // Increasing the counter of stored quotes
         ticks_stored++;
        }
     }
  }

La lecture des cotations du fichier a été décrite plus en détail ci-dessus, elle est pareille à celle de l'indicateur précédent.

Si les cotations ont déjà été lues dans le tableau TicksBuffer[], nous écrivons une nouvelle valeur de prix dans le fichier, plaçons un nouveau prix dans le tableau TicksBuffer[] et nous rehaussons le compteur des cotations :

// If the data have been read before
else
  {
   // Moving file pointer at the end of the file
   FileSeek(file_handle,0,SEEK_END);
   // Forming a string, that should be written to the file
   StringConcatenate(file_buffer,TimeCurrent()," ",DoubleToString(last_price_bid,_Digits)," ",DoubleToString(last_price_ask,_Digits));
   // Writing a string to the file
   FileWrite(file_handle,file_buffer);
   // If the Bid prices are used, adding the last Bid price to TicksBuffer[] array
   if(applied_price==0) TicksBuffer[ticks_stored]=last_price_bid;
   // If the Ask prices are used, adding the last Ask price to TicksBuffer[] array
   if(applied_price==1) TicksBuffer[ticks_stored]=last_price_ask;
   // Increasing the quotes counter
   ticks_stored++;
  }

Clôture du fichier :

// Closing the file
FileClose(file_handle);

Si le nombre de cotations stockées atteint le nombre de barres sur le graphique des prix ou devient supérieur, nous supprimons la moitié des données les plus anciennes et décalons les données restantes :

// If number of quotes is more or equal than number of bars in the chart
if(ticks_stored>=rates_total)
  {
   // Removing the first tick_stored/2 quotes and shifting remaining quotes
   for(i=ticks_stored/2;i<ticks_stored;i++)
     {
      // Shifting the data to the beginning in the TicksBuffer[] array on tick_stored/2
      TicksBuffer[i-ticks_stored/2]=TicksBuffer[i];
     }
   // Changing the quotes counter
   ticks_stored-=ticks_stored/2;
  }

Calculons les valeurs OHLC pour chaque bougie et plaçons ces valeurs dans les marges indicatrices correspondantes :

   // We assign the CandleNumber with a number of invalid candle
   CandleNumber=-1;
   // Search for all the price data available for candle formation
   for(i=0;i<ticks_stored;i++)
     {
      // If this candle is forming already
      if(CandleNumber==(int)(MathFloor((ticks_stored-1)/ticks_in_candle)-MathFloor(i/ticks_in_candle)))
        {
         // The current quote is still closing price of the current candle
         CloseBuffer[CandleNumber]=TicksBuffer[i];
         // If the current price is greater than the highest price of the current candle,
          // it will be a new highest price of the candle
         if(TicksBuffer[i]>HighBuffer[CandleNumber]) HighBuffer[CandleNumber]=TicksBuffer[i];
         // If the current price is lower than the lowest price of the current candle, 
          // it will be a new lowest price of the candle
         if(TicksBuffer[i]<LowBuffer[CandleNumber]) LowBuffer[CandleNumber]=TicksBuffer[i];
         // If the candle is bullish, it will have a color with index 2 (green)
         if(CloseBuffer[CandleNumber]>OpenBuffer[CandleNumber]) ColorIndexBuffer[CandleNumber]=2;
         // If the candle is bearish, it will have a color with index 1 (red)
         if(CloseBuffer[CandleNumber]<OpenBuffer[CandleNumber]) ColorIndexBuffer[CandleNumber]=1;
         // If the opening and closing prices are equal, then the candle will have a color with index 0 (grey)
         if(CloseBuffer[CandleNumber]==OpenBuffer[CandleNumber]) ColorIndexBuffer[CandleNumber]=0;
        }
      // If this candle hasn't benn calculated yet
      else
        {
         // Let's determine the index of a candle
         CandleNumber=(int)(MathFloor((ticks_stored-1)/ticks_in_candle)-MathFloor(i/ticks_in_candle));
         // The current quote will be the opening price of a candle
         OpenBuffer[CandleNumber]=TicksBuffer[i];
         // The current quote will be the highest price of a candle
         HighBuffer[CandleNumber]=TicksBuffer[i];
         // The current quote will be the lowest price of a candle
         LowBuffer[CandleNumber]=TicksBuffer[i];
         // The current quote will be the closing price of a candle
         CloseBuffer[CandleNumber]=TicksBuffer[i];
         // The candle will have a color with index 0 (gray)
         ColorIndexBuffer[CandleNumber]=0;
        }
     }

L'exécution de la fonction OnCalculate s’achève avec la réinitialisation à une valeur non nulle, ce qui signifie que le tableau TicksBuffer[] a déjà les données et qu’il n'est pas nécessaire de les lire au prochain appel de la fonction. Nous plaçons le crochet final à la fin de la fonction            

 // Return from OnCalculate(), return a value, different from zero   
 return(rates_total);
}

À la fin de l'article, il y a un lien qui peut être utilisé pour télécharger le code source complet de l'indicateur.

Conclusion

Dans cet article, nous avons envisagé la création de deux indicateurs à graduations : l'indicateur graphique à graduations et l'indicateur « tick candles ».

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

Fichiers joints |
tickindicator.mq5 (8.28 KB)
Nouvelles opportunités avec MetaTrader 5 Nouvelles opportunités avec MetaTrader 5
MetaTrader 4 a gagné en popularité auprès des traders du monde entier, et il semblait que rien de plus ne pouvait être souhaité. Avec sa vitesse de traitement élevée, sa stabilité, son large éventail de possibilités d'écriture d'indicateurs, d'Expert Advisors et de systèmes de trading informatifs, et la possibilité de choisir parmi plus d'une centaine de courtiers différents, le terminal s'est grandement distingué des autres. Mais le temps ne s'arrête pas et nous nous trouvons face à un choix de MetaTrade 4 ou MetaTrade 5. Dans cet article, nous décrirons les principales différences du terminal de 5ème génération par rapport à notre actuel favori.
Les styles de dessin dans MQL5 Les styles de dessin dans MQL5
Il existe 6 styles de dessin dans MQL4 et 18 styles de dessin dans MQL5. Par conséquent, il peut être intéressant d'écrire un article pour présenter les styles de dessin de MQL5. Dans cet article, nous examinerons les détails des styles de dessin dans MQL5. De plus, nous allons créer un indicateur pour montrer comment utiliser ces styles de dessin et affiner le tracé.
Guide étape par étape pour rédiger un conseiller expert en MQL5 pour les débutants Guide étape par étape pour rédiger un conseiller expert en MQL5 pour les débutants
La programmation des Expert Advisors dans MQL5 est simple et vous pouvez l'apprendre facilement. Dans ce guide étape par étape, vous verrez les étapes de base nécessaires à la rédaction d'un simple Expert Advisor basé sur une stratégie de trading développée. La structure d'un Expert Advisor, l'utilisation d'indicateurs techniques et de fonctions de trading intégrés, les détails du mode Debug et l'utilisation du Testeur de stratégie sont ici présentés.
Comment faire appel aux indicateurs dans MQL5 Comment faire appel aux indicateurs dans MQL5
Avec la nouvelle version du langage de programmation MQL disponible, non seulement l'approche du traitement des indicateurs a changé, mais il existe également de nouvelles façons de créer des indicateurs. De plus, vous disposez d'une flexibilité supplémentaire en travaillant avec les tampons d'indicateurs - vous pouvez désormais spécifier la direction d'indexation souhaitée et obtenir exactement autant de valeurs d'indicateurs que vous le souhaitez. Cet article explique les méthodes de base pour faire appel aux indicateurs et récupérer des données à partir des tampons de l'indicateur.