mercredi 17 juillet 2013

Les conditions en MQL4: initiation à la programmation des experts advisors

L'instruction if

Quelque chose d'important, et sans ça la programmation serait très restreinte: les conditions. Une condition permet de faire un choix, de n'exécuter une série d'instructions (ou une seule) seulement si une condition est remplie. Cette condition est testée avec une instruction ' if '. C'est la traduction anglaise de ' si '. On met après le ' if ' la condition à respecter pour que les instructions qui suivent soient exécutées. ' if ' est considéré dans la documentation de MQL4 comme un opérateur. Peu importe le nom qu'on donne à cette chose, elle réalise le même travail quelque soit le langage de programmation. Elle se présente comme suit:

if(condition) {
    instruction 1;
    instruction 2;
    ...
    instruction n;
}
instruction suivante toujours réalisée;

Le ' if ' suivi par une condition entre parenthèses puis on ouvre une accolade pour y placer le bloc d'instructions qui sera exécuté si la condition est remplie. Puis les instructions à exécuter sous cette condition et une accolade fermante pour terminer ce bloc et après ce bloc les instructions qui continuent le programme et qui seront exécutées de toute façon. Nous allons maintenant détailler un peu la condition.

La condition

Une condition est une expression qui donne une valeur booléenne, c'est-à-dire vrai ou faux. Si la valeur résultante est vrai, alors la condition est remplie, si elle vaut faux, elle n'est pas remplie. Qu'est-ce qui peut donner une valeur booléenne ? Comme on l'a vu avant il y a des variables qui peuvent contenir une telle valeur. J'avais donné comme exemple  bool enMouvementHaussier = false donc si je mets cette variable dans les parenthèses de la condition, c'est suffisant. Par exemple:

if(enMouvementHaussier) {
    instruction d'ordre d'achat;
}
instruction suivante toujours réalisée;

Si la valeur contenue dans la variable enMouvementHaussier est true (vrai) alors l'ordre d'achat dans la paire d'accolades est exécuté. Et on peut même en combiner plusieurs de manière logique avec des connecteurs logiques qui sont les opérateurs NON, OU et ET. L'opérateur NON prend le contraire de ce qui suit (si la valeur est vrai, il la transforme en faux et inversement). L'opérateur OU connecte deux valeurs et il faut que l'une des valeurs au moins soit vraie pour que le résultat soit vrai. (il faut l'une ou l'autre). L'opérateur ET demande à ce que les deux valeurs soient vraies pour que le résultat soit vrai. (il faut l'une et l'autre). En MQL4 ces opérateurs se notent:

  • NON: avec le point d'exclamation !. Par exemple:  !enMouvementHaussier;  signifie le contraire soit "pas en mouvement haussier" et si  enMouvementHaussier = true; , alors  !enMouvementHaussier  vaut  false .
  • OU: avec le double pipe: || (ALT GR+6). Par exemple  enMouvementHaussier || enMouvementBaissier  qui vaudra vrai si l'un ou l'autre vaut vrai, c'est-à-dire s'il y a un mouvement quel qu'il soit.
  • ET: avec le double esperluette: &&. Par exemple:  enMouvementHaussier && enAcceleration  qui vaudra vrai si l'une et l'autre valent vrai. Il faut les deux à la fois, c'est à dire qu'il y a une hausse et une accélération.

Les tests

C'est très bien tout ça, et on peut faire plein de combinaisons, mais ça ne dit toujours pas comment on peut décider de mettre vrai ou faux dans une variable ! Pouvoir calculer un vrai ou un faux, ça se fait avec un test. Il y a dans un langage de programmation, des opérations qui produisent une valeur vrai ou faux. Ces opérations sont des tests logiques. Des comparaisons d'égalité, d'infériorité ou de supériorité. Le compilateur lit ces tests à faire entre des valeurs, il les effectue et il produit un résultat vrai ou faux.

  • test d'égalité: a == b teste si les deux valeurs sont égales et donne la valeur vrai si c'est le cas, faux sinon. (double signe égal pour l'opérateur d'égalité.)
  • test d'inégalité: a != b teste si les deux valeurs sont différentes et renvoie la valeur vrai si c'est le cas et faux sinon.
  • test d'infériorité stricte: a < b teste si a est plus petit que b et renvoie vrai si c'est le cas, faux sinon.
  • test d'infériorité large: a <= b teste si a est inférieur ou égal à b et renvoie vrai si c'est le cas, faux sinon.
  • test de supériorité large a >= b teste si a est plus grand ou égal à b et renvoie vrai si c'est le cas, faux sinon.
  • test de supériorité stricte: a > b teste si a est plus grand que b et renvoie vrai si c'est le cas, faux sinon.

Que faire avec ces tests ? On peut stocker le résultat dans une variable:
  enMouvementHaussier = (coursActuel > coursPrecedent); 
Puis utiliser cette variable dans la condition du if ou alors la combiner avec des connecteurs logiques NON, OU ou ET pour produire un autre résultat logique. On peut aussi mettre directement le test dans la condition du if:


