mardi 21 janvier 2014

un fichier include d'arithmétique temporelle et horodatages

Je vous propose dès à présent d'organiser votre code et en même temps je vous fourni du code réutilisable dans vos projets. Le but est de mettre dans un fichier des fonctions qui peuvent servir à plusieurs experts advisors ou indicateurs de Metatrader que vous créez. Ces fichiers sont des fichiers "include". Nous allons en faire plusieurs à l'avenir, et je vous propose ici de débuter un fichier "include" consacré à l'arithmétique temporelle. Il contiendra de nombreuses fonctions qui serviront à des calculs ou traitements sur le temps et le type datetime.

Les fichiers include .mqh:


On les nomme ainsi car on fait appel à la directive du préprocesseur #include pour les inclure dans un programme qui va utiliser une ou des fonctions intégrées à cet "include". Ces fichiers portent l'extension ".mqh" pour MetaQuotes Header, car du point de vue programmation, il s'agit de fichiers headers qui normalement ne devraient contenir que des déclarations. Et là j'ai fait un choix personnel, critiquable et j'attends les remarques, d'utiliser ces fichiers pour non seulement déclarer les fonctions mais aussi y mettre tout le code des fonctions. Et ceci au lieu d'utiliser la directive #import qui permet d'importer des fonctions une par une. Je ne jette pas la pierre aux programmeurs de MetaQuotes car créer un langage est quelque chose de très très conséquente. C'est un gros projet pas facile du tout et je leur tire mon chapeau pour la création d'un langage. Mais le fait est que Le langage MQL4 n'est pas très aboutit. Ils ont fait des choix techniques en fonction de leurs moyens humains et temporels, et il y a quelques défauts notables, dont celui de la création de bibliothèques de fonctions qui normalement devrait aboutir à l'utilisation de la directive #import pour sélectionner juste la fonction qu'on veut, mais je n'ai pas trouvé comment forcer le compilateur à produire l'exécutable alors qu'il n'y a pas de fonction init(), deinit() et start() dans le code. Oui, lorsqu'on créé une librairie de fonctions, on écrit un fichier qui ne contient que des fonctions à utiliser séparément et qui n'est pas destiné à être exécuté dans son ensemble sur une paire de devises comme un expert advisor ou un indicateur. Il n'y a donc pas à mettre les fonctions init(), deinit() et start(). Mais Le soucis c'est que le compilateur les réclame pour produire l'exécutable. Et en plus quand on réussit à produire l'exécutable quand je mets ces fonctions (enfin surtout start()) qui ne doivent surtout pas être là, il faut charger en mémoire la totalité de la librairie pour utiliser qu'une seule fonction, quand un expert advisor ou un indicateur y fait appel. Mon choix est de placer ces fonctions dans un header qui normalement n'est pas fait pour ça, mais le compilateur me signalera en warning seulement toutes les fonctions qui ne sont pas utilisées par le code et qu'il n'a pas mis dans l'exécutable. Du coup ce sera plus léger en mémoire lors du fonctionnement. Je dois juste faire attention aux collisions de noms en choisissant des noms de fonctions dont je suis sûr qu'ils ne seront pas utilisés ailleurs, donc des noms suffisamment précis. Ah ! ... Le nommage ! =D (Autre défaut de ce langage: la limitation des noms à 31 caractères ! Ce qui m'oblige à faire des entorses à ce qu'on appelle le "clean code", voir le livre du même nom pour les expérimentés en programmation). Peut-être quelque chose m'échappe sur l'utilisation des fichiers librairies qui doivent normalement être utilisés à la place des fichiers headers dans ce cas. Je finirai par le comprendre. Un fichier include se réalise en sélectionnant "include" dans l'assistant de nouveau fichier.

Le préprocesseur:


J'en reviens aux fichiers headers. Ils contiennent donc des déclarations de constantes, des inclusions d'autres fichiers, des imports etc. Le principe de ces fichiers est d'être inclus dans d'autres. Pour cela il y a ce qu'on appelle le préprocesseur. Il s'agit d'un programme qui va être lancé automatiquement juste avant le compilateur pour scanner le fichier source qu'on veut compiler à la recherche de directives qui sont des instructions pour lui. Ces directives doivent être seules sur une ligne et commencer par le signe dièse: #include <fichier-a-inclure.mqh> et il n'y a pas de point virgule à la fin d'une directive car ce n'est pas une instruction pour le compilateur, et elle ne sera plus là quand le compilateur passera. Il y aura à la place le code du fichier inclus. Cette directive indique au préprocesseur d'y mettre à la place le contenu du fichier entre les chevrons.

horodatage et MarketInfo():


