Programmer en MQL4

 

Sortie en boutique ce mois ci du livre de Henry Baltzer intitulé “Programmer en MQL4“. Henry avait déjà écrit en format électronique le fameux “MQL4 pour les nuls“. Face à la demande et à l’abscence de toute offre francophone, il a décidé d’amméliorer ce premier jet et de produire un livre complet au format papier. Le livre étant publié à compte d’auteur, acheter une version est aussi un moyen de supporter ce genre d’inititatives plus que rares puisque c’est la première…

 

 

Apprenez à automatiser vos stratégies sur MetaTrader 4. Cet ouvrage est le premier guide de programmation en MQL4 en français. Grâce à ce manuel, vous pourrez apprendre à programmer vos stratégies, modifier des codes existants ou encore tout simplement comprendre la logique derrière certains experts consultants.

Programmer en MQL4 est dispoinible en boutique de Trading Automatique.

Exécution des Programmes MQL4

 

Les compétences en programmation seront mieux développées si le programmeur a un programme léger à sa disposition. Pour comprendre l’ensemble du programme, il est nécessaire d’examiner complètement tous ses composants et de tracer son fonctionnement pas à pas.

Veuillez noter que les propriétés des fonctions spéciales des différents programmes d’application (Expert Advisors, scripts, indicateurs) sont différentes.

Maintenant, nous allons analyser comment fonctionne un EA.

Exemple d’un simple EA ( simple.mq4 )

 

{xtypo_code}//——————————————————————–
// simple.mq4
// Pour être utilisé comme exemple dans le livre de MQL4.
//——————————————————————–  
int Count = 0 ;                             // Global variable
//——————————————————————–
int init ()                                 // Spec. Funct. init ()
{
Alert ( ” Function init() triggered at start ” ) ;     // Alert  
return ;                             // Exit init()
}
//——————————————————————–
int start ()                                 // Spec. funct. start()
{
double Price  = Bid ;                     // Local variable
Count ++;                             // Tick counter
Alert ( ” New tick ” , Count , ”    Price = ” , Price ) ; // Alert
return ;                             // Exit start()
}
//——————————————————————–
int deinit ()                                 // Spec. funct. deinit()
{
Alert ( “Function  deinit() triggered at deinitialization ” ) ;     // Alert
return ;                                     // Exit deinit()
}
//——————————————————————– {/xtypo_code}

 

1. 1. Au moment où un programme est joint à un graphique, le Terminal Client passe le contrôle au programme et ensuite le programme va commencer son exécution.

L’exécution du programme commence à partir de l’entête.

L’entête ne contient qu’une seule ligne :

{xtypo_code}int Count = 0 ;                     // Global variable {/xtypo_code}

Dans cette ligne, la variable globale “Count” est déclarée et initialisée à 0.

(Les variables locales et globales sont analysées en détail dans la section Types de Variables . Il convient de noter ici, que l’algorithme utilisé dans ce programme d’exemple exige la déclaration de la variable Count comme globale, c’est pourquoi elle ne peut être déclarée dans une fonction, elle doit être déclarée en dehors de la description des fonctions, c’est à dire dans l’entête ; de sorte que la valeur de la variable globale Count sera disponible à partir de n’importe quelle partie du programme.)

2. 2. Après l’exécution de l’entête du programme, la fonction spéciale init() sera lancée pour l’exécution.

Veuillez noter que cet appel de fonction n’est pas contenu dans un code de programme.

Le début de l’exécution de init() lorsque un EA est joint à un graphique est la propriété spécifique de la fonction.

Le Terminal Client fera appel à init() pour exécution simplement parce que le code du programme contient sa description.

Dans le programme analysé, la description de la fonction spéciale init() est la suivante :

{xtypo_code} int init ()                                 // Spec. Funct. init ()
{
Alert ( ” Function init() triggered at start ” ) ;     // Alert
return ;                             // Exit init()
}  {/xtypo_code}

Le corps de la fonction ne contient que deux opérateurs.

2.1 La fonction Alert() montre une fenêtre d’information :

Fonction init() déclenchée au début

2.2 L’opérateur termine l’opération de la fonction spéciale init()

À la suite de l’exécution de init(), un message d’information sera produit.

Dans les programmes réellement utilisés, un tel algorithme est très rare, parce que l’utilisation de ce init() n’est pas d’une grande utilitée.  Vraiment, il n’y a pas de sens à utiliser une fonction qui indique à un opérateur qu’il est en cours d’exécution. Ici l’algorithme est utilisé uniquement pour la visualisation de l’exécution de init().

Attention: la fonction spéciale init() est exécutée une seule fois dans un programme. L’exécution de la fonction a lieu au début du fonctionnement du programme, après qu’un entête ait été traité. Quand l’opérateur return est exécuté dans la fonction spéciale init(), le programme renvoie le contrôle au Terminal Client.

3. Le Terminal Client détecte la description de la fonction spéciale start() dans le programme :

{xtypo_code} int start ()                             // Special funct. int start ()
{
double Price  = Bid ;                 // Local variable
Count ++;  
Alert ( ” New tick ” , Count , ” Price = ” , Price) ;     // Alert
return ;                             // Exit start()
} {/xtypo_code}

3.1. Le contrôle est tenu par le terminal client.

Le Terminal Client attend un nouveau tick et ne démarre pas les fonctions du programme tant qu’un nouveau tick n’arrive pas.

Cela signifie que le programme ne fonctionne pas pendant un certain temps, c’est à dire pas d’actions réalisées par lui. Une pause apparaît, bien qu’il n’y ait ni commande directe ou indirecte pour effectuer cette pause.

La nécessité d’attendre un tick est la propriété spécifique de start() et il n’existe aucun moyen pour influencer cette propriété (par exemple, de le désactiver).

Le programme sera en attente pour le contrôle jusqu’à ce qu’un nouveau tick arrive.

Quand un nouveau tick arrive, le Terminal Client passe le contrôle au programme, à savoir à la fonction spéciale start() (dans ce cas, conformément à la propriété de la fonction start() de l’EA).