if(coursActuel > coursPrecedent) {
    instructions dans le cas ou le cours actuel
    est plus grand que le précédent;
}
instruction suivante toujours réalisée;

On va tester ces déterminations de mouvement haussiers et baissiers et voir que la détermination d'une tendance n'est pas si simple que juste regarder si le cours actuel est plus grand ou plus petit que le précédent. On va donc faire un expert advisor basé sur ce principe pour compter les mouvements dans un sens et dans l'autre.

Expert Advisor primitif de comptage de mouvements

Première chose: on peut facilement obtenir le bid et le ask par les variables prédéfinies du même nom: Bid et Ask. Des variables prédéfinies sont bel et bien des variables et s'utilisent comme les autres sauf nous ne les avons pas déclarées et ni choisi leur nom et ni affecté une valeur, c'est MetaTrader qui a fait tout ça. Nous avons juste à les utiliser, mais sans leur affecter de valeur car c'est MetaTrader qui doit s'en charger. D'ailleurs on ne saurait pas quoi mettre comme valeur car nous n'avons pas les éléments nécessaires pour le faire. On va donc utiliser ces valeurs d'offre et de demande, mais comme le broker les font varier indépendamment du cours réel, on va tenter de retrouver la valeur du cours réel en faisant la moyenne des deux, car le cours réel se trouve approximativement au milieu, entre les deux. on va donc faire (Bid + Ask) / 2.
Deuxième chose: il faut comparer deux valeurs du cours qui se sont suivies. On va donc copier la valeur qui a été prise au tick précédent dans une variable à part avant de l'écraser par la nouvelle valeur. Comme ça on aura les deux valeurs successives qu'on pourra comparer. On va donc faire:

    coursPrecedent = coursActuel;
    coursActuel = (Bid + Ask) / 2;

A la première ligne le cours actuel est copié dans la variable cours précédent. Le cours actuel était celui du tick précédent qui est resté. Puis à la deuxième ligne le cours actuel prend la nouvelle valeur issue du calcul de la moyenne du bid et du ask. Il faudra initialiser le cours actuel avec une valeur quelconque au début, car au premier tick reçu, on en a besoin avant même de lui affecter sa première valeur. Et donc on aura forcément un mouvement dès le départ entre la valeur d'initialisation et celle du premier tick. Ce mouvement de départ est un artefact de l'algorithme, du programme tel qu'on l'a fait. Il faut coder autrement pour que ce soit parfait. Il faudrait rajouter du code pour l'éviter, mais on s'en fout et on ne va pas se compliquer la vie pour cet exemple. On va alors faire toutes ces étapes:
  1. Démarrer MetaTrader 4 si ce n'est pas déjà le cas.
  2. Cliquez sur le bouton au losange jaune pour démarrer l'éditeur de code.
  3. Une fois l'éditeur de code ouvert, cliquez sur le bouton à la croix verte pour un nouveau programme.
  4. Sélectionnez Expert Advisor et cliquez sur le bouton "suivant".
  5. Mettez le nom "ComptageMouvements" et cliquez sur le bouton "Terminer".
  6. Agrandissez la fenêtre de code et effacez toutes les lignes avec  //----  Il ne doit y avoir qu'une seule ligne vide par section.
  7. Placez-vous en haut du fichier, dessous les lignes  #property  cliquez pour y placer le curseur et appuyez sur la touche Entrée pour faire une nouvelle ligne vide.
  8. Saisissez le code suivant
  9. int nbHausses, nbBaisses, nbTicksRecus;
    double coursActuel, coursPrecedent;
    string debutMessage = "Il y a eu ";
    string milieuMessage = " baisses et ";
    string finMessage = " hausses sur ";
    
  10. Cliquez sur la ligne vide de la première section, pour y placer le curseur et saisissez:
  11. coursActuel = 1.0;
    nbBaisses = 0;
    nbHausses = 0;
    nbTicksRecus = 0;
    
  12. Dans la deuxième section, cliquez sur la ligne vide pour y placer le curseur et saisissez:
  13. prin
    Appuyez sur la touche Entrée pour valider la proposition
    de l'auto-complétion.
    (debutMessage, nbBaisses, milieuMessage, nbHausses, finMessage, nbTicksRecus);
    
  14. Allez dans la troisième section et cliquez dans la ligne vide pour y mettre le curseur et saisissez:
  15. coursPrecedent = coursActuel;
    coursActuel = (Bid + Ask) / 2;
    if(coursActuel > coursPrecedent){
        nbHausses = nbHausses + 1;
    }
    if(coursActuel < coursPrecedent){
        nbBaisses = nbBaisses + 1;
    }
    nbTicksRecus = nbTicksRecus + 1;
    
  16. Cliquez sur le bouton avec la disquette bleue pour sauvegarder;
  17. Cliquez sur le bouton "Compile" pour créer le fichier exécutable.
  18. Vérifiez qu'il n'y a pas d'erreurs, sinon corrigez, puis retournez dans MetaTrader
  19. Déroulez l'arborescence de Experts Consultants de la petite fenêtre de gauche.
  20. Glissez et déposez l'expert ComptageMouvements sur un graphique.
  21. Au bout d'un moment Faites un clic droit sur le graphique
  22. Dans le menu contextuel, à Experts consultants, cliquez sur Retirer.
  23. Allez dans la fenêtre du bas, cliquez sur l'onglet Experts.
  24. Vous pouvez constater les comptages de mouvements de hausses et de baisses, ainsi que le total des ticks reçus.