Je le rappelle car on l'a vu dans le post précédent, l'horodatage est un nombre entier qui désigne le nombre de secondes écoulées depuis le 1er janvier 1970 à 00:00:00 GMT. Ce nombre on ne l'invente pas ! On peut le calculer pour une date précise, mais il faudra tenir compte des années bisextiles, et autres détails gênants du même type, et ça ... je ne pense pas que vous y teniez ! :D Surtout que les horodatages, on ne peut pas les deviner, ils doivent être liés à une cotation et c'est seulement le serveur qui peut nous les donner. Il y a donc une fonction qu'on a vu qui peut récupérer le dernier temps reçu avec la dernière cotation. C'est
MarketInfo(Symbol(), MODE_TIME);

Le premier paramètre pourrait tout aussi bien être remplacé par "EURUSD" ou "GBPJPY" par exemple car Symbol() donne la même chose pour la paire de devise sur lequel est lancé le programme. Le deuxième paramètre est une constante définie par Metatrader, c'est-à-dire un nombre fixe qui indique qu'on veut le dernier horodatage reçu.

La fonction TimeCurrent():


La fonction précédente est à connaitre car on va l'utiliser à de nombreuses reprises pour diverses informations sur le marché, mais il y a plus simple pour obtenir le dernier horodatage reçu du serveur pour la paire de devises courante: c'est la fonction TimeCurrent(). On va donc créer une fonction qui va l'exploiter pour nous donner le dernier temps reçu pour une paire de devise. Mais aussi exploiter la possibilité de demander cette information pour n'importe quelle paire. Cette paire de devise sera passée en paramètre avec une valeur par défaut. Avec une valeur par défaut, nous ne sommes pas obligés de fournir une valeur en paramètre à la fonction pour l'appeler, et ce sera souvent le cas. Attention on serait tenté de mettre Symbol() à cette valeur par défaut, mais le compilateur ne va pas l'accepter car il lui faut quelque chose de constant et cette fonction donne nécessairement une valeur non constante. On va donc mettre la valeur "NULL" par défaut et si c'est la valeur du paramètre alors on utilise TimeCurrent() sinon on utilise MarketInfo() avec la paire passée en argument. Et cette fonction doit retourner un nombre entier qui est le numéro du dernier temps connu. On ne peut même pas utiliser la constante NULL parce que le compilateur ne l'accepte pas. Et pourtant ce serait bien pratique, c'est un beau défaut du langage MQL4. On utilise alors la même chose sous forme de chaine de caractères, mais ce n'est pas une bonne façon de régler le problème et si quelqu'un a une idée, qu'il la propose en commentaire. Les types int et datetime ne sont pas complètement compatibles, on va donc utiliser le type le plus précis puisqu'il y a un problème avec les valeurs négatives des entiers qui n'existent pas pour les horodatages. Les entiers vont de environ -2 milliards à +2 milliards, alors que les horodatages vont de 0 à 4 milliards environ. Si on laisse faire le cast, il y aura sûrement un problème à la conversion avec les horodatages supérieurs à 2 milliards qui seront mis en négatif. Voici le code de la fonction:

datetime obtenirNoDerniereSecConnue(string paire="NULL") {
   datetime horodatage;
   if(paire=="NULL") { horodatage = TimeCurrent(); }
   else { horodatage = MarketInfo(paire, MODE_TIME); }
   return(horodatage);
}

Le tutoriel vidéo et le code du fichier include:




//+------------------------------------------------------------------+
//|                                       ArithmetiqueTemporelle.mqh |
//|                  Copyright 2014, argent-facile-avec-robots-forex |
//|               http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, argent-facile-avec-robots-forex"
#property link   "http://argent-facile-avec-robots-forex.blogspot.fr"

//+------------------------------------------------------------------+
//| defines                                                          |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| DLL imports                                                      |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| EX4 imports                                                      |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| includes                                                         |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| variables globales                                               |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| constantes globales                                              |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| fonctions comptage                                               |
//+------------------------------------------------------------------+

datetime obtenirNoDerniereSecConnue(string paire="NULL") {
   datetime horodatage;
   if(paire=="NULL") { horodatage = TimeCurrent(); }
   else { horodatage = MarketInfo(paire, MODE_TIME); }
   return(horodatage);
}

//+------------------------------------------------------------------+

Nous n'avons qu'une fonction pour l'instant dans cet include mais il va très vite s'étoffer, et ce, dès les posts suivants. Nous allons d'abord créer un fichier de tests pour les fonctions de ce fichier include. Et nous créerons d'autres fonctions pour celui-là et d'autres fichiers include dans la foulée.

 PS: Cette fonction peut être critiquée aussi, car elle n'existe que pour nous donner un nombre qu'on aurait pu avoir plus simplement en utilisant directement les fonctions MQL4 qu'elle utilise. D'autant plus que son code n'est là que pour vérifier si on a passé le paramètre et choisir la fonction MQL4 correspondante. Son avantage unique est qu'elle permet de renommer une action grâce à son nom ce qui rend le code extrêmement lisible et compréhensible, ce qui nous arrange pour résoudre notre problème de programmer un robot qui rapporte des sous. Du point de vue traitements informatiques, elle n'arrange rien du tout, et alourdit même le travail du microprocesseur.

Aucun commentaire:

Enregistrer un commentaire