À la suite son exécution démarre.

3.2 (1). Dans la ligne

{xtypo_code}double Price  = Bid ;             // Local variable{/xtypo_code}

les actions suivantes sont effectuées :

32.1(1). Déclaration d’une variable locale Price (voir types de variables).

La valeur de ces variables locales seront disponibles à partir de n’importe quelle partie de la fonction spéciale start().

32.2(1). Exécution de l’opérateur d’affectation.

La valeur actuelle du prix  offert sera affectée à la variable Price.

Le nouveau prix de valeur apparaît chaque fois qu’un nouveau tick arrive (par exemple, au premier tick un prix de titre égal à 1.2744).

33(1). Puis la ligne suivante est exécutée :

{xtypo_code}Count ++;{/xtypo_code}

Cette façon inhabituelle d’écrire signifie Count = Count +1; (analogie au langage C)

Au moment de passer le contrôle de cette ligne, la valeur de la variable Count est égal à zéro. À la suite de l’exécution Count++, la valeur de la variable Count sera augmentée de un. Ainsi, au moment de passer le contrôle à la ligne suivante, la valeur de Count sera égale à 1.

34(1).  La ligne suivante contient l’appel à la fonction Alert() :

{xtypo_code}Alert ( ” New tick ” , Count , ” Price = ” , Price ) ;             // Alert  {/xtypo_code}

La fonction va écrire toutes les constantes et les variables énumérées entre les parenthèses.

À la première exécution de la fonction start(), le programme va écrire New tick, puis se réfère-vous à la variable Count pour obtenir sa valeur (à la première exécution cette valeur est égale à 1), écrit cette valeur, puis écrit Price = et se refère à la variable Price pour obtenir sa valeur (dans notre exemple, il est 1,2744) et lécrire.

En conséquence, la ligne suivante sera écrite :
{xtypo_code}New tick 1 Price = 1.2744{/xtypo_code}

35(1). Opérateur

{xtypo_code} return ;             // Exit start(){/xtypo_code}

termine l’opération de la fonction spéciale start().

36. Le contrôle est retourné au Terminal Client (jusqu’à ce qu’un nouveau tick arrive).

Voilà comment la fonction start() d’un EA est exécuté.

Lorsque l’exécution est terminée, la fonction spéciale start() retourne le contrôle au Terminal Client et quand un nouveau tick arrive, le Terminal Client démarre son fonctionnement une fois de plus.

Ce processus (à partir de l’exécution de la fonction start() et renvoi du contrôle au Terminal Client) peut se poursuivre pendant une longue période – plusieurs jours ou semaines. Pendant tout ce temps la fonction spéciale start() sera exécutée de temps à autre.

En fonction des paramètres d’environnement (nouveaux prix, le temps, les conditions de trading, etc) dans la fonction spéciale start(), différentes actions comme ouvrir ou  modifier les ordres peuvent être effectuées.

37. A partir du moment de la réception d’un nouveau tick, les actions des points 32-36 sont répétés.

Toutefois, seule la séquence des opérateurs exécutés se répète, mais les variables seront affectées des nouvelles valeurs à chaque fois. Voyons les différences entre la première et la deuxième exécution de la fonction spéciale start().

32(2). Dans la ligne

{xtypo_code}double Price  = Bid ; // Local variable{/xtypo_code}

les actions suivantes sont effectuées :

32.1(2). Déclaration d’une variable locale Price (inchangé).

32.2(2). Exécution de l’opérateur d’affectation.

La valeur actuelle du prix Bid sera affectée à la variable Price (une nouvelle valeur de cotation apparaît chaque fois qu’un nouveau tick arrive, par exemple au deuxième tick le prix du titre sera égal à 1,2745) (il ya des changements).

33(2). Puis la ligne suivante sera exécutée :

{xtypo_code}Count ++;{/xtypo_code}

Au moment de passer le contrôle de cette ligne, la valeur de la variable Count (après la première exécution de la fonction start()) est égal à 1.

À la suite de l’exécution de Count++, la valeur de Count sera augmentée de un.

Ainsi, lors de la deuxième exécution, Count sera égal à 2 (modifié).

34 (2). Fonction Alert() :

{xtypo_code}Alert ( ” New tick ” , Count , ” Price = ” , Price ) ;         // Alert {/xtypo_code}

écrit toutes les constantes et variables (les nouvelles valeurs) énumérées entre parenthèses.

A la deuxième exécution de start() le programme va écrire New tick, puis se réfère à la variable Count pour obtenir sa valeur (en deuxième exécution, elle est égale à 2), écrire cette valeur, puis écrire Price = et indiquer la variable Price, obtenir sa valeur (dans notre exemple 1,2745) et l’écrire (modifiée).

En conséquence, la ligne suivante sera écrite :
{xtypo_code}New tick 2 Price = 1.2745{/xtypo_code}

35(2). Opérateur
{xtypo_code}return ;                         // Exit start(){/xtypo_code}

termine l’opération de la fonction start() (sans changement).

36(2). Le contrôle est retourné au terminal client pour attendre un nouveau tick.

37 (2). Puis c’est répété à nouveau.
Dans la troisième exécution start() les variables auront de nouvelles valeurs et seront écrites par la fonction Alert(), c’est à dire le programme reprend les points 32-36 (3).

Et puis ainsi de suite : 32 – 36 (4), 32 – 36 (5 ),..( 6) .. (7) .. (8) …

Si un utilisateur n’effectue aucune action, ce processus sera répété à l’infini.

À la suite de l’opération start() dans ce programme, nous allons voir l’historique du changement des prix des ticks.

Les événements suivants se reproduiront tant que l’utilisateur n’aura pas décidé de mettre fin au programme en forçant manuellement le programme à sortir du graphique.

4. Le Terminal Client passe le contrôle à la fonction spéciale deinit() (conformément à ses propriétés).

{xtypo_code} int deinit ()                                 // Special funct. int deinit ()
{
Alert ( ” Function deinit() triggered at exit ” ) ;     // Alert
return ;                             // Exit deinit()
}{/xtypo_code}