Je vais un peu commenter ce code. Premièrement, on peut, lorsqu'on déclare des variables de même type, les déclarer ensemble sur la même ligne en les séparant par des virgules. Deuxièmement, à l'initialisation, on fixe le cours actuel à une valeur arbitraire, donc autant choisir celle qui a le plus de sens: j'ai choisis l'équité parfaite entre les devises de la paire, c'est-à-dire qu'elles valent autant l'une que l'autre donc un rapport entre leurs valeurs de 1. Je tape 1.0 parce qu'il faut un nombre à virgule, vu que le cours est stocké dans une variable de type nombre décimal (double). Les comptes de mouvements sont évidemment mis à zéro. Maintenant, dans la fonction start(). On commence par copier la valeur de coursActuel qui est celle du tick précédent (ou 1.0 si c'est le premier tick) pour sauvegarder temporairement dans coursPrecedent, histoire de pouvoir comparer l'évolution. Ensuite on écrase l'ancienne valeur coursActuel par la nouvelle qui est le calcul de la moyenne entre bid et ask. Puis il n'y a qu'à comparer, si le cours actuel est plus grand que le précédent on augmente les hausses de 1, et si le cours actuel est plus petit que le précédent on augmente les baisses de 1. Et pour finir, dans tous les cas on augmente le nombre de ticks reçus de 1. Toutes ces opérations d'augmentation s'appelent dans le jargon informatique et mathématique: incrémenter de 1. A l'arrêt de l'expert, il faut évidemment afficher les comptes. Conservez ce petit expert, j'y reviendrai pour faire un indicateur qui peut être vraiment intéressant et dont je viens d'avoir l'idée. D'ailleurs, tous ceux qui ont des idées d'amélioration, d'utilisation de ce code peuvent les proposer en commentaires, n'hésitez pas, partagez. Maintenant, le code complet pour que vous puissiez avoir une référence et la même chose en vidéo, je vous le montre et je vous fais ensuite pratiquer avec moi plus lentement.

//+------------------------------------------------------------------+
//|                                           ComptageMouvements.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"

int nbHausses, nbBaisses, nbTicksRecus;
double coursActuel, coursPrecedent;
string debutMessage = "Il y a eu ";
string milieuMessage = " baisses et ";
string finMessage = " hausses sur ";

//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
   coursActuel = 1.0;
   nbBaisses = 0;
   nbHausses = 0;
   nbTicksRecus = 0;
   return(0);
  }
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
  {
   Print(debutMessage, nbBaisses, milieuMessage, nbHausses, finMessage, nbTickRecus);
   return(0);
  }
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
  {
   coursPrecedent = coursActuel;
   coursActuel = (Bid + Ask) / 2;
   if(coursActuel > coursPrecedent){
      nbHausses = nbHausses + 1;
   }
   if(coursActuel < coursPrecedent){
      nbBaisses = nbBaisses + 1;
   }
   nbTicksRecus = nbTicksRecus + 1;
   return(0);
  }
//+------------------------------------------------------------------+



J'espère que ça vous a été profitable, que vous progressez. Si vous avez besoin d'éclaircissements, demandez-les en commentaires. Pour le prochain post nous allons en remettre une couche sur le ' if ' avec son extension: la clause ' else '. Comme ça vous pratiquerez un peu plus cette notion, vous la comprendrez mieux et la maîtriserez mieux. Il faut battre le fer tant qu'il est chaud !

2 commentaires:

  1. Très intéressant.
    Une question. Est-il toujours nécessaire de faire la moyenne entre ask et bid pour un obtenir une valeur moyenne du dernier cours ?
    Existe-t-il une variable qui détermine le dernier cours ?
    Encore merci pour ces excellents tutos !

    RépondreSupprimer
    Réponses
    1. Bonjour,
      Non, il n'est pas nécessaire de faire la moyenne. Tous les autres développeurs n'utilisent que le bid. D'autant que l'historique de MetaTrader n'enregistre que le bid.
      Je suis apparemment le seul qui tente de retrouver le cours réel. Si vous observez bien, les cours et notamment la petite fenêtre des graphiques en ticks à gauche dans MetaTrader, vous verrez que le cours peut rester stable par moment et que c'est le broker en faisant varier son spread qui introduit du mouvement supplémentaire, et donc du bruit par rapport au signal d'origine.
      Selon les Experts et Indicateurs que je vais vous faire programmer, j'utiliserais différentes techniques, soit que le bid, soit la moyenne, ou d'autres calculs.
      Y a pas de quoi !
      PS: après une longue interruption pour causes de soucis personnels, je reprend ce blog et tiendrai les promesses :).

      Supprimer