mardi 13 août 2013

Débuggage et reformulation d'algorithme

L'initiation à la programmation en MQL4 est finie, mais l'apprentissage ne finit jamais. Je reviens donc sur l'expert advisor que nous avons fait et restructuré: celui de la moyenne du cours à chaque seconde. Son code a été amélioré, il est plus clair et explicite. Mais il contient des bugs potentiels. Nous allons y réfléchir et aussi repenser la manière de faire la moyenne. Comme ça vous verrez qu'il n'y a pas qu'une seule façon de faire et que la façon dont nous avons procédé est maladroite !

Le problème du choix de la taille du tableau:

Réfléchissons à propos du tableau utilisé. Nous fixons sa taille à 10 car nous ne savons pas combien nous avons de ticks dans la seconde, et surtout, ça change à chaque seconde: c'est variable. Nous avons donc choisi une taille de 10 considérant que ce sera largement suffisant. En effet il y a très peu de risque d'avoir plus de 10 ticks dans une seconde. Très peu de risque ne signifie pas risque zéro. Il y a tout de même une probabilité, même faible. Alors on peut choisir d'agrandir le tableau pour réduire encore plus cette probabilité de débordement de tableau. Cette façon de faire n'est pas la bonne, il faut revoir tout ça et faire autrement. Même si on sait qu'en choisissant une taille doublée, nous pourrons rester une vie à faire fonctionner le programme sans que le débordement ne se produise. Ce n'est pas la manière la plus élégante de résoudre le problème puisqu'on laisse théoriquement un bug possible de débordement. Et normalement un débordement de tableau produit un crash du programme. Le système l'arrête immédiatement car le programme essaie d'écrire dans une zone qui n'est plus le tableau et qu'il n'a pas le droit d'écrire. S'il s’avérait que le programme ait le droit d'écrire dans la mémoire juste après le tableau, c'est que c'est une zone qu'il a réservé auprès du système, et donc on écrit et on écrase une donnée du programme ou le programme lui même. Et ceci va provoquer d'autres bugs, un comportement anormal voire un crash du programme. Il faut être très prudent avec les tableaux, il ne faut surtout pas écrire ou lire en débordant du tableau. Nous allons régler le problème en changeant la façon de faire la moyenne.

Traitements inutiles:

Voyons un peu ce que fait le programme. Pour obtenir la moyenne, il enregistre les cours de chaque tick, puis lorsque la seconde n'est plus la même, il parcours tous les enregistrements pour les additionner. Et au final on fait la division de la somme par le nombre d'éléments parcourus. Regardons un peu ce qu'on fait avec les enregistrements dans le tableau: juste la somme des enregistrements, et rien d'autre. Alors dans ce cas, pourquoi les enregistrer dans le tableau. On pourrait directement les additionner dans une variable qui contiendra la somme. Comme ça quand la seconde n'est plus la même: on a juste à effectuer la division. On s'épargne ainsi les étapes d'enregistrement, de parcours de tableau pour lire tous ses éléments L'algorithme est donc plus rapide, car moins d'étapes et en plus: fini le problème de la taille du tableau. Sans tableau il n'y a plus de débordement possible. Cet algorithme est donc plus fiable et plus rapide (bien qu'on ne s'apercevra pas de la différence). C'est un code plus robuste car on s'est affranchi d'un problème théorique. La somme des cours pourra en accumuler autant que nécessaire, et plus besoin de réserver de la place pour chacun en mémoire.

Améliorations:

On peut pousser plus loin les améliorations en n'écrivant les constantes qu'une seule fois dans le code. Et en plus ça rassemble les déclarations en un lieu unique. Par exemple, le nom du label ("moyenne") est indiqué deux fois à deux endroits différents dans le code. On le passe dans une variable dont la valeur ne change pas: une constante. En MQL4, rien ne différencie une variable d'une constante. Si on veut faire une constante, il faut une variable, initialiser dès la déclaration et faire attention à ne pas la modifier, car du point de vue du langage, c'est une variable comme les autres, dont la valeur peut changer en y affectant une nouvelle. On va donc créer la variable constante 'NOM_LABEL' au début du fichier. L'avantage c'est que si on doit la modifier pour faire évoluer le code, on ne le fait qu'à un seul endroit, et une seule fois. Nous n'aurons pas à répéter les modifications à différents endroits du code. On va faire de même pour la taille du texte du label avec une variable constante nommée TAILLE_TEXTE. (On fait une différentiation dans le nommage pour reconnaitre les variables des constantes, les constantes sont en majuscules avec un souligné pour séparer les mots. Ce n'est qu'une convention que j'applique à mes codes). On en profite aussi pour mettre le texte dans une autre couleur car il est peu visible en l'état. Les couleurs du web sont déjà inscrites dans le langage. On va utiliser 'White'. Attention, il faut mettre la majuscule, car l'auto-complétion ne reconnait pas ces constantes, et pourtant l'éditeur de code en changera la couleur, ce qui signifie qu'il reconnait le mot. Cette couleur est à préciser en dernier paramètre de la fonction ObjectSetText(). Il y a un paramètre de police de caractères juste avant qu'il faut alors préciser. On le met "Arial" dans une constante nommée FONTE qu'on utilisera comme paramètre. Maintenant je vais vous le faire faire en vidéo. Je vous montre étape par étape. Après la vidéo le code complet. Nous ferons un nouvel expert advisor pour pouvoir garder l'autre, vous pourrez ainsi comparer.



//+------------------------------------------------------------------+
//|                                           moyenneParSeconde2.mq4 |
//|                  Copyright 2013, argent-facile-avec-robots-forex |
//|               http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, argent-facile-avec-robots-forex"
#property link   "http://argent-facile-avec-robots-forex.blogspot.fr"

datetime tempsEnCoursTraitement, tempsTickActuel;
double sommeCours;
int nbTicksDansSeconde;
string NOM_LABEL = "moyenne";
int TAILLE_TEXTE = 10;
string FONTE = "Arial";

double obtenirCoursActuel() {
   double cours = (Bid + Ask) / 2.0;
   return(cours);
}

void creerLabel(string nom, int x, int y) {
   bool aReussi = ObjectCreate(nom, OBJ_LABEL, 0, x, y);
   if(aReussi) { ObjectSetText(nom, "###", TAILLE_TEXTE, FONTE, White); }
   else { Print("Erreur à la création du texte: ", GetLastError()); }
}

void effacerObjetsGraphiques() {
   int nbObjetsEffaces = ObjectsDeleteAll();
   Print(nbObjetsEffaces, " objets graphiques effacés !");
}

//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
   tempsEnCoursTraitement = MarketInfo(Symbol(), MODE_TIME);
   sommeCours = 0.0;
   nbTicksDansSeconde = 0;
   creerLabel(NOM_LABEL, 1,1);
   return(0);
  }
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
  {
   effacerObjetsGraphiques();
   return(0);
  }
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
  {
   double moyenneCours = 0.0;
   tempsTickActuel = MarketInfo(Symbol(), MODE_TIME);
   if(tempsTickActuel > tempsEnCoursTraitement) {
      if(nbTicksDansSeconde > 0) { moyenneCours = sommeCours / nbTicksDansSeconde; }
      ObjectSetText(NOM_LABEL, DoubleToStr(moyenneCours, 5), TAILLE_TEXTE, FONTE, White);
      sommeCours = 0.0;
      nbTicksDansSeconde = 0;
      tempsEnCoursTraitement = tempsTickActuel;
   }
   sommeCours += obtenirCoursActuel();
   nbTicksDansSeconde++;
   return(0);
  }
//+------------------------------------------------------------------+

J'insiste sur ce code car nous allons en faire la base d'un indicateur. Cet indicateur sera simplement le cours sans bruit, sans artifices psychologiques et dénués de sens mathématique telles les clôtures. Ce sera une moyenne par chandelier, et avec bien plus de sens mathématique pour le traitement du signal que ce dont on dispose actuellement sur les graphiques. Nous y ajouterons même une information supplémentaire: l'écart-type et vous constaterez un signal dénué de bruit en le comparant avec les cours selon les clôtures. Nous allons le faire dès le prochain post.

Aucun commentaire:

Enregistrer un commentaire