Il n’ya que deux opérateurs dans le corps de la fonction.

41. Alert() écrira :

Fonction deinit() déclenchée à la sortie

42. Opérateur return termine le fonctionnement de deinit().

La fonction deinit() est lancée pour l’exécution par le terminal client une seule fois, après que Alert() ci-dessus apparaîsse dans la fenêtre d’information et le programme sera supprimé du graphique.

5. Ici se termine l’exécution des EA.

Insérez cet exemple de programme pour n’importe quel graphique et le lancer.

Le programme d’exploitation affiche une fenêtre contenant toutes les alertes générées par la fonction Alert(). Par le contenu de la fenêtre des alertes, il est facile de comprendre quelle fonction spéciale est liée à telle ou telle entrée.

Fig. 35. Résultats d’exploitation du programme simple.mq4 .

 

Dans cet exemple, vous pouvez facilement voir que le programme est exécuté conformément aux propriétés des fonctions spéciales décrites dans Fonctions Spéciales.

Terminer le programme et le relancer.

Après avoir essayé plusieurs fois, vous obtiendrez l’expérience du fonctionnement d’un programme MQL4. D’autres programmes que vous écrivez vous-même seront également construits en conformité avec la structure décrite et pour le démarrage de leur exécution, vous devrez également le joindre à un graphique.

Comprendre tous les concepts, les règles et les processus de création de programmes en MQL4 sera alors facile et agréable.

 

Retour sommaire cours MQL4

Traduction: Jean Marc Venet
Source: http://book.mql4.com/programm/execution
“MQL4 is a trade mark of MetaQuotes Software Corp. and all related materials are reserved for MetaQuotes”

Fonctions spéciales MQL4

Fonctions spéciales

La particularité des programmes destinés à fonctionner dans le Terminal Client MT4 est leur interaction avec des informations constamment mises à jour en mode temps réel.

Dans le langage MQL4, cette particularité se reflète sous la forme de trois fonctions spéciales: init (), start () et deinit ().

Les fonctions spéciales sont des fonctions avec des noms prédéfinis init(), start() et deinit() possédant des propriétés particulières spécifiques.

Propriétés des fonctions spéciales

 

Propriété commune des fonctions spéciales

La principale propriété de l’ensemble des fonctions spéciales est leur exécution dans un programme sous certaines conditions, sans l’aide d’appel de fonction spéciale du programme. Les fonctions spéciales sont appelées à être exécutées par le Terminal Client. Si un programme contient la description d’une fonction spéciale, il sera appelé (et exécuté), conformément aux conditions d’appel (propriétés spécifiques).

Les fonctions spéciales sont appelées à être exécutées  par le Terminal Client.

Propriétés spécifiques des fonctions spéciales

 

Fonction spéciale init().

La propriété spécifique de la fonction spéciale init() est son exécution à l’initialisation du programme.  Si un programme contient la description de la fonction spéciale init(), elle sera appelée (et exécutée) au lancement du programme. S’il n’ya pas de fonction spéciale init() dans un programme, aucune action ne sera effectuée au lancement du programme.

Dans les Expert Advisors (EA), la fonction spéciale init() est appelée (et exécutée) après le démarrage du Terminal Client et le téléchargement des données historiques, après avoir changé de titre et/ou la période du graphique, après la recompilation du programme dans MetaEditor, après avoir changé les paramètres d’entrée dans la fenêtre de configuration des EA et après changement du compte.

Dans les scripts, la fonction spéciale init() est aussi appelée (et exécutée) immédiatement après qu’ il soit appliqué à un graphique.

Dans les indicateurs personnalisés, la fonction spéciale init() est appelée (et exécutée) immédiatement après le démarrage du Terminal Client, après avoir changé de titre et/ou la période du graphique, après la recompilation du programme dans MetaEditor et après avoir changé les paramètres d’entrée dans la fenêtre de configuration de l’indicateur personnalisé.

Fonction spéciale start().

Les propriétés spécifiques de la fonction spéciale start() diffèrent selon le type de programme exécutable. Dans les EA, la fonction spéciale start() est appelée (et exécutée) immédiatement après l’arrivée d’une nouvelle cotation.

Si une nouvelle cotation arrive durant l’exécution de la fonction spéciale start(), cette cotation sera ignorée, càd que la fonction spéciale start() ne sera pas appelée pour exécution lorsqu’une telle cotation survient.

Toutes les cotations reçues au cours de l’exécution de la fonction spéciale start() seront ignorées.

Le démarrage de la fonction spéciale start() pour exécution n’est assurée par le Terminal Client qu’à la condition que la session de la précédente opération ait été effectuée, le contrôle étant retourné au Terminal Client et la fonction spéciale start() est en attente d’une nouvelle cotation.

La possibilité d’appeler et d’exécuter la fonction spéciale start() est influencée par l’état du bouton “Activer / désactiver les EA”. Si ce bouton est dans l’état de désactivation des EA, le Terminal Client n’appellera pas pour exécution la fonction spéciale start() indépendamment du fait que de nouvelles cotations arrivent ou non. Toutefois, le changement de l’état -activé à désactivé- du bouton ne met pas fin à la session de fonctionnement courante de la fonction spéciale start().

La fonction spéciale start() n’est pas appelée par le Terminal Client si la  fenêtre  des propriétés des EA est ouverte. La fenêtre des propriétés des EA ne peut être ouverte que lorsque la fonction spéciale start() est en attente d’une nouvelle cotation. Cette fenêtre ne peut pas être ouverte durant l’exécution d’une session de la fonction spéciale start() des EA.

Dans les scripts, la fonction spéciale start() est appelée (et exécutée)  immédiatement après l’initialisation du programme dans la fonction spéciale init ().

Dans les indicateurs personnalisés la fonction spéciale start() est appelée (et exécutée) immédiatement après qu’une nouvelle cotation survienne, immédiatement après avoir été attachée à un graphique, lors du changement de taille de la fenêtre du titre, lors du passage d’un titre à l’autre, lors du démarrage du Terminal Client (si au cours de la session précédente un indicateur a été fixé à un graphique), après avoir changé un symbole et la période d’un graphique en cours, indépendamment du fait de savoir si de nouvelles cotations surviennent ou non.

La fin d’une session courante d’exécution de start() pour tous les types de programmes peut être réalisée quand un programme est retiré d’un graphique, où le titre et/ou la période de graphique sont modifiés, quand un compte est modifié / un graphique est fermé et à la suite de fin d’opération du terminal client.

Si la fonction spéciale start() a été exécutée au cours de la commande de fermeture, le temps disponible pour le terminal pour achever l’exécution de la fonction est de 2,5 secondes.

Si après la commande de fermeture, la fonction spéciale start() poursuit son opération plus longtemps que le délai indiqué, elle sera forcée à l’arrêt par le Terminal Client.

Fonctions spéciale deinit().

La fonction spécifique de la  fonction spéciale deinit() est son exécution à la fin du programme (terminaison).

Si un programme contient la description de la fonction spéciale deinit(), elle sera appelée (et exécutée) à la fermeture du programme.

Si un programme ne contient pas cette fonction spéciale deinit(), aucune action ne sera réalisée lors de l’arrêt du programme.

La fonction spéciale deinit() est également appelée pour exécution par le Terminal Client à la fermeture du terminal, quand une fenêtre de titre est fermée, juste avant de changer de titre et/ou la période du graphique, à une recompilation réussie du programme dans MetaEditor, lors de la modification des paramètres d’entrée , ainsi que quand le compte est modifié.

Dans les EA et les scripts, l’arrêt du programme avec l’appel nécessaire de la fonction spéciale deinit() peut se produire lors de l’attachement d’un graphique à un nouveau programme du même type qui remplace le précédent. Dans les indicateurs personnalisés la fonction spéciale deinit() n’est pas exécutée quand un nouvel indicateur est joint à un graphique.

Plusieurs indicateurs peuvent fonctionner sur chaque fenêtre spécifique à un sous-jaccent particulier, c’est pourquoi la fixation d’un nouvel indicateur à un graphique n’entraîne pas la fermeture d’autres indicateurs avec l’appel à  deinit().

Le temps d’exécution de deinit() est limité à 2,5 secondes.

Si le code de la fonction spéciale deinit() est exécuté plus longtemps, le Terminal Client forcera la  fin de l’exécution de la fonction spéciale deinit() et le fonctionnement du programme.

Exigences pour les fonctions spéciales

Les fonctions spéciales init() et deinit() peuvent être absentent dans un programme. L’ordonnancement des descriptions des fonctions spéciales dans un programme n’a pas d’importance. Les fonctions spéciales peuvent être appelées depuis n’importe quelle partie du programme, conformément à l’ordonnancement général des appels de fonction.

Les fonctions spéciales peuvent intégrer des paramètres. Cependant, lorsque ces fonctions sont appelées par le Terminal Client, aucun paramètre ne sera envoyé de l’extérieur, les valeurs par défaut étant seulement utilisées.

Les fonctions spéciales init() et deinit() doivent terminer leur fonctionnement le plus rapidement possible et en aucun cas fonctionner dans une voie essayant de démarrer l’opération complète  avant d’appeler la fonction spéciale start().

 

Ordre d’utilisation des fonctions spéciales

Les développeurs ont présenté aux programmeurs un outil très pratique : lors du démarrage d’un programme, tout d’abord init() est exécuté, après cela la principale tâche est effectuée avec l’aide de la fonction start(), et quand un utilisateur termine son travail, le fonction deinit() sera lancée avant l’arrêt du programme.

Le code principal d’un programme doit être contenu dans la fonction start().

Tous les opérateurs, et les appels des fonctions intégrées et personnalisées et tous les calculs nécessaires devront être effectuées à l’intérieur de cette fonction.

Dans le même temps, il faut bien comprendre le rôle des fonctions personnalisées.

La description des fonctions personnalisées est située dans un code de programme en dehors de la description des fonctions spéciales, mais si une fonction personnalisée est appelée pour exécution, une fonction spéciale ne termine pas son opération. Cela signifie que le contrôle est passé de temps en temps à la fonction personnalisée, mais la fonction personnalisée opère elle-même au sein d’une fonction spéciale qui l’a appelée.

Ainsi, dans le processus de l’exécution du programme la fonction spéciale fonctionne toujours (conformément à leurs propriétés spécifiques) et la fonction personnalisée, sont exécutées lorsqu’elles sont appelées par des fonctions spéciales.

Si un programmeur n’ pas l’intention d’utiliser les fonctions spéciales, il peut refuser de les utiliser dans un programme. Dans un tel cas, le terminal client ne l’appellera pas. Dans l’absolu, un programme normal contient l’ensemble des trois fonctions spéciales. Un programme qui n’a pas init() ou deinit() ou ces deux fonctions est également considéré comme normal. Si aucune des fonctions spéciales n’est utilisée dans un programme, ce programme ne sera pas exécuté.

Le Terminal Client n’appelle pour exécution, que les fonctions spéciales en fonction de leurs propriétés.

Les fonctions personnalisées ne sont pas appelées par le terminal client. C’est pourquoi si un programme ne contient pas de fonctions spéciales (et ne contient que des fonctions personnalisées), il ne sera jamais appelé pour exécution.

Il n’est pas recommandé d’appeler la fonction start() à partir de la fonction spéciale init() ou effectuer des opérations de trading à partir de la fonction init(), car au cours de l’initialisation des valeurs d’information de l’environnement, les paramètres peuvent ne pas être prêts (information sur les graphiques, les prix du marché, etc.)

Les articles Exécution de programme et les Exemples de mise en œuvre, contiennent plusieurs exemples pratiques qui permettront de voir les propriétés des fonctions spéciales.

Retour sommaire cours MQL4

Traduction: Jean Marc Venet
Source: http://book.mql4.com/programm/special
“MQL4 is a trade mark of MetaQuotes Software Corp. and all related materials are reserved for MetaQuotes”

Comment spécifier votre stratégie de trading à un développeur

 

Depuis la création du service de programmation de Trading Automatique, nous avons travaillé avec de nombreux traders différents et nous avons fait le constat que la phase de spécification du système est souvent la plus délicate, voire la plus longue. Pour éviter les malentendus, nous avons mis en place un système de formulaire à remplir pour aider le trader à formuler sa demande, mais ceci n’est pas toujours efficace. Voici donc un petit article dont la lecture est conseillée avant de réaliser votre demande de programmation.

Tout d’abord, ayez bien à l’esprit que le programme va être codé par une personne qui n’a initialement pas la moindre idée de votre stratégie. Vous devriez donc spécifier tous les petits détails : comme les paramètres des indicateurs, la distance des ordres stops, le nombre maximal de positions ouvertes, l’algorithme de trailing stop, etc. Vos spécifications doit contenir la description de la marche à suivre en fonction de chaque évènement significatif : activation d’un ordre stop, apparition d’un signal d’entrée lorsqu’une position est déjà ouverte, que faire lors du redémarrage d’un EA après une déconnexion, etc.

Vous devriez comprendre que votre ordinateur ne peut ne deviner, ni assumer des décisions indépendantes. Il tradera seulement en fonction de vos règles. Si une situation non prévue par votre algorithme survient, votre EA ne fera rien.

Je sens bien que vous êtes en train de vous dire que ceci est logique et que vous l’avez bien compris. Pourtant ce n’est pas ce que nous observons en pratique. Prenons donc un exemple tiré de cet article disponible sur MQL4.com .

C’est un échange typique bien que largement exagéré pouvant survenir lorsqu’un trader commande un EA à un développeur qui n’ira pas plus loin que les spécifications fournies. Bien évidemment, nous ne réagissons pas comme ça et nous demanderons les détails supplémentaires. Mais le but ici est d’exagérer les erreurs pour les mettre en valeur. N’oubliez pas qu’au final, une spécification bien faite dès le départ permet de faire gagner du temps et donc de l’argent à la fois au trader et au développeur.

 

Trader :

Bonjour! Je veux commander un EA.
L’EA doit ouvrir une position au croisement de la MM(9) et MM(18). Si la moyenne rapide croise vers le haut la moyenne lente, une position Buy doit être ouverte. Et vice versa.
Combien ça coute?

 

Développeur :

Pour vous donner un devis, j’ai besoins des spécifications détaillées. Je dirais environ xx euros en fonctions de ce que j’ai là.

 

Trader :

Je vous ai déjà tout détaillé dans mon mail précédent. L’EA doit ouvrir une position au croisement de la MM(9) et MM(18). Si la moyenne rapide croise vers le haut la moyenne lente, une position Buy doit être ouverte. Et vice versa.

 

Développeur :

OK, voici votre EA.

 

Trader :

C’est quoi ce travail? Ce n’est pas un EA ça! Pourquoi il y a autant de positions ouvertes et jamais clôturées. Etes vous réellement un programmeur?

 

Développeur :

Le nombre de positions ouvertes correspond au nombre de croisements. Testez votre EA en mode visuel du backtest et vous verrez bien qu’une position est ouverte à chaque croisement.Si le croisement est vers le haut, une position BUY est ouverte, si le croisement est vers le bas c’est une position SELL. Votre spécification ne dit rien sur la fermeture des ordres.

 

Trader :

J’ai oublié de vous le dire: si il y a une position ouverte, elle devrait être fermée lors d’un croisement inverse. Seulement une position peut être ouverte à un moment donnée. Et pour chaque position un stop loss devrait être placé à une distance paramétrable.

 

Developpeur :

OK, ceci est beaucoup plus clair. Voici la nouvelle version.

 

Trader :

Pourquoi il y a une position Buy ouverte ici? Il n’y a pas de croisement!

Developpeur :

Il y avait bien un croisement mais il a disparu. Le graphique ne reflète que les valeur des indicateurs sur les barres fermées et vous devez regarder le graphique en temps réel pour voir évoluer au fur et à mesure la valeur de l’indicateur sur la dernière barre. Croyez moi, il y avait bel et bien une intersection au moment de l’ouverture de la barre.

Si vous le souhaitez, nous pouvons modifier l’EA pour qu’il prenne en compte la valeur des indicateurs seulement à la clôture des bougies. De cette manière, tous les signaux seront visibles sur le graphique.


Trader :

Essayons.
Et puis je optimiser les valeurs des moyennes mobiles, des stop loss et take profit?


Developpeur :

Voici la troisième version :
– la recherche des signaux est réalisée sur les bougies clôturées (1ère et 2 ème)
– les paramètres des moyennes mobiles, stop loss et take profit sont désormais tous des paramètres à part entière que vous pouvez modifier et optimiser comme bon vous semble.


Trader :

Maintenant ça ressemble à ce que je désirais réellement. Mais quand je démarre plusieurs EAs, seulement l’un des deux trade. Et de temps en temps ils ferment les positions des autres EAs!


Developpeur :

Dans cette quatrième version j’ai ajouté la séparation des ordres en fonction du magic number. Si vous démarrez plusieurs EAs sur une même paire, mettez une valeur de magic number différente pour chaque EA.


Trader :

C’est enfin parfait.

 

Pour conclure cet exemple, voici ce que doivent être les spécifications pour que le programmeur fournisse l’équivalent de la quatrième version au premier coup (faisant économiser donc au passage de l’argent au trader) :

 

  • L’EA devrait contrôler seulement ses positions et ne devrait pas interagir avec les positions ouvertes manuellement.
  • Si il n’y a pas une position en cours :
    • si la MM courte croise à la hausse la MM lente, une position BUY est ouverte;
    • si la MM courte croise à la baisse la MM lente, une position SELL est ouverte;
  • Si il y a une position ouverte par l’EA :
    • position BUY:
      • si la MM rapide croise la MM longue à la baisse, la position Buy est cloturée et une position Sell est ouverte.
    • position SELL:
      • si la MM rapide croise la MM longue à la hausse, la position Buy est cloturée et une position Sell est ouverte.
  • Les paramètres des MM (période, etc) doivent être des paramètres modifiables
  • Les valeurs des indicateurs doit être calculées en fonction du timeframe affiché par le graphique.
  • La tailles des positions est déterminée par un paramètre modifiable
  • Les stop loss et take profit sont placés à l’ouverture de l’ordre et leur valeur doit être modifiable par paramètres.
  • Il devrait y avoir un paramètre permettant d’activer ou de désactiver les EAs

 

Afin d’aider ce processus de spécification nous fournissons un formulaire à remplir. Si toutefois, même aidé par notre formulaire, écrire sur papier et mettre en forme l’ensemble des règles de votre programme de trading vous semble insurmontable ou que vous avez des questions, n’hésitez pas à nous contacter. Nous ne sommes pas des programmeurs robots tel que décrit dans cet exemple et du moment que vous avez compris le message de cet article, nous serons heureux de travailler avec vous pour vous aider à y voir plus clair.

MQL4 pour les nuls

 

Il n’est jamais trop tard pour se mettre à la programmation et à MQL4! Si l’arrêt de la traduction du cours MQL4 vous a laissé sur votre faim, voici de quoi vous consoler.  En attendant que MQL5 soit complètement opérationnel, voici un guide d’apprentissage de MQL4 traduit par Henri Baltzer du site Eole Trading que tout le monde peut remercier. Vous pouvez retrouver les différents chapitres sur le forum d’Eole ici.

Edit: La version complete “livre” du MQL4 Pour Les Nuls est désormais disponible en boutique!

MQL4 Pour Les Nuls

 

Comment traiter les erreurs 146: Trade Context is busy

 

Si vous programmez ou utilisez des EA ou scripts MQL4 sous Metatrader vous êtes probablement déjà tombé sur la fameuse erreur 146: “Trade Context is busy”. Et cette erreur peut être un véritable casse tête pour le néophyte car son apparition semble aléatoire… ce qui est la pire des choses pouvant arriver à un programmeur.

Je me suis rendu compte au détours de forums que beaucoup de choses fausses sont dites à son propos. Non cette erreur 146 n’est pas une fatalité. Pas mal de monde l’attribue à une manipulation de leur broker senser faire échouer leur trade. Alors, certes je n’ai pas la preuve que cette situation n’arrive jamais, mais une chose est sure, vous pourrez éliminer à 99% l’apparition de cette erreur si vous comprenez son origine et prenez les mesures nécessaires.

Fonctionnement de la plateforme Metatrader

Pour cela il faut comprendre le fonctionnement de la plateforme Metatrader. Lorsque votre EA ou script MQL4 passe un ordre au sens large (ouverture, fermeture, modification, etc), il passe la main à la plateforme (terminal client) qui va elle même passer l’ordre, attendre sa confirmation puis repasser la main au programme de trading, à savoir votre EA ou script. Vous pouvez déjà en déduire que l’exécution de votre EA ou script s’arrête tant que le terminal client n’a pas terminé la séquence de passage d’ordre se terminant par un acquittement positif ou négatif (ordre ayant échoué) venant du serveur de votre broker.

Le deuxième point important à noter est que le terminal client ne peut fonctionner en multi-threading, c’est à dire ne peut exécuter plusieurs ordres en parallèle. Si il reçoit deux ordres en même temps venant de deux EAs différents (puisqu’un EA ne peut pas envoyer deux ordres en même temps), il ne pourra en exécuter un. Qu’arrivera-t-il au deuxième? Vous aurez deviné, il recevra la fameuse erreur 146, “trade context is busy”.

La solution est donc de trouver un moyen d’empêcher le passage d’un ordre par un EA ou script si le termnal client est déjà occupé à traiter un autre ordre. Pour cela il existe deux solutions. La manière forte, brute, et la manière élégante. Vous aurez compris que la manière brute est la plus facile à mettre en place et l’élégante la plus compliquée.

La manière forte pour résoudre l’erreur 146

Commençons par la manière forte. Etant donné que votre EA recevra cette erreur tant que le trade précédant ne sera pas exécuté complètement par la plateforme, il suffit de continuer à demander à la plateforme d’exécuter le trade jusqu’à ce qu’il soit enfin exécuté. Vous pouvez obtenir le résultat d’un passage d’ordre grâce à la valeur retournée par la fonction. Grâce à cela, il suffit de faire une boucle demandant le passage d’ordre tant qu’il ne sera pas éxécuté en faisant attention toutefois à limité le nombre de demande et à introduire une temporisation grâce à la fonction Sleep.

La manière élégante pour résoudre l’erreur 146

Les manières élégantes visent à ne pas utiliser la force brute des demandes en boucle. On ne passe un ordre seulement si le terminal client est disponible, ce qui peut être déduit grâce à la fonction IsTradeContextBusy. Pour étudier de manière approfondie des solutions élégantes à ce problème, je vous conseille cet article de la communauté MQL4 qui fera éventuellement l’objet d’un traduction si cela vous intéresse (à vos commentaires…).

 

Structure des Programmes

 

Dans les premières sections, nous avons appris quelques notions basiques de la programmation avec le langage MQL4. Maintenant, étudions comment un programme est organisé en général.  Dans cet objectif, nous étudierons son schéma structurel.

Comme nous l’avons déjà mentionné, le code principal écrit par un programmeur est placé à l’intérieur des fonctions spéciales et définies par l’utilisateur. Dans la section Fonctions nous avons discuté des notion et des propriétés des fonctions intégrées et définies par l’utilisateur. En résumé: une fonction définie par l’utilisateur dispose d’une description, et l’appel de la fonction est utilisé pour le début de son exécution dans un programme. Toute fonction intégrée ou définie par l’utilisateur peut être exécutée seulement après avoir été appelée. On dit que  la fonction est appelée par le programme pour exécution.

Les propriétés des fonctions spéciales sont décrites en détail dans une section ultérieure. Ici, nous étudierons seulement les principales informations à leur sujet. Une fonction spéciale est une fonction appelée à être exécutée par le terminal client. À la différence des fonctions communes, les fonctions spéciales ont seulement une description et leur appel n’est pas spécifié dans le programme. Les fonctions spéciales sont appelées à être exécutées par le terminal client (il y a aussi une possibilité technique de faire appel aux fonctions spéciales à partir d’un programme, mais nous considérons cette méthode comme étant incorrecte et nous en discuterons donc pas ici). Quand un programme est lancé pour exécution dans une fenêtre de sécurité, le terminal client passe le contrôle à l’une des fonctions spéciales. En conséquence, cette fonction est exécutée.

La règle de programmation en MQL4 est la suivante:

{xtypo_alert}Le code du programme doit être écrit à l’intérieur des fonctions.{/xtypo_alert}

 

Cela signifie que les  lignes de programme (les opérateurs et les appels de fonction) qui sont à l’extérieur de la fonction ne peuvent pas être exécutées. Lors de la tentative de compilation d’un tel programme, lr MetaEditor affiche le message d’erreur correspondant et le fichier exécutable *. ex4 n’apparaît pas comme un résultat de la compilation.

 Considérons les schéma structurel d’un programme classique – Expert Advisor:

 

 

Fig. 31. Schéma fonctionnel d’un programme (Expert Advisor).

Les plus grands blocs d’un programme écrit en MQL4 sont:

1. L’en-tête d’un programme.

2. La fonction spéciale init().

3. La fonction spéciale start().

4. La fonction spéciale deinit().

5. Les fonctions définies par les utilisateurs.

 

Nous analyserons seulement le contenu interne de ces blocs fonctionnels d’un programme, alors que tous les objets externes (par exemple, le domaine d’information du terminal du client ou du matériel) sera hors de notre champ d’intérêt.

 

L’environnement d’information du Terminal Client MetaTrader 4

L’environnement d’information du terminal client MT4 n’est pas une partie composante du programme. L’environnement d’information est un ensemble de paramètres disponibles pour être traités par un programme. Par exemple, c’est le nouveau prix d’un titre arrivant avec le nouveau tick, le volume cumulé à chaque nouveau tick, des informations sur les prix maximum et minimum de l’historique des bars, des paramètres qui caractérisent les conditions commerciales offertes par le centre de traitement (dealing center), etc. L’environnement d’information est toujours sauvegardé et  mis à jour par le terminal client connecté avec le serveur à chaque nouveau tick.

 

Structure du programme

 

Partie d’en-tête

La partie d’en-tête est constituée de plusieurs lignes au début d’un programme (à partir de la première ligne). Ces lignes contiennent des informations générales sur le programme. Par exemple, cette partie comprend des lignes de déclaration et d’initialisation des variables globales ( la nécessité d’inclure telle ou telle information dans l’en-tête sera discutée plus tard). La fin de la partie d’en-tête peut être indiquée lorsque la ligne suivante contient une description de fonction (définie par l’utilisateur ou spéciales).


Fonctions spéciales

Habituellement, après la partie d’en-tête du programme, les fonctions spéciales sont décrites. La description de la fonction spéciale ressemble à la description habituelle d’une fonction définie par l’utilisateur, mais les fonctions spéciales ont des noms prédéfinis : init (), start () et deinit (). Les fonctions spéciales sont un bloc de calculs et sont en relations avec l’environnement d’information du terminal client et les fonctions définies par l’utilisateur. Les fonctions spéciales sont décrites en détail dans une section ultérieure.

Fonctions définies par l’utilisateur

La description des fonctions définies par l’utilisateur est habituellement donnée après la description des fonctions spéciales. Le nombre de fonctions définies par l’utilisateur dans un programme n’est pas limité. Le schéma ne contient que deux fonctions définies par l’utilisateur, mais un programme peut en contenir 10 ou 500, ou aucune. Si aucune fonction définie par l’utilisateur est utilisée dans un programme, le programme aura une structure simplifiée: l’en-tête et la description des fonctions spéciales.


Fonctions standard

Comme indiqué précédemment, les fonctions standard ne peuvent être présentées que comme un appel de fonction. Les fonctions standards, comme les fonctions spéciales et définies par l’utilisateur, ont une description. Cependant, cette description n’est pas donnée dans le programme (c’est la raison pour laquelle ne figurent pas dans le schéma). La description d’une fonction standard est cachée, non visible pour un programmeur et ne peuvent donc pas être changée. Bien qu’elle est disponible pour le MetaEditor. Au cours de la compilation du programme, le MetaEditor fera un fichier exécutable, dans lequel toutes les fonctions standards appelées seront exécutées correctement.

 

Disposition des parties dans un programme

L’en-tête devrait être située dans les premières lignes. La disposition des particuliers et des fonctions définies par l’utilisateur descriptions n’a pas d’importance. Fig. 32 montre une disposition des blocs fonctionnels, à savoir: – la tête part, des fonctions, fonctions définies par l’utilisateur. Fig. 33 montre la structure du programme d’autres variantes. Dans tous les exemples de la tête la première partie, tandis que les fonctions peuvent être décrites dans un ordre aléatoire.

La partie d’en-tête devrait être située dans les premières lignes. La disposition de la description des fonctions spéciales et définies par l’utilisateur descriptions n’a pas d’importance. La Fig. 32 montre une disposition des blocs fonctionnels, à savoir: l’en-tête, les fonctions spéciales et les fonctions définies par l’utilisateur. La Fig. 33 montre d’autres variantes de la structure du programme. Dans tous les exemples, l’en-tête vient en première partie, tandis que les fonctions peuvent être décrites dans un ordre aléatoire.

 

 

Fig. 32. Organisation habituelle des blocs fonctionnels dans un programme (recommandé).

 

 

Fig. 33. Des possibilités d’organiser des blocs fonctionnels dans un programme (ordre aléatoire).

Notez bien :

{xtypo_warning}Aucune fonctions ne peut être décrite dans une autre fonction. Il est interdit d’utiliser dans un programme des fonctions dont la description est située dans une autre fonction.{/xtypo_warning}

 

Voici des exemples de mauvaise disposition des descriptions de fonction.

 

 

Fig. 34. Exemples de mauvaises dispositions de fonctions dans un programme.

 

Si par erreur, un programmeur crée un programme où la description de l’une de ses fonctions est située à l’intérieur de la description d’une autre fonction, à l’étape de compilation, le MetaEditoraffichera un message d’erreur et un fichier exécutable ne sera pas créé pour un tel programme.

 

Séquence d’exécution du code

En-tête et fonctions spéciales


Dès que l’exécution d’un programme a commencé dans une fenêtre du MetaEditor, les lignes de du code de l’en-tête sont exécutées.

Après les préparatifs décrits dans l’en-tête soient exécutés, le terminal client passe commande à la fonction spéciale init() et la fonction est exécutée (le passage du contrôle est indiqué dans le schéma structurel par les grandes flèches jaunes). La fonction spéciale init() est appelée pour être exécutée une seule fois au début du programme. Habituellement, cette fonction contient un code qui doit être exécuté qu’une seule fois avant que l’opération principale du programme commence. Par exemple, lorsque la fonction init() est exécutée, certaines variables globales sont initialisées, des objets graphiques sont affichés dans une fenêtre graphique, des messages peuvent être affichés. Après que toutes les lignesdu code de la fonction init() soient exécutées, la fonction termine son exécution et le contrôle est retourné au terminal client.

Le temps d’exécution du programme principal est la durée d’exécution de la fonction start(). Dans certaines conditions (voir les caractéristiques des fonctions spéciales dans la section s’y rapportant), y compris la réception d’un nouveau tick par le terminal clientl, le terminal client demande l’exécution de la fonction spéciale start(). Cette fonction (comme d’autres fonctions) peuvent se référer à l’environnement d’information du terminal client, effectuer les calculs nécessaires, réaliser l’ouverture et la clôture des ordres, c’est-à-dire effectuer toutes les actions autorisées par MQL4. Habituellement, lorsque la fonction spéciale start() est exécutée, un solution est produite qui est implémentée comme un contrôle d’action (flèche rouge). Ce contrôle peut être mis en œuvre comme une demande de trading pour ouvrir, fermer ou modifier un ordre constitué par le programme.

Après que l’ensemble du code de la fonction spéciale start() de l’EA soit exécuté, la fonction start() termine son fonctionnement et retourne le contrôle au terminal client. Le terminal aura le contrôle pendant un certain temps, ne commençant aucune autre fonction spéciale. Une pause apparaît, au cours de laquelle le programme ne fonctionne pas. Plus tard, quand un nouveau tick arrive, le client passe le contrôle de nouveau à la fonction spéciale start(), qui sera exécutée. Après son exécution terminée, le contrôle sera renvoyé au terminal… jusqu’à l’arrivée du prochain tick.

Le processus d’appel multiple de la fonction spéciale start() par le terminal client sera répété tant que le programme est joint à un graphique, ce qui peut durer des semaines et des mois. Pendant toute cette période, un Expert Advisor peut réaliser du trading automatique, c’est-à-dire réaliser sa mission principale. Ce processus est représenté sur le schéma par plusieurs flèche jaune enveloppant la fonction spéciale start().

Quand un trader enlève un EA d’un graphique, le terminal exécute une fois la fonction particulière deinit(). L’exécution de cette fonction est nécessaire pour la bonne fin de l’opération de l’EA. Pendant son fonctionnement, le programme peut, par exemple, créer des objets graphiques et des variables globales du terminal client. C’est pourquoi le code de la fonction deinit () contient des lignes de code dont l’exécution se traduit par la suppression des objets et variables inutiles. Après l’exécution de la fonction spéciale deinit(), le contrôle est renvoyé au terminal.

L’exécution des fonctions spéciales peut se référer à l’environnement d’information (flèches bleues sur le schéma) et appeler l’exécution des fonctions définies par l’utilisateur (flèches jaunes). Notez que les fonctions spéciales sont exécutées après avoir été appelées par le terminal client dans l’ordre prédéfini de leurs propriétés: d’abord init (), puis des appels multiples de start() et après un appel à deinit ().

Fonctions définies par l’utilisateur

Les fonctions définies par l’utilisateur sont exécutées lorsque l’appel à une fonction définie par l’utilisateur est contenue dans une fonction. Dans ce cas, le contrôle est  passé à la fonction définie par l’utilisateur et lorsque son exécution est terminée, le contrôle est retourné à l’endroit de l’appel (flèches orange sur le schéma). Les appels aux fonctions définies par l’utilisateur peuvent être contenues, non seulement dans la description d’une fonction spéciale, mais aussi dans la description des autres fonctions définies par l’utilisateur. Une fonction définie par l’utilisateur peut appeler d’autres fonctions définies par l’utilisateur – ce qui est largement utilisé en pratique dans la programmation.

Les fonctions définies par l’utilisateur ne sont pas mises en exécution par le terminal client. Les fonctions définies par l’utilisateur sont exécutées à l’intérieur d’une fonction spéciale qui retourne le contrôle au terminal. Elles peuvent aussi demander pour leurs calculs, les valeurs des variables de l’environnement d’information du terminal client (flèches bleues du schéma).

Si un programme contient la description d’une fonction définie par l’utilisateur, mais il n’y a aucun appel à cette fonction, cette fonction sera exclue du programme lors de la compilation et ne sera pas utilisée lors des opérations du programme.

{xtypo_alert}Note: les fonctions spéciales sont appelées pour exécution par le terminal client. Les fonctions définies par l’utilisateur sont exécutées si elles sont appelées par des fonctions spéciales ou d’autres fonctions définies par l’utilisateur, mais ne sont jamais appelées par le terminal client. Les actions de contrôle (comme des ordres de trades) peuvent être formées à la fois par les fonctions spéciales et définies par l’utilisateur.{/xtypo_alert}

 

Retour sommaire cours MQL4

Traduction: Nicolas Vitale
Source: http://book.mql4.com/programm/structure
“MQL4 is a trade mark of MetaQuotes Software Corp. and all related materials are reserved for MetaQuotes”