tag:blogger.com,1999:blog-58197407241018411932024-03-05T12:24:40.402+01:00Rentier par le Forex: la méthode de A à Z !Le trading sur le Forex par des robots, sans rester toute sa vie devant les cours à passer des ordres et stresser pour son investissement. Comprendre et maitriser le forex techniquement et programmer des experts advisors qui traderont pour vous, simplement en reproduisant les exemples de code. Le trading automatique et l'argent facile pour tous !Unknownnoreply@blogger.comBlogger51125tag:blogger.com,1999:blog-5819740724101841193.post-80755039412219030242014-04-01T14:35:00.000+02:002014-04-01T14:36:50.414+02:00Les objets graphiques<div style="text-align: justify; text-indent: 3em;">
MetaTrader nous permet de créer en manuel des objets graphiques pour nous aider dans l'analyse des cours. Ces objets sont divers et standardisés dans le monde du trading: des droites de tendances, des canaux, des lignes de supports ou résistances, des niveaux de Fibonacci, des angles de Gann, des marques d'ouverture de position, des annotations de texte, etc. Ces objets nous aident à visualiser, à analyser les cours et à gérer notre trading manuel. Tous ces objets graphiques peuvent être créés, modifiés et effacés par programmation avec le langage MQL4. Nous voyons une introduction à tout cela dans ce post.
</div>
<br />
<h3 style="font-weight: bold; text-decoration: underline;">
Les types d'objets
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Les objets sont de divers types et ces types sont relativement nombreux. la seule chose qu'on ne puisse pas créer, c'est un segment de ligne. Cela pourrait nous servir à tracer une courbe, mais ceci est déjà géré par MetaTrader, et uniquement par le logiciel quand on créé un indicateur. C'est mieux ainsi, car MetaTrader peut ainsi gérer la mémoire importante nécessaire et la rapidité d'exécution. Nous devons nous contenter de symboles,, de texte, de primitives géométriques et d'objets d'analyse technique des cours. Voici une liste non exhaustive avec les constantes prédéfinies MQL4 à utiliser pour les obtenir:<br />
<ul>
<li>Le texte</li>
<ul>
<li>Labels <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_LABEL </code></li>
<li>Textes <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_TEXT </code></li>
<li>Zones d'édition de texte <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_EDIT </code></li>
<li>Label Prix gauche <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_ARROW_LEFT_PRICE </code></li>
<li>Label Prix droite <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_ARROW_RIGHT_PRICE </code></li>
</ul>
<li>Les primitives géométriques</li>
<ul>
<li>Rectangles <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_RECTANGLE </code></li>
<li>Triangles <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_TRIANGLE </code></li>
<li>Ellipses <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_ELLIPSE </code></li>
</ul>
<li>Les symboles</li>
<ul>
<li>Stop <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_ARROW_STOP </code></li>
<li>Check <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_ARROW_CHECK </code></li>
<li>Main avec pouce vers le haut <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_ARROW_THUMB_UP </code></li>
<li>Main avec pouce vers le bas <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_ARROW_THUMB_DOWN </code></li>
<li>Achat <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_ARROW_BUY </code></li>
<li>Vente <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_ARROW_SELL </code></li>
<li>Flèche vers le haut <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_ARROW_UP </code></li>
<li>Flèche vers le bas <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_ARROW_DOWN </code></li>
</ul>
<li>Les objets d'analyse technique</li>
<ul>
<li>Ligne verticale de période <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_VLINE </code></li>
<li>Ligne horizontale de support ou résistance <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_HLINE </code></li>
<li>Ligne oblique de tendance <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_TREND </code></li>
<li>Ligne oblique de tendance définie par l'angle <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_TRENDBYANGLE </code></li>
<li>Cycles temporels <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_CYCLES </code></li>
<li>Canal équidistant <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_CHANNEL </code></li>
<li>Canal de déviation standard <code style="background-color: white; color: #0b5394; font-weight: bold;">OBJ_STDDEVCHANNEL </code></li>
<li>Ligne de Gann <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_GANNLINE </code></li>
<li>Angles de Gann <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_GANNFAN </code></li>
<li>Grille de Gann <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_GANNGRID </code></li>
<li>Retracements de Fibonacci <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_FIBO </code></li>
<li>Zones temporelles de Fibonacci <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_FIBOTIMES </code></li>
<li>Angles de Fibonacci <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_FIBOFAN </code></li>
<li>Arcs de Fibonacci <code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJ_FIBOARC </code></li>
</ul>
</ul>
Et il y existe d'autres objets non cités ici. Nous ne les verrons pas tous dans ce post, seulement le label et comment les objets sont créés et gérés.</div>
<br />
<h3 style="font-weight: bold; text-decoration: underline;">
Le système de coordonnées des graphiques
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Avant toute chose, il faut préciser le système de coordonnées utilisé dans les graphiques. Un graphique en trading est temporel, c'est-à-dire que les abscisses sont exprimées en temps: du type <span style="color: blue;">datetime</span>. En horizontal nous avons le temps. Pour les ordonnées, on se place verticalement en fonction du cours, c'est-à-dire du prix du sous-jacent (ici pour le forex, c'est le taux de conversion de la paire de devises). C'est donc un nombre décimal, du type <span style="color: blue;">double</span>. Il y a certains objets qui ne doivent pas être placés sur un temps et un prix précis, mais de manière fixe sur la fenêtre, de sorte qu'on la voit toujours. Un temps ou un prix pouvant être hors affichage. On va d'ailleurs commencer à utiliser de tels objets.</div>
<br />
<h3 style="font-weight: bold; text-decoration: underline;">
Les sous-graphiques
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Autre détail important: un graphique peut posséder des sous graphiques pour y placer des indicateurs. Un indicateur pouvant se placer dans le graphique principal de la paire de devises, ou bien dans une fenêtre à part, qui est sous-fenêtre de la principale. Ces fenêtres sont numérotées dans leur ordre d'apparition: 0 pour la principale, 1 pour la première sous-fenêtre, 2 pour la deuxième, etc.
</div>
<br />
<h3 style="font-weight: bold; text-decoration: underline;">
La création d'objets
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Créer un objet graphique se fait à l'aide d'une fonction prédéfinie en MQL4: <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">ObjectCreate</span>() </code>. Cette fonction retourne un booléen (type <span style="color: blue;">bool</span>), c'est-à-dire vrai ou faux pour dire si la création de l'objet a réussi ou non. Depuis la nouvelle version du langage MQL4 mise à jour récemment en février 2014, il y a deux versions de cette fonction, (elle est surchargée, pour les connaisseurs): il y a une version où on indique la référence de la fenêtre principale où on veut créer l'objet, puis le numéro de la sous-fenêtre (commençant à zéro), et une version où on n'indique pas la fenêtre principale car c'est celle où est exécutée le programme (indicateur ou expert advisor). Seule la deuxième était existante avant.<br />
Il faut lui fournir de nombreux arguments et dans cet ordre:<br />
<ul>
<li><code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">long</span> identifiantDeGraphique </code>: C'est le pointeur de la fenêtre pour identifier la fenêtre principale sur laquelle on veut créer l'objet et qui donc peut être différente de celle où le programme fonctionne. Paramètre nouveau et optionnel.</li>
<li><code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">string</span> nomDeLobjet </code>: Nom de l'objet à créer. Il faut évidemment lui donner un nom pour pourvoir ensuite le modifier ou le supprimer.</li>
<li><code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">ENUM_OBJECT</span> typeDeLobjet </code>: On utilise ici une constante précédemment listée.</li>
<li><code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">int</span> noSousFenetre </code>: Le numéro de la sous-fenêtre graphique dans laquelle créer l'objet. 0 pour la principale, 1 pour la première si elle existe, 2 pour la deuxième si elle existe, etc. La fenêtre principale est celle où est exécutée le programme ou bien celle désignée par l'identifiant de fenêtre en option.</li>
<li><code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">datetime</span> premiereCoordonneeTemps </code>: l'horodatage du premier point qui place l'objet.</li>
<li><code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">double</span> premiereCoordonneePrix </code>: position veticale (prix) du premier point qui place l'objet.</li>
<li>On peut répéter ces deux coordonnées jusqu'à trois fois pour la vieille version de la fonction, parce qu'il peut falloir jusqu'à trois points pour définir la position, l'orientation et la taille de l'objet sur le graphique. Mais toujours par paire. Avec la nouvelle version, lorsqu'on précise une fenêtre par son identifiant, on n'est plus limité à trois, mais autant de points qu'on veut.</li>
</ul>
On créé ainsi un objet, mais sans préciser de contenu, car beaucoup n'en n'ont pas besoin. Ceux du type texte ou label, on besoin qu'on leur ajoute un contenu texte. Ce sera fait avec une modification de l'objet dans le paragraphe suivant. Une précision supplémentaire: les objets label, ne prennent pas en compte les coordonnées fournies à la création car un label va rester fixe par rapport à l'affichage, alors qu'un point placé sur un horodatage précis pourra ne pas être vu si l'horodatage est en dehors de l'intervalle affiché, de même pour la coordonnée verticale du prix. Un label devant être toujours affiché, il faut lui préciser dans un second temps des coordonnées en pixels par rapport à un coin de la fenêtre. Ce sera fait avec la fonction de modification.</div>
<br />
<h3 style="font-weight: bold; text-decoration: underline;">
La modification d'objets
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Pour modifier un objet, c'est pas compliqué, il suffit d'utiliser la fonction spécialement prévue à cet effet: <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">ObjectSet</span>() </code>. Cette fonction change une propriété de l'objet. On doit lui donner le nom de l'objet à modifier, la propriété à changer sous forme de nombre entier soit une constante prédéfinie et la nouvelle valeur sous forme de nombre décimal. Elle retourne un booléen vrai ou faux pour dire si la modification a réussi ou pas. Les propriétés sont désignées par ces constantes (liste non exhaustive):<br />
<ul>
<li><code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJPROP_TIME1 </code> horodatage du premier point de positionnement</li>
<li><code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJPROP_PRICE1 </code> prix du premier point de positionnement</li>
<li><code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJPROP_COLOR </code> couleur de l'objet</li>
<li><code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJPROP_STYLE </code> style de traçage pour les lignes uniquement</li>
<li><code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJPROP_WIDTH </code> epaisseur du trait pour les lignes uniquement</li>
<li><code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJPROP_ANGLE </code> angle de l'objet</li>
<li><code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJPROP_FONTSIZE </code> taille de la fonte (police) pour les objet avec du texte.</li>
<li><code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJPROP_CORNER </code> coin de la fenêtre origine de coordonnées pour placer le label (objets label uniquement), c'est un numéro de 0 à 3 pour les quatre coins du graphique.</li>
<li><code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJPROP_XDISTANCE </code> position horizontale en pixels pour placer l'objet de manière fixe par rapport à la fenêtre, et non pas par rapport au temps et au prix. (pour les labels)</li>
<li><code style="background-color: white; color: #0b5394; font-weight: bold;"> OBJPROP_YDISTANCE </code> position verticale en pixels. (même commentaire)</li>
</ul>
Il y en a bien d'autres, voir la documentation fournie, dans l'aide de MetaEditor. On peut aussi simplement obtenir la valeur d'une propriété d'un objet avec la fonction <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">ObjectGet</span>() </code> à qui on fournit le nom de l'objet et la propriété voulue et qui nous retourne sa valeur.<br />
Nous allons dans le prochain post créer des labels, à qui il faut évidemment fournir un texte, et la fonction <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">ObjectSet</span>() </code> ne peut le faire car la valeur transmise n'est pas un texte, mais est numérique. Il y a pour cela une fonction spéciale pour fixer le texte d'objets contenant du texte: <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">ObjectSetText</span>() </code>. On doit lui passer le nom de l'objet, le texte à mettre et en option car il y a des valeurs par défaut: la taille de la fonte (0 par défaut pour ne pas la changer), le nom de la fonte à utiliser (chaine de caractères pour désigner une police de caractères, par défaut NULL) et la couleur du texte (par défaut: clrNone). Elle retourne un booléen pour dire si la mise à jour du texte à réussi.</div>
<br />
<h3 style="font-weight: bold; text-decoration: underline;">
La suppression d'objets
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Enfin, lors de la déinitialisation, il faut supprimer les objets créés pour libérer de la place sur le graphique. Il y a deux fonctions pour cela:
<code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">ObjectDelete</span>() </code> qui prend un nom d'objet en argument et qui efface seulement celui-là. La fonction <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">ObjectsDeleteAll</span>() </code> qui prend en option un numéro de sous-fenêtre et/ou un type d'objet pour se limiter à une sous-fenêtre et/ou un type d'objets et qui les efface tous. Ces deux fonctions retournent le nombre d'objets effacés et existent aussi maintenant en version avec la référence de la fenêtre principale en premier argument pour viser une fenêtre autre que celle sur laquelle le programme s'exécute.
</div>
<br />
<div style="text-align: justify; text-indent: 3em;">
Voilà pour une présentation qui permet de démarrer l'utilisation des objets graphiques, nous allons commencer dès le prochain post un fichier include d'outils pour les objets graphiques. Des fonctions pour les créer et les gérer et on commencera avec les labels.
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-89975308238858671392014-03-28T19:17:00.000+01:002014-03-28T19:17:32.655+01:00Test du fichier include d'outils pour les indicateurs<div style="text-align: justify; text-indent: 3em;">
Dans le post précédent nous avons créé un fichier include avec des fonctions d'initialisation d'indicateur et d'index. Le résultat de ces fonctions ne peut pas être analysé par un programme, d'ailleurs les fonctions ne retournent rien, elles sont du type void. Le résultat ne peut être que visuel, et il faut en plus initialiser plusieurs fois l'indicateur avec des paramètres différents pour voir comment il réagit.<br />
<br />
Une petite précision: il y a eu de gros changements dans MQL4 avec une mise à jour récente. Les nouveautés seront en partie utilisées et d'autres non utilisées pour l'instant car je ne les ai pas testées. Notamment les arguments fournis à la fonction <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">OnCalculate</span>() </code> qui font double emploi avec les variables prédéfinies du même nom mais avec une majuscule. Ces arguments sont présents pour une meilleure compatibilité avec le langage C et MQL5. L'argument &spread[] m'a étonné, alors que jusqu'à présent les spreads des périodes n'étaient pas disponibles. En réalité, il est présent, au cas où le broker les fournisse, ce qui a peu de chances de se produire. L'argument rates_total serait équivalent à Bars et l'argument prev_calculated à <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">IndicatorCounted</span>() </code>. Je mets bien ça au conditionnel car je ne connais pas la gestion interne de ces arguments par MetaTrader, notamment vis-à-vis de la gestion mémoire. Il y aurait une différence car on doit désormais retourner à la fin de nos calculs le nombre de valeurs calculées, pour que Metatrader le donne à nouveau lors de l'appel suivant dans l'argument prev_calculated. Il faudra tester tout ceci à l'avenir. Pour le moment nous utiliserons toujours les anciennes méthodes et toute l'armada très «dirty code» (code sale) des arguments ne nous servira pas. (les variables globales sont aussi du code sale, mais elles ne gênent pas la lisibilité au moins !) Nous pourrions tout simplement utiliser encore la fonction <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">start</span>() </code>, mais on va commencer à s'habituer aux nouveautés juste avec <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">OnCalculate</span>() </code>. On constate aussi, que des paramètres des indicateurs et des index peuvent être fixés par des <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">#property</span> </code> au début du code. Cela n'empêche en rien de les déclarer à nouveau par nos fonctions d'initialisation, d'autant plus qu'ils n'y sont pas tous et que cela permet de les modifier à la volée lors de l'initialisation, ce que ne permet pas les <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">#property</span> </code>.</div>
<br />
<h3 style="font-weight: bold; text-decoration: underline;">
Un signal d'index vite fait pour remplir l'historique:</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Vite fait, c'est vite dit ! Nous allons utiliser le signal d'un indicateur déjà présent dans MetaTrader. Donc dans la boucle principale de l'indicateur nous récupérons simplement la valeur d'un indicateur de moyenne mobile <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #38761d;">iMA</span>() </code> et nous la mettons dans notre tableau d'historique. Pour rappel, nous devons à chaque appel de la fonction <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">OnCalculate</span>() </code> (on utilisait avant <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">start</span>() </code> et on peut toujours) parcourir toutes les périodes à recalculer comme le demande MetaTrader. Le nombre de périodes total dans l'historique est donné par <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">Bars</span> </code> et le nombre de périodes depuis le début de l'historique à ne pas recalculer est donné par <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">IndicatorCounted</span> ()</code>. Donc le nombre de périodes à traiter est <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">Bars</span> - <span style="color: #674ea7;">IndicatorCounted</span>() </code> et le numéro de la première période à traiter est alors <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">Bars</span> - <span style="color: #674ea7;">IndicatorCounted</span> - <span style="color: #38761d;">1</span> </code> car la numérotation des cases du tableau est décalée d'une unité. Un schéma vaut mieux qu'un long discours:<br />
<table border="1" style="margin: 0.5em; text-align: center; width: 100%;">
<caption>tableau d'historique</caption>
<thead>
<tr><th colspan="10">supposons un historique de 10 périodes au total et 2 périodes déjà calculées</th>
</tr>
</thead>
<tbody>
<tr><td style="background-color: #007700;">9</td><td style="background-color: #007700;">8</td><td style="background-color: #770000;">7</td><td style="background-color: #770000;">6</td><td style="background-color: #770000;">5</td><td style="background-color: #770000;">4</td><td style="background-color: #770000;">3</td><td style="background-color: #770000;">2</td><td style="background-color: #770000;">1</td><td style="background-color: #770000;">0</td></tr>
</tbody>
<tfoot>
<tr><td colspan="10">Bars - 1 = 10 - 1 = 9 et Bars - IndicatorCounted - 1 = 10 - 2 - 1 = 7</td>
</tr>
<tr><td colspan="10">On commence bien à traiter la période n°7 qui est la première à devoir être calculée!</td></tr>
</tfoot>
</table>
<br />
Dans notre code nous calculons donc le numéro de la première période à traiter et nous commençons la boucle for à ce numéro et on la continue en décrémentant (diminuant) de 1 à chaque passage le numéro de la période. La boucle s'arrête selon les nécessités des calculs des indicateurs au n°1 ou 0. A chaque passage on récupère la valeur de la moyenne mobile et on l'affecte à la case correspondante de notre tableau, c'est tout ! Pour les besoins de calculs de cet indicateur nous ne devons pas commencer les calculs dès le début de l'historique, puisque pour faire une moyenne mobile de 12 périodes par exemples, il nous faut 12 périodes précédentes. On commence donc à <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">Bars</span>-<span style="color: #38761d;">1</span>-<span style="color: #990000;">nbPeriodesMoyenne</span> </code>. Le code de l'indicateur de test est simple:<br />
<ol>
<li>Initialisation du nombre de périodes à traiter</li>
<li>Si ce nombre est supérieur à <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">Bars</span>-<span style="color: #990000;">nbPeriodesMoyenne</span>-<span style="color: #38761d;">1</span> </code> alors fixer le début à cette valeur.</li>
<li>Sinon fixer le début <code style="background-color: white; color: black; font-weight: bold;"> nbPeriodesATraiter-<span style="color: #38761d;">1</span> </code></li>
<li>Initialiser la boucle For</li>
<ol>
<li>récupérer la moyenne mobile de l'indicateur déjà existant dans MetaTrader</li>
<li>mettre cette valeur dans notre tableau d'historique.</li>
</ol>
<li>C'est nouveau: retourner <code style="background-color: white; color: black; font-weight: bold;"> rates_total </code> !</li>
</ol>
Voici le code: </div>
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">int</span> <span style="color: #674ea7;">OnCalculate</span>(<span style="color: blue;">const int</span> rates_total,
<span style="color: blue;">const int</span> prev_calculated,
<span style="color: blue;">const datetime</span> &time[],
<span style="color: blue;">const double</span> &open[],
<span style="color: blue;">const double</span> &high[],
<span style="color: blue;">const double</span> &low[],
<span style="color: blue;">const double</span> &close[],
<span style="color: blue;">const long</span> &tick_volume[],
<span style="color: blue;">const long</span> &volume[],
<span style="color: blue;">const int</span> &spread[]) {
<span style="color: blue;">double</span> moyenneMobile;
<span style="color: blue;">int</span> noPeriode, noPeriodeDebut;
<span style="color: blue;">int</span> nbPeriodeATraiter = <span style="color: magenta;">Bars</span> - <span style="color: #674ea7;">IndicatorCounted</span>();
<span style="color: blue;">int</span> noPeriodeLimiteCalcul = <span style="color: magenta;">Bars</span> - <span style="color: #990000;">nbPeriodesMoyenne</span> - <span style="color: #38761d;">1</span>;
<span style="color: blue;">if</span>(nbPeriodesATraiter>noPeriodeLimiteCalcul) {
noPeriodeDebut = noPeriodeLimiteCalcul;
}
<span style="color: blue;">else</span> { noPeriodeDebut = nbPeriodesATraiter - <span style="color: #38761d;">1</span>; }
<span style="color: blue;">for</span>(noPeriode=noPeriodeDebut ; noPeriode>=<span style="color: #38761d;">0</span> ; noPeriode--) {
moyenneMobile = <span style="color: #38761d;">iMA</span>(<span style="color: #0b5394;">NULL</span>, <span style="color: #38761d;">0</span>, <span style="color: #990000;">nbPeriodesMoyenne</span>, <span style="color: #990000;">shift</span>,
<span style="color: #0b5394;">MODE_SMA</span>, <span style="color: #0b5394;">PRICE_MEDIAN</span>, noPeriode);
bufferMoyenne[noPeriode] = moyenneMobile;
}
<span style="color: blue;">return</span>(rates_total);
}
</code></pre>
<div style="text-align: justify; text-indent: 3em;">
Quelques commentaires: variables colorées en rouge sont des variables globales qui servent de paramètre à l'indicateur. Elles sont déclarées désormais <span style="color: blue;">input</span> au début du code au lieu de <span style="color: blue;">extern</span> jusqu'à la récente mise à jour du langage. Ces paramètres externes permettent de modifier des valeurs pour le programme lorsqu'on le lance sur un graphique. Il suffit de les modifier dans la fenêtre qui s'ouvre, dans l'onglet Paramètres. Autre détail, de taille ! Tous ces arguments à la fonction ! Ils font double emploi avec les variables prédéfinies, et nous ne les utilisons pas pour l'instant. Nous devons impérativement retourner cette valeur désormais. La fonction iMA nous donne la moyenne mobile, et elle a besoin de nombreux paramètres que nous expliquerons dans un post ultérieur. Cette moyenne, à peine récupérée, elle est mise dans notre buffer: C'est le seul traitement que nous faisons dans cet indicateur, car le but n'est pas de calculer une valeur, mais bien de vérifier si nos fonctions réalisent bien leur travail.
</div>
<br />
<h3 style="font-weight: bold; text-decoration: underline;">
Tester l'initialisation de l'indicateur:</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
La fonction d'initialisation d'indicateurs effectue deux choses: fixer le nombre de décimales et donner le nom court de l'indicateur. Nous allons passer des valeurs à la fonction, en l'occurrence seulement le nom court, et vérifier que l'indicateur la prend bien en compte. Il faudra fournir ce nom en paramètre externe, c'est-à-dire fixé lors de l'initialisation de l'indicateur dans la fenêtre qui s'ouvre. Et il faudra constater le changement sur l'indicateur. Il faudra aussi vérifier que le nombre de décimales de l'indicateur est bien celui de la paire. La plupart des brokers travaillent avec 5 décimales désormais. On va donc tester sur une paire à 5 décimales très probablement et on le fera sur une paire avec le yen qui n'en a que deux ou trois.<br />
En résumé, nous devons choisir un nom en paramètre externe de l'indicateur et vérifier qu'il apparait bien dans le menu contextuel que nous donne MetaTrader avec un clic droit sur un signal de cet indicateur. Nous devons aussi tester cet indicateur sur un paire sans le Yen et une paire avec le Yen et constater dans l'infobulle de MetaTrader lorsqu'on pointe sur le signal graphique qu'il y a 5 décimales pour une paire sans le Yen et 2 ou 3 décimales pour une paire avec le Yen.<br />
Sans oublier la déclaration du paramètre externe nomCourtIndicateur avec sa valeur par défaut, ni oublier l'inclusion du fichier d'outils Indicateurs, la ligne de code de l'initialisation est simplement dans la fonction <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">OnInit</span>() </code>:
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">input string</span> <span style="color: #990000;">nomCourtIndicateur</span>=<span style="color: #45818e;">"indicateur-test"</span>;
<span style="color: blue;">#include</span> <OutilsIndicateurs.mqh>
<span style="color: blue;">int</span> <span style="color: #674ea7;">OnInit</span>() {
initIndicateur(<span style="color: #990000;">nomCourtIndicateur</span>);
}
</code></pre>
Le paramètre externe du nom court de l'indicateur en rouge est déclaré avec une valeur par défaut mais pourra être modifié à la volée lors de l'initialisation de l'indicateur voire même après. Un paramètre externe est simplement une variable que MetaTrader présente dans la fenêtre d'initialisation pour qu'on puisse la modifier quand on utlise le programme. Avec la nouvelle version du langage, elles sont déclarées en tant qu'entrées du programme (input) et non plus comme variables externes. C'est juste un changement de dénomination, ça reste la même chose. Maintenant l'avantage, c'est qu'elles sont colorées en rouge par l'éditeur.
</div>
<br />
<h3 style="font-weight: bold; text-decoration: underline;">
Tester l'initialisation d'un index:</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Pour initialiser un index, notre fonction transmet de nombreux paramètres à MetaTrader, dont la plupart en valeur par défaut. Nous transmettrons le numéro de l'index et le tableau qui lui sert de buffer et le simple fait que MetaTrader trace le signal suffit à confirmer que ça fonctionne car ces deux éléments sont primordiaux pour faire fonctionner l'indicateur, sans ça, pas de signal.<br />
<br />
Nous utiliserons le décalage traditionnellement appelé shift dans Metatrader en tant que paramètre externe pour le décalage des périodes de l'indicateur par rapport à l'historique du cours. Comme ça nous pourrons le modifier et voir le décalage modifié en direct.</div>
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code><span style="color: blue;">input int</span> <span style="color: #990000;">shift</span>=<span style="color: #38761d;">0</span>;</code></pre>
<div style="text-align: justify; text-indent: 3em;">
Concernant le début du traçage, nous allons aussi utiliser un paramètre externe pour le modifier à la volée, mais il nous faut savoir combien il y a de périodes dans l'historique car nous risquons sinon de chercher longtemps le début de l'historique. Eh oui ! il y en a beaucoup dans l'historique. Nous allons donc faire afficher à l'initialisation le nombre de périodes dans l'historique pour savoir quel nombre mettre afin de voir le début du traçage vers la fin de l'historique:</div>
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code><span style="color: blue;">input int</span> <span style="color: #990000;">debutTracage</span>=<span style="color: #38761d;">0</span>;
<span style="color: #674ea7;">Print</span>(<span style="color: #45818e;">"nombre de périodes dans l'historique: "</span>, <span style="color: magenta;">Bars</span>);</code>
</pre>
<div style="text-align: justify; text-indent: 3em;">
Il y a ensuite le nom donné à l'index, celui-ci apparaitra dans les infobulles de MetaTrader, il suffit de lui en donner un par une constante déclarée au début que nous concatènerons pendant l'initialisation avec le nombre de périodes de calculs de la moyenne elle aussi en paramètre externe (concaténer signifie mettre les chaines de caractères bout à bout):</div>
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code><span style="color: blue;">input int</span> <span style="color: #990000;">nbPeriodesMoyenne</span>=<span style="color: #38761d;">12</span>;
<span style="color: blue;">string</span> NOM_INDEX = <span style="color: #45818e;">"moy-mobile-"</span>;
<span style="color: blue;">string</span> nomIndex;
<span style="color: #999999;">dans OnInit()</span> nomIndex = <span style="color: #674ea7;">StringConcatenate</span>(NOM_INDEX, <span style="color: #990000;">nbPeriodesMoyenne</span>);</code></pre>
<div style="text-align: justify; text-indent: 3em;">
Puis vient le tour des caractéristiques de traçage, dont la couleur. Première chose, ces caractéristiques sont aussi définies de manière statique par des <code style="background-color: white; color: blue; font-weight: bold;"> #property </code> au début du code, et c'est l'assitant de création de nouveau fichier qui nous l'a mis. Le problème, c'est qu'avec ces définitions, statiques, nos tentatives de définitions des caractéristiques de manière dynamique dans le code échoueront et même il n'y aura pas de traçage. Nous devons donc supprimer ces définitions statiques car nous les définissons de manière dynamique avec notre fonction d'initialisation d'index. Dans l'appel de la fonction d'initialisation d'index, nous mettons simplement le nom de la couleur nouvellement défini dans la mise à jour du langage: les noms de couleur commencent tous par le préfixe «clr». Ici nous mettons <code style="background-color: white; color: #0b5394; font-weight: bold;"> clrBlue </code>.
</div>
<br />
<div style="text-align: justify; text-indent: 3em;">
La même chose pour le style, le mode de traçage et l'épaisseur du trait qu'on définit en paramètres externes histoire de les changer un peu pour voir le résultat.</div>
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code><span style="color: blue;">input int</span> <span style="color: #990000;">styleDeTracage</span>=<span style="color: #0b5394;">STYLE_SOLID</span>;
<span style="color: blue;">input int</span> <span style="color: #990000;">modeDeTracage</span>=<span style="color: #0b5394;">DRAW_LINE</span>;
<span style="color: blue;">input int</span> <span style="color: #990000;">epaisseurDuTrait</span>=<span style="color: #0b5394;">EMPTY</span>;
</code></pre>
<br />
<div style="text-align: justify; text-indent: 3em;">
Dernier paramètre et c'est celui qui a le moins de chances d'être modifié (c'est pour ça qu'il est placé en dernier): la valeur signifiant «pas de valeur calculée». C'est la valeur vide de l'indicateur. Quand elle est présente dans une case du tableau d'historique de l'index, elle signifie pour MetaTrader qu'aucune valeur n'est calculée pour cette période, et MetaTrader ne trace rien à cette période. Normalement on y place la valeur <code style="background-color: white; color: #0b5394; font-weight: bold;"> EMPTY_VALUE </code> mais on peut la modifier. Nous la mettons en paramètre externe, avec sa valeur par défaut, mais lorsque l'indicateur fonctionnera on y placera une valeur particulière qui est utilisée sur le moment dans l'indicateur pour voir que MetaTrader ne trace plus lorsqu'il y a cette valeur. (voir la vidéo pour bien comprendre)</div>
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code><span style="color: blue;">input double</span> <span style="color: #990000;">valeurNonCalculee</span>=<span style="color: #0b5394;">EMPTY_VALUE</span>;</code></pre>
<h3 style="font-weight: bold; text-decoration: underline;">
Le tutoriel et le code de test:</h3>
<div class="separator" style="clear: both; text-align: center;">
<object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="https://ytimg.googleusercontent.com/vi/km_NoxTvfHE/0.jpg" height="480" width="640"><param name="movie" value="https://youtube.googleapis.com/v/km_NoxTvfHE&source=uds" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="640" height="480" src="https://youtube.googleapis.com/v/km_NoxTvfHE&source=uds" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<br />
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| testsOutilsIndicateurs.mq4|
//| Copyright 2014, argent-facile-avec-robots-forex|
//| http://argent-facile-robots-forex.blogspot.fr|
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property</span> <span style="color: #0b5394;">copyright</span> <span style="color: #45818e;">"Copyright 2014, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property</span> <span style="color: #0b5394;">link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: blue;">#property</span> <span style="color: #0b5394;">version</span> <span style="color: #45818e;">"1.00"</span>
<span style="color: blue;">#property</span> <span style="color: #0b5394;">strict</span>
<span style="color: blue;">#property</span> <span style="color: #0b5394;">indicator_chart_window</span>
<span style="color: blue;">#property</span> <span style="color: #0b5394;">indicator_buffers</span> <span style="color: #38761d;">1</span>
<span style="color: blue;">#property</span> <span style="color: #0b5394;">indicator_plots</span> <span style="color: #38761d;">1</span>
<span style="color: #999999;">//--plot moyenne
//#property indicator_label1 "moyenne"
//#property indicator_type2 DRAW_LINE
//#property indicator_color1 clrRed
//#property indicator_style1 STYLE_SOLID
//#property indicator_witdh1 1
//+------------------------------------------------------------------+
//| Tampons d'historique des index |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">double</span> bufferMoyenne[];
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Paramètres externes |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">input string</span> <span style="color: #990000;">nomCourtIndicateur</span>=<span style="color: #45818e;">"indicateur-test"</span>;
<span style="color: blue;">input int</span> <span style="color: #990000;">shift</span>=<span style="color: #38761d;">0</span>;
<span style="color: blue;">input int</span> <span style="color: #990000;">debutTracage</span>=<span style="color: #38761d;">0</span>;
<span style="color: blue;">input int</span> <span style="color: #990000;">nbPeriodesMoyenne</span>=<span style="color: #38761d;">12</span>;
<span style="color: blue;">input int</span> <span style="color: #990000;">styleDeTracage</span>=<span style="color: #0b5394;">STYLE_SOLID</span>;
<span style="color: blue;">input int</span> <span style="color: #990000;">modeDeTracage</span>=<span style="color: #0b5394;">DRAW_LINE</span>;
<span style="color: blue;">input int</span> <span style="color: #990000;">epaisseurDuTrait</span>=<span style="color: #0b5394;">EMPTY</span>;
<span style="color: blue;">input double</span> <span style="color: #990000;">valeurNonCalculee</span>=<span style="color: #0b5394;">EMPTY_VALUE</span>;
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Includes |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#include</span> <OutilsIndicateurs.mqh>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Constantes globales |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">string</span> NOM_INDEX = <span style="color: #45818e;">"moy-mobile-"</span>;
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Variables globales |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">string</span> nomIndex;
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> <span style="color: #674ea7;">OnInit</span>() {
nomIndex = <span style="color: #674ea7;">StringConcatenate</span>(NOM_INDEX, <span style="color: #990000;">nbPeriodesMoyenne</span>);
<span style="color: #674ea7;">Print</span>(<span style="color: #45818e;">"nombre de périodes dans l'historique: "</span>, <span style="color: magenta;">Bars</span>);
initIndicateur(<span style="color: #990000;">nomCourtIndicateur</span>);
initIndex(<span style="color: #38761d;">0</span>, bufferMoyenne, <span style="color: #990000;">shift</span>, <span style="color: #990000;">debutDuTracage</span>, nomIndex, <span style="color: #0b5394;">clrBlue</span>,
<span style="color: #990000;">styleDeTracage</span>, <span style="color: #990000;">modeDeTracage</span>, <span style="color: #990000;">epaisseurDuTrait</span>, <span style="color: #990000;">valeurNonCalculee</span>);
<span style="color: blue;">return</span>(<span style="color: #0b5394;">INIT_SUCCEEDED</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> <span style="color: #674ea7;">OnCalculate</span>(<span style="color: blue;">const int</span> rates_total,
<span style="color: blue;">const int</span> prev_calculated,
<span style="color: blue;">const datetime</span> &time[],
<span style="color: blue;">const double</span> &open[],
<span style="color: blue;">const double</span> &high[],
<span style="color: blue;">const double</span> &low[],
<span style="color: blue;">const double</span> &close[],
<span style="color: blue;">const long</span> &tick_volume[],
<span style="color: blue;">const long</span> &volume[],
<span style="color: blue;">const int</span> &spread[]) {
<span style="color: blue;">double</span> moyenneMobile;
<span style="color: blue;">int</span> noPeriode, noPeriodeDebut;
<span style="color: blue;">int</span> nbPeriodeATraiter = <span style="color: magenta;">Bars</span> - <span style="color: #674ea7;">IndicatorCounted</span>();
<span style="color: blue;">int</span> noPeriodeLimiteCalcul = <span style="color: magenta;">Bars</span> - <span style="color: #990000;">nbPeriodesMoyenne</span> - <span style="color: #38761d;">1</span>;
<span style="color: blue;">if</span>(nbPeriodesATraiter>noPeriodeLimiteCalcul) {
noPeriodeDebut = noPeriodeLimiteCalcul;
}
<span style="color: blue;">else</span> { noPeriodeDebut = nbPeriodesATraiter - <span style="color: #38761d;">1</span>; }
<span style="color: blue;">for</span>(noPeriode=noPeriodeDebut ; noPeriode>=<span style="color: #38761d;">0</span> ; noPeriode--) {
moyenneMobile = <span style="color: #38761d;">iMA</span>(<span style="color: #0b5394;">NULL</span>, <span style="color: #38761d;">0</span>, <span style="color: #990000;">nbPeriodesMoyenne</span>, <span style="color: #990000;">shift</span>,
<span style="color: #0b5394;">MODE_SMA</span>, <span style="color: #0b5394;">PRICE_MEDIAN</span>, noPeriode);
bufferMoyenne[noPeriode] = moyenneMobile;
}
<span style="color: blue;">return</span>(rates_total);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span>
</code></pre>
<div style="text-align: justify; text-indent: 3em;">
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-23491674668881445432014-03-07T12:14:00.000+01:002015-06-01T19:19:24.876+02:00Un fichier include .mqh d'outils pour les indicateurs<div style="text-align: justify; text-indent: 3em;">
Après un fichier de fonctions pour les calculs temporels et les calculs sur les cotations, que nous étofferons par la suite, nous allons faire un fichier pour nous faciliter la tache lors de la création d'indicateurs. Il n'y aura que deux fonctions pour l'instant, très simples algorithmiquement, elles nous soulageront des nombreuses lignes de codes à répéter pour créer des indicateurs. Et les valeurs par défaut nous éviteront de les préciser à chaque fois.
</div>
<br />
<h3 style="font-weight: bold; text-decoration: underline;">
Ce que fait un indicateur:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Un indicateur va chercher les valeurs du cours dans l'historique et fait des calculs pour donner un résultat chiffré par période. Ce résultat doit être stocké dans un historique spécialement créé pour l'indicateur, et MetaTrader se sert de cet historique pour tracer une courbe ou un histogramme correspondant à l'évolution de notre valeur calculée. La courbe ainsi créée se rajoute au cours sur le graphique pour nous donner l'évolution de notre valeur. C'est cette valeur qui va nous donner des indications pour trader, ou bien qui va servir à des experts advisors pour prendre des décisions.
</div>
<br />
<h3 style="font-weight: bold; text-decoration: underline;">
Les initialisations nécessaires
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
L'historique de cet indicateur est simplement un tableau, dont la taille est gérée par MetaTrader. Nous n'avons qu'à déclarer son existence et le remplir. MetaTrader doit, pour effectuer ce travail, être averti de certaines choses. Pour l'indicateur globalement:<br />
<ul>
<li>Donner un nom à l'indicateur.</li>
<li>Fixer la précision de l'indicateur: le nombre de décimales.</li>
</ul>
Dans chaque indicateur il peut y avoir jusqu'à huit valeurs basées sur huit calculs différents avec chacune leur historique. Chaque valeur calculée avec son historique est appelée un index. Pour chacun des huit index possibles, il faut:
<br />
<ul>
<li>Préciser le tableau à utiliser pour l'historique.</li>
<li>Fixer le décalage entre les périodes de l'indicateur et celle du cours.</li>
<li>Fixer le style graphique pour le traçage de la valeur.</li>
<li>Préciser la période de début de traçage.</li>
<li>Préciser le label à afficher pour l'index.</li>
<li>Préciser la valeur signifiant aucune donnée pour la période.</li>
</ul>
</div>
<br />
<h3 style="font-weight: bold; text-decoration: underline;">
Une fonction d'initialisation de l'indicateur
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Nous devons préciser à MetaTrader le nombre de décimales que l'indicateur doit fournir, en général, le même nombre de décimales que celui de la paire sur laquelle il s'exécute. Nous utilisons donc la fonction <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">MarketInfo</span>() </code> qui va nous donner cette information grâce aux paramètres <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">Symbol</span>() </code> qui donne le nom de la paire de devises courante. (sur laquelle on est) et <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #0b5394;">MODE_DIGITS</span> </code> qui est un code signifiant à la fonction <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">MarketInfo</span>() </code> qu'on veut le nombre de décimales (digits). Et ce nombre de décimales est fourni à la fonction <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">IndicatorDigits</span>() </code> qui va le fixer pour notre indicateur.
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">string</span> paireCourante = <span style="color: #674ea7;">Symbol</span>();
<span style="color: blue;">int</span> nombreDecimales = <span style="color: #674ea7;">MarketInfo</span>(paireCourante, <span style="color: #0b5394;">MODE_DIGITS</span>);
<span style="color: #674ea7;">IndicatorDigits</span>(nombreDecimales);
</code></pre>
<br />
On doit également donner un nom court à l'indicateur, utilisable par MetaTrader notamment pour l'afficher dans les graphiques et pour être appelé par un expert advisor. Ce nom on le donne à la fonction IndicatorShortName() qui va le fixer pour cet indicateur.
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: #674ea7;">IndicatorShortName</span>(nomCourt);
</code></pre>
<br />
La fonction d'initialisation de l'indicateur reçoit alors juste le nom court de l'indicateur et exécute les lignes de code précédentes. Elle ne retourne aucune valeur, elle est donc du type void:
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">void</span> initIndicateur(<span style="color: blue;">string</span> nomCourt) {
<span style="color: blue;">string</span> paireCourante = <span style="color: #674ea7;">Symbol</span>();
<span style="color: blue;">int</span> nombreDecimales = <span style="color: #674ea7;">MarketInfo</span>(paireCourante, <span style="color: #0b5394;">MODE_DIGITS</span>);
<span style="color: #674ea7;">IndicatorDigits</span>(nombreDecimales);
<span style="color: #674ea7;">IndicatorShortName</span>(nomCourt);
}
</code></pre>
</div>
<br />
<h3 style="font-weight: bold; text-decoration: underline;">
Une fonction d'initialisation d'un index
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
L'initialisation d'un index doit indiquer le numéro de l'index sur les huit possibles: de 0 à 7. Il faut donc transmettre ce numéro en argument à la fonction et le fournir à toutes les fonctions que nous allons appeler pour paramétrer cet index.<br />
Nous devons déclarer le tableau qui nous sert d'historique pour l'indicateur, il y a en au moins un. Nous pouvons en créer jusqu'à huit par indicateur. Pour ces déclarations, nous ne précisons pas la taille du tableau, MetaTrader s'en chargera. Cette déclaration de tableau sera faite manuellement pour chaque indicateur, car nous ne pouvons pas retourner un tableau avec une fonction, donc pas de déclaration de ces tableaux dans une fonction. Nous devrons par contre passer le tableau à la fonction et par référence (pas de copie) pour qu'elle puisse passer cette référence à MetaTrader qui saura alors quel tableau utiliser pour l'historique. C'est la fonction SetIndexBuffer() qui transmet la référence.
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: #674ea7;">SetIndexBuffer</span>(noIndex, tamponHistorique);
</code></pre>
<br />
Nous devons ensuite régler le décalage de l'indicateur par rapport aux périodes des courts. C'est-à-dire le décalage voulu entre la valeur calculée pour une période et la période qu'elle représente. Normalement il n'y en a pas, on calcule une valeur pour une période et cette valeur ressort quand on demande cette période précisément. Mais on peut vouloir décaler toutes les valeurs de chaque période pour avancer ou reculer le signal par rapport aux cotations de la paire. Ce décalage est fourni en argument, sans valeur par défaut, car elle peut être modifiée à chaque initialisation de l'indicateur. On doit donc la transmettre à chaque fois:
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: #674ea7;">SetIndexShift</span>(noIndex, decalagePeriodes);
</code></pre>
<br />
Le calcul d'une valeur d'index pour une période, demande presque tout le temps d'utiliser les cours antérieurs à la période calculée. Or pour la toute première période et les quelques suivantes de l'historique, il n'y a pas suffisamment de cotations antérieures pour faire ce calcul. On ne doit donc pas tracer l'indicateur pour ces toutes premières périodes car s'il on y calcule des valeurs, elles ne seront pas bonnes par manque de cotations antérieures. On peut préciser à MetaTrader de ne pas tracer l'index pour un certain nombre de périodes au début de l'historique:
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: #674ea7;">SetIndexDrawBegin</span>(noIndex, debutTracage);
</code></pre>
<br />
Pour afficher le nom de l'index lorsqu'on pointe dessus avec la souris, ou pour avoir un intitulé dans la fenêtre de description, on peut assigner un label à un index:
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: #674ea7;">SetIndexLabel</span>(noIndex, intitule);
</code></pre>
<br />
Ensuite, on peut, et c'est conseillé de donner un style de traçage à l'index. On peut modifier<br />
<ul>
<li>le mode (ligne, section, histogramme, flèches, zigzag, remplissage ou aucun traçage).</li>
<li>le style du tracé (continu, traits interrompus, points, trait-point et trait-point-point).</li>
<li>l'épaisseur du trait en pixel (de 1 à 5) ou EMPTY pour aucun changement d'épaisseur.</li>
<li>la couleur (clrNONE pour aucun changement de couleur).</li>
</ul>
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: #674ea7;">SetIndexStyle</span>(noIndex, modeTracage, style, epaisseur, couleur);
</code></pre>
<br />
Pour finir, il faut indiquer la valeur vide à utiliser pour signaler à MetaTrader qu'il n'y a pas de valeur calculée dans une période, lui indiquant ainsi qu'il ne faut pas tracer pour cette période. Cette valeur vide par défaut pour chaque index est <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #0b5394;">EMPTY_VALUE</span> </code>. On la reçoit en argument avec cette valeur par défaut.
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: #674ea7;">SetIndexEmptyValue</span>(noIndex, valeurVide);
</code></pre>
<br />
La fonction d'initialisation de l'index reçoit tous ces paramètres et exécute les lignes de code précédentes. Elle ne retourne aucune valeur, elle est donc du type void:
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">void</span> initIndex(<span style="color: blue;">int</span> noIndex, <span style="color: blue;">double</span> &tamponHistorique[], <span style="color: blue;">int</span> decalagePeriodes,
<span style="color: blue;">int</span> debutTracage=<span style="color: #38761d;">0</span>, <span style="color: blue;">string</span> intitule=<span style="color: #45818e;">""</span>,
<span style="color: blue;">color</span> couleur=<span style="color: #0b5394;">clrNONE</span>, <span style="color: blue;">int</span> style=<span style="color: #0b5394;">STYLE_SOLID</span>,
<span style="color: blue;">int</span> modeTracage=<span style="color: #0b5394;">DRAW_LINE</span>, <span style="color: blue;">int</span> epaisseur=<span style="color: #0b5394;">EMPTY</span>,
<span style="color: blue;">double</span> valeurVide=<span style="color: #0b5394;">EMPTY_VALUE</span>) {
<span style="color: #674ea7;">SetIndexBuffer</span>(noIndex, tamponHistorique);
<span style="color: #674ea7;">SetIndexShift</span>(noIndex, decalagePeriodes);
<span style="color: #674ea7;">SetIndexDrawBegin</span>(noIndex, debutTracage);
<span style="color: #674ea7;">SetIndexLabel</span>(noIndex, intitule);
<span style="color: #674ea7;">SetIndexStyle</span>(noIndex, modeTracage, style, epaisseur, couleur);
<span style="color: #674ea7;">SetIndexEmptyValue</span>(noIndex, valeurVide);
}
</code></pre>
</div>
<br />
<h3 style="font-weight: bold; text-decoration: underline;">
Le tutoriel vidéo et le code complet de l'include
</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='640' height='480' src='https://www.youtube.com/embed/fxEhovvT3e0?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<br />
<div style="text-align: justify; text-indent: 3em;">
Voici le fichier include «OutilsIndicateurs.mqh» que nous créons dans sa première version:
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| OutilsIndicateurs.mqh |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property</span> <span style="color: #30088c;">copyright</span> <span style="color: #45818e;">"Copyright 2014, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property</span> <span style="color: #30088c;"> link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: blue;">#property</span> <span style="color: #30088c;"> strict</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Defines |
//+------------------------------------------------------------------+</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Constantes |
//+------------------------------------------------------------------+</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Fonctions d'initialisation |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">void</span> initIndicateur(<span style="color: blue;">string</span> nomCourt) {
<span style="color: blue;">string</span> paireCourante = <span style="color: #674ea7;">Symbol</span>();
<span style="color: blue;">int</span> nombreDecimales = <span style="color: #674ea7;">MarketInfo</span>(paireCourante, <span style="color: #0b5394;">MODE_DIGITS</span>);
<span style="color: #674ea7;">IndicatorDigits</span>(nombreDecimales);
<span style="color: #674ea7;">IndicatorShortName</span>(nomCourt);
}
<span style="color: blue;">void</span> initIndex(<span style="color: blue;">int</span> noIndex, <span style="color: blue;">double</span> &tamponHistorique[], <span style="color: blue;">int</span> decalagePeriodes,
<span style="color: blue;">int</span> debutTracage=<span style="color: #38761d;">0</span>, <span style="color: blue;">string</span> intitule=<span style="color: #45818e;">""</span>,
<span style="color: blue;">color</span> couleur=<span style="color: #0b5394;">clrNONE</span>, <span style="color: blue;">int</span> style=<span style="color: #0b5394;">STYLE_SOLID</span>,
<span style="color: blue;">int</span> modeTracage=<span style="color: #0b5394;">DRAW_LINE</span>, <span style="color: blue;">int</span> epaisseur=<span style="color: #0b5394;">EMPTY</span>,
<span style="color: blue;">double</span> valeurVide=<span style="color: #0b5394;">EMPTY_VALUE</span>) {
<span style="color: #674ea7;">SetIndexBuffer</span>(noIndex, tamponHistorique);
<span style="color: #674ea7;">SetIndexShift</span>(noIndex, decalagePeriodes);
<span style="color: #674ea7;">SetIndexDrawBegin</span>(noIndex, debutTracage);
<span style="color: #674ea7;">SetIndexLabel</span>(noIndex, intitule);
<span style="color: #674ea7;">SetIndexStyle</span>(noIndex, modeTracage, style, epaisseur, couleur);
<span style="color: #674ea7;">SetIndexEmptyValue</span>(noIndex, valeurVide);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span>
</code></pre>
Et voilà de quoi nous soulager pour programmer des indicateurs ! Nous allons évidemment tester ce code dès le prochain post pour garantir que le tout fonctionne !
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-15954771444495750252014-02-28T22:05:00.000+01:002015-06-01T19:58:55.691+02:00Création d'un fichier include .mqh d'arithmétique des cotations<br />
<h3 style="text-decoration: underline;">
L'objectif:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Nous avons commencé la création de fichiers include (.mqh) pour y mettre des fonctions réutilisables et dans lesquelles on peut avoir confiance car les fonctions sont testées et nous n'avons plus qu'à nous concentrer sur notre code principal et plus sur les petits détails. Ces fonctions pour le premier include concernent les calculs sur le temps: c'est le fichier «ArithmetiqueTemporelle.mqh», et nous y avons mis quatre fonctions pour l'instant. Nous allons maintenant attaquer un fichier include pour l'arithmétique des cotations: «ArithmetiqueCotations.mqh». Nous y mettrons dès le présent post, des fonctions de moyennes et d'écarts.<br />
<ul>
<li style="text-indent: 0;">obtenirCoursReelActuel()</li>
<li style="text-indent: 0;">obtenirCoursMedian()</li>
<li style="text-indent: 0;">obtenirCoursPondere()</li>
<li style="text-indent: 0;">obtenirSpreadActuel()</li>
</ul>
Nullement besoin d'expliquer longtemps car les noms sont assez expressifs. Je vais tout de même donnez des détails techniques sur ces fonctions.
</div>
<br />
<h3 style="text-decoration: underline;">
Une fonction de contrôle du décalage de l'historique:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Nous aurons besoin pour deux des fonctions de cet include, d'un code de contrôle du décalage dans l'historique. Nous allons passer à deux des fonctions, un nombre entier qui représente un numéro de période en remontant dans l'historique. Mais ce numéro ne doit pas être négatif, ni être supérieur ou égal au nombre de périodes dans l'historique. Le nombre de périodes de l'historique est stocké dans la variable prédéfinie <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">Bars</span> </code>, et l'historique va de la période n°0 (celle en cours) à la période n°Bars-1 (la plus vieille de l'historique). On va donc créer cette fonction qui reçoit le décalage à contrôler et retourne une valeur booléenne pour dire s'il est valide ou non. Le code de cette fonction est simplement un test de ces conditions dont le résultat vrai ou faux est stockée dans une variable booléenne. Si le décalage est non valide, on affiche le message d'erreur avec le nom de la fonction reçu aussi en argument et la valeur erronée. Ensuite la valeur du test est retournée au code appelant:
</div>
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code style="background-color: white; color: black; font-weight: bold;"><code>
<span style="color: blue;">bool</span> leDecalageEstIlValide(<span style="color: blue;">int</span> decalage, <span style="color: blue;">string</span> nomFonction) {
<span style="color: blue;">bool</span> decalageEstValide = (decalage >= <span style="color: #38761d;">0</span>) && (decalage < <span style="color: magenta;">Bars</span>);
<span style="color: blue;">if</span>(!decalageEstValide) { <span style="color: #674ea7;">Alert</span>(nomFonction, msgErrDecalageNonValide, decalage); }
<span style="color: blue;">return</span>(decalageEstValide);
}
</code></code></pre>
<code style="background-color: white; color: black; font-weight: bold;">
</code>
<br />
<h3 style="text-decoration: underline;">
obtenirCoursReelActuel():
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Il s'agit ici d'obtenir le dernier cours réel estimé reçu par MetaTrader. Je fais la simple moyenne du Bid et du Ask, car le cours réel est grosso modo au milieu des deux. Ceci est en conflit avec les cotations dans l'historique qui ne concernent que le Bid. Si on veut juste le dernier Bid reçu, pas besoin de fonction: il suffit simplement d'utiliser la variable prédéfinie <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">Bid</span> </code> ! Et c'est bien plus court :) Pour cette fonction nous n'avons aucun paramètre à lui fournir et nous demandons qu'une seule chose: le dernier cours reçu. Elle utilise les deux variables prédéfinies <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">Bid</span> </code> et <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">Ask</span> </code>, les additionne et divise par deux la somme. Et il n'y a qu'à retourner ce résultat. Elle est très courte:<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">double</span> obtenirCoursReelActuel() {
<span style="color: blue;">double</span> coursReelActuel = (<span style="color: magenta;">Bid</span> + <span style="color: magenta;">Ask</span>) / <span style="color: #38761d;">2.0</span>;
<span style="color: blue;">return</span>(coursReelActuel);
}
</code></pre>
</div>
<br />
<h3 style="text-decoration: underline;">
obtenirCoursMedian():
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Par cours médian, les traders comprennent la moyenne du plus bas et du plus haut de la période. Nous voulons ici, non pas avoir le tout dernier cours médian reçu, cela n'a aucun sens, mais avoir le cours médian d'une période dans l'historique. Elle peut être n'importe laquelle de l'historique ou bien celle qui est en cours et qui n'est pas encore finie, et dans ce cas le cours médian évolue en temps réel, au fur et à mesure que les cotations arrivent. Dès que la période est finie, ce cours est fixé et ne changera plus pour cette période. Elle était numérotée 0, et devient d'un coup, la numéro 1 en remontant l'historique.<br />
Il faut au moins un paramètre: le décalage à faire dans l'historique pour tomber sur la période voulue. 0 étant la période actuelle. C'est un nombre entier positif ou nul qui grandit en remontant l'historique des périodes. Ce décalage doit aussi être inférieur au nombre de périodes contenues dans l'historique, et ce nombre est stocké dans la variable prédéfinie <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">Bars</span> </code>. La numérotation des périodes de l'historique allant de 0 à <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">Bars</span>-1 </code>. On doit alors tester que ce paramètre ne soit pas négatif et aussi qu'il ne soit pas strictement supérieur à <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">Bars</span> </code>. S'il ne l'est pas, on peut récupérer le <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">High</span>[] </code> et le <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">Low</span>[] </code> de la période. (ce sont des tableaux dont l'indice est le décalage pour remonter l'historique.) On additionne ces deux valeurs et on divise par deux. Si le décalage est négatif ou bien supérieur à <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">Bars</span> </code>, on ne peut pas faire ça, et l'alerte avec un message d'erreur et la valeur erronée a déjà été levée dans la fonction de test du décalage. On doit alors retourner un code d'erreur. Ce code d'erreur est placé dès le départ, à l'initialisation de la variable à retourner, et si le calcul normal est fait, ce code est écrasé par le résultat que la fonction doit retourner. Il ne reste plus qu'à retourner cette variable:<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">double</span> obtenirCoursMedian(<span style="color: blue;">int</span> decalage) {
<span style="color: blue;">double</span> coursMedian = ERREUR_DOUBLE;
<span style="color: blue;">bool</span> decalageEstValide = leDecalageEstIlValide(decalage, nomObtenirCoursMedian);
<span style="color: blue;">if</span>(decalageEstValide) { coursMedian = (<span style="color: magenta;">High</span>[decalage] + <span style="color: magenta;">Low</span>[decalage]) / <span style="color: #38761d;">2.0</span>; }
<span style="color: blue;">return</span>(coursMedian);
}
</code></pre>
</div>
<br />
<h3 style="text-decoration: underline;">
obtenirCoursPondere():
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Par pondéré, j'entends pondéré par les quatre valeurs de cotations de chaque période: le plus haut, le plus bas, l'ouverture et la fermeture. Cette valeur que j'appelle pondérée est plus précise que la valeur médiane si on vise la valeur moyenne de la période. (les traders ont l'habitude de n'utiliser que la valeur médiane en cherchant à avoir une pseudo-valeur moyenne !). J'utilise et vous propose un calcul plus proche de la vraie valeur moyenne. Pour une vraie moyenne, il faudrait avoir toutes les valeurs du cours de la période, or il n'en reste que quatre. Autant faire le calcul avec ces quatre, ce sera plus proche de la vraie moyenne. (Les traders utilisent même des moyennes pondérées par une valeur psychologique: il mettent 2 fois le close, en pensant que cette valeur à plus d'importance parce qu'elle clôt la période et donne le sens d'évolution des cours de la période. Ce qui est totalement faux, car le close d'une période est juste à côté de l'open de la suivante, et n'a pas de position privilégiée. La preuve, si on décale l'horloge d'une seconde, l'open devient le close de la période précédente et le close n'est plus considérée car oubliée comme la plupart des valeurs de la période. Autant faire le trading avec un gri-gri pour porter chance =D En fait seul les chandeliers journaliers pour les actions ont un close qui a une signification plus importante car à la fin de la journée de trading il y a en général une impulsion plus forte qui donne un mouvement représentatif de toute la séance et de plus il y a une coupure temporelle entre un close journalier et l'open suivant provoquant une psychologie de la foule des traders différente pour le chandelier suivant puisque demain est un autre jour, ce qui n'est pas le cas pour le forex qui ne ferme pas la nuit, mais seulement en fin de semaine. On observe tout de même une psychologie de marché sur le forex différente d'un jour à l'autre.)</div>
<div style="text-align: justify; text-indent: 3em;">
Sur le même modèle que la fonction précédente, on fait le calcul avec les quatre valeurs <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">High</span>[], <span style="color: magenta;">Low</span>[], <span style="color: magenta;">Open</span>[] et <span style="color: magenta;">Close</span>[] </code>. On les additionne et on divise par quatre. Même algorithme que la précédente:<br />
<ul>
<li style="text-indent: 0;">on reçoit en argument qui doit être positif ou nul, le décalage dans l'historique.</li>
<li style="text-indent: 0;">on initialise la variable qui contiendra le résultat avec le code d'erreur</li>
<li style="text-indent: 0;">on teste la validité du décalage reçu en argument</li>
<li style="text-indent: 0;">s'il l'est, on fait le calcul qu'on met dans la variable en écrasant le code d'erreur</li>
<li style="text-indent: 0;">on retourne le contenu de la variable.</li>
</ul>
</div>
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">double</span> obtenirCoursPondere(<span style="color: blue;">int</span> decalage) {
<span style="color: blue;">double</span> coursPondere = ERREUR_DOUBLE;
<span style="color: blue;">bool</span> decalageEstValide = leDecalageEstIlValide(decalage, nomObtenirCoursPondere);
<span style="color: blue;">if</span>(decalageEstValide) {
coursPondere = (<span style="color: magenta;">High</span>[decalage]+<span style="color: magenta;">Low</span>[decalage]+<span style="color: magenta;">Open</span>[decalage]+<span style="color: magenta;">Close</span>[decalage]) / <span style="color: #38761d;">4.0</span>;
}
<span style="color: blue;">return</span>(coursPondere);
}
</code></pre>
<br />
<h3 style="text-decoration: underline;">
obtenirSpreadActuel():
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Contrairement aux trois précédentes fonctions qui étaient des moyennes, le spread est un écart: la différence entre le Bid et le Ask. C'est la marge du broker proportionnelle au capital mis en jeu dans la position ouverte. Il est important d'avoir ce spread, car lorsqu'on ouvre une position, il faut impérativement fermer lorsque le cours a eu une variation supérieure au spread. Eh oui, car le broker prend la valeur du spread quoi qu'il arrive, et donc il nous faut un écart de cours supérieur au spread pour être gagnant (et que le cours ait varié dans le bon sens, ça c'est l'évidence !) Étant donné que l'historique ne contient pas les valeurs Ask, nous ne pouvons le calculer que sur la dernière cotation reçue.<br />
C'est une fonction très simple, sans paramètre, car il n'y a pas de choix à faire: le spread de la dernière cotation reçue est le spread actuel, rien d'autre ! On fait donc la différence entre les variables prédéfinies: <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">Ask</span> - <span style="color: magenta;">bid</span> </code> et on retourne ce résultat !</div>
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">double</span> obtenirSpreadActuel() {
<span style="color: blue;">double</span> spread = <span style="color: magenta;">Ask</span> - <span style="color: magenta;">Bid</span>;
<span style="color: blue;">return</span>(spread);
}
</code></pre>
<br />
<h3 style="text-decoration: underline;">
Les constantes de messages:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Pour les besoins de ces fonctions, nous devons écrire quelques constantes de message d'erreur et des noms de fonctions:
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">string</span> nomObtenirCoursReelActuel = <span style="color: #45818e;">"obtenirCoursReelActuel()"</span>;
<span style="color: blue;">string</span> nomObtenirCoursMedian = <span style="color: #45818e;">"obtenirCoursMedian()"</span>;
<span style="color: blue;">string</span> nomObtenirCoursPondere = <span style="color: #45818e;">"obtenirCoursPondere()"</span>;
<span style="color: blue;">string</span> nomObtenirSpreadActuel = <span style="color: #45818e;">"obtenirSpreadActuel()"</span>;
<span style="color: blue;">string</span> msgErrDecalageNonValide = <span style="color: #45818e;">" a reçu un argument de
<span style="color: #999999;">// ligne coupée pour des raisons de largeur du post, ne pas la couper:</span>
décalage historique négatif ou alors supérieur à Bars: "</span>;
</code></pre>
</div>
<br />
<h3 style="text-decoration: underline;">
Modification de l'include UtilitairesTests.mqh:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Pour les besoins des tests, nous allons améliorer notre fichier include d'utilitaires des tests et rectifier un petit bug insignifiant. Première chose, nous allons mutualiser des constantes de chaines de texte pour ne pas avoir à les écrire à chaque fois et pour centraliser les données. La première sert à faire un bilan de test par fonction, les deux autres pour servir de séparateurs dans l'affichage du journal pour s'y retrouver plus facilement. Ces constantes sont:
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">string</span> msgBilanTestFonction = <span style="color: #45818e;">" a terminé ses tests avec un total d'erreurs de "</span>;
<span style="color: #999999;">// la nouvelle version de l'éditeur qui vient d'arriver cette semaine:
// nous permet d'ouvrir une chaine avec un type de guillemet (simple ou double)
// pour la refermer avec le même et d'insérer l'autre type de guillemet sans
// l'antislash pour échapper la signification de fermeture de chaine.</span>
<span style="color: blue;">string</span> SEPARATEUR = <span style="color: #45818e;">"-------------------------------------------------------"</span>;
<span style="color: blue;">string</span> SEPARATEUR_DOUBLE = <span style="color: #45818e;">"================================================"</span>;
</code></pre>
Nous rectifions également dans ce fichier une fonction d'analyse de résultat de test: celle du type double. En effet, lors de l'affichage de l'erreur, le dernier paramètre passé à la fonction <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">Print</span>() </code> est le nombre décimal tel quel ! Or si la fonction <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">Print</span>() </code> l'accepte sans problème, elle tronque tout de même les décimales à la cinquième et arrondi. Vous verriez sans la modification suivante qu'un arrondi et non la valeur exacte de notre constante <code style="background-color: white; color: black; font-weight: bold;"> ERREUR_DOUBLE </code> avec 10 décimales. C'est un problème mineur d'affichage qui ne gène pas le fonctionnement du programme. La modification est la suivante: on ne transmet pas la variable resultat directement à la fonction <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">Print</span>() </code>, mais à une fonction de conversion <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">DoubleToStr</span>() </code> qui comme son nom le suggère, va nous prendre un type <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">double</span> </code> pour en faire un <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">string</span> </code> qui est le type normalement demandé par la fonction <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">Print</span>() </code>. L'avantage est qu'elle demande le nombre de décimales à fournir en second paramètre. La ligne à modifier est celle du deuxième <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">Print</span>() </code>:</div>
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: #674ea7;">Print</span>(nomFonction, msgErreur, parametresCas, <span style="color: #674ea7;">DoubleToStr</span>(resultatTest, <span style="color: #38761d;">10</span>));
</code></pre>
<br />
<h3 style="text-decoration: underline;">
Les tests de ces fonctions:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Nous réalisons immédiatement le test des fonctions sans attendre dans le fichier d'un expert advisor nommé testsArithmetiqueCotations.mq4. Il n'y aura pas grand chose à tester d'autant plus que la plupart des valeurs utilisées par ces fonctions sont récupérées dans les variables prédéfinies. Mais nous faisons les tests par principe, même si certains sont pour le moment pas très utiles. Du moins on a l'impression que certains seront inutiles, mais à l'avenir, si on modifie une fonction, il y aura déjà le test auquel on ajoute des cas. En plus, même s'il ne teste pas la réaction de la fonction face à un paramètre, il permet d'affirmer qu'il n'y a pas d'erreur de frappe et que le code fonctionne.</div>
<br />
<table border="1" style="text-align: center;">
<caption style="font-weight: bold;">obtenirCoursReelActuel()</caption>
<thead style="background-color: #dddddd; color: black;">
<tr><th>n°cas</th><th>résultat attendu</th><th>commentaires</th>
</tr>
</thead>
<tbody>
<tr><td>1</td><td>(Bid+Ask)/2.0</td><td>étant donné que le résultat attendu est calculé avec les même valeurs que celles prises par la fonction, ils doit concorder avec celui de la fonction. Ce test est utile pour prouver qu'il n'y a pas d'erreur de syntaxe et que le code fonctionne bien qu'il soit minimaliste.</td></tr>
</tbody>
</table>
<br />
<table border="1" style="text-align: center;">
<caption style="font-weight: bold;">obtenirCoursMedian()</caption>
<thead style="background-color: #dddddd; color: black;">
<tr><th>n°cas</th><th>decalage</th><th>résultat attendu</th><th>commentaires</th>
</tr>
</thead>
<tbody>
<tr><td>1</td><td>0</td><td>(High[0]+Low[0]) /2.0</td><td>Période actuelle. Dans tous les cas nous ne pouvons pas prévoir le résultat du calcul, d'où le même calcul que dans la fonction en résultat attendu.</td></tr>
<tr><td>2</td><td>10</td><td>(High[10]+Low[10]) /2.0</td><td>Idem.</td></tr>
<tr><td>3</td><td>Bars-1</td><td>(High[Bars-1]+Low[Bars-1]) /2.0</td><td>Décalage valide car strictement inférieur à Bars, c'est la première période chronologique contenue dans l'historique.</td></tr>
<tr><td>4</td><td>-10</td><td>ERREUR_DOUBLE</td><td>Décalage négatif, donc alerte levée et retour d'un code d'erreur.</td></tr>
<tr><td>5</td><td>Bars</td><td>ERREUR_DOUBLE</td><td>Décalage égal à Bars, donc alerte levée et retour d'un code d'erreur.</td></tr>
<tr><td>6</td><td>1 000 000</td><td>ERREUR_DOUBLE</td><td>Décalage supérieur à Bars, donc alerte levée et retour d'un code d'erreur.</td></tr>
</tbody>
</table>
<br />
<table border="1" style="text-align: center;">
<caption style="font-weight: bold;">obtenirCoursPondere()</caption>
<thead style="background-color: #dddddd; color: black;">
<tr><th>n°cas</th><th>decalage</th><th>résultat attendu</th><th>commentaires</th>
</tr>
</thead>
<tbody>
<tr><td>1</td><td>0</td><td>(High[0]+Low[0]+ Open[10]+Close[10]) /4.0</td><td>Période actuelle. Dans tous les cas nous ne pouvons pas prévoir le résultat du calcul d'où le même calcul que dans la fonction en résultat attendu.</td></tr>
<tr><td>2</td><td>10</td><td>(High[10]+Low[10]+ Open[10]+Close[10]) /4.0</td><td>Idem.</td></tr>
<tr><td>3</td><td>Bars-1</td><td>(High[Bars-1]+Low[Bars-1]+ Open[Bars-1]+Close[Bars-1]) /4.0</td><td>Décalage valide car strictement inférieur à Bars, c'est la première période chronologique contenue dans l'historique.</td></tr>
<tr><td>4</td><td>-10</td><td>ERREUR_DOUBLE</td><td>Décalage négatif, donc alerte levée et retour d'un code d'erreur.</td></tr>
<tr><td>5</td><td>Bars</td><td>ERREUR_DOUBLE</td><td>Décalage égal à Bars, donc alerte levée et retour d'un code d'erreur.</td></tr>
<tr><td>6</td><td>1 000 000</td><td>ERREUR_DOUBLE</td><td>Décalage supérieur à Bars, donc alerte levée et retour d'un code d'erreur.</td></tr>
</tbody>
</table>
<br />
<table border="1" style="text-align: center;">
<caption style="font-weight: bold;">obtenirSpreadActuel()</caption>
<thead style="background-color: #dddddd; color: black;">
<tr><th>n°cas</th><th>résultat attendu</th><th>commentaires</th>
</tr>
</thead>
<tbody>
<tr><td>1</td><td>Ask-Bid</td><td>étant donné que le résultat attendu est calculé avec les même valeurs que celles prises par la fonction, il doit concorder avec celui de la fonction. Ce test est utile pour prouver qu'il n'y a pas d'erreur de syntaxe et que le code fonctionne bien qu'il soit minimaliste.</td></tr>
</tbody>
</table>
<br />
<div style="text-align: justify; text-indent: 3em;">
Il y a quelques différences avec le premier module de tests réalisé précédemment. Premièrement les valeurs de résultats sont du type <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">double</span> </code> au lieu de <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">datetime</span> </code>. Il faut les changer tous dans la valeur de retour des fonctions d'exécution et leurs variables resultat à l'intérieur et dans les tableaux des résultats attendus de chaque fonction de test.<br />
Ensuite, la fonction du cours actuel et celle du spread actuel n'ont qu'un seul test, mais surtout elle ne prennent aucun argument. Nous laissons pour elles, le code de test sous forme d'une fonction de test et d'une fonction d'exécution car à l'avenir, il est possible d'ajouter un paramètre optionnel à ces deux fonctions et donc d'avoir besoin de la fonction d'exécution. Le code de la fonction d'exécution pour ces deux-là change: la variable résultat prend une valeur par défaut qui est <code style="background-color: white; color: black; font-weight: bold;"> ERREUR_DOUBLE </code>. Dans ces deux fonctions d'exécution nous réalisons l'exécution de la fonction testée que si l'argument est la constante <code style="background-color: white; color: black; font-weight: bold;"> ARG_STRING_EMPTY </code> (l'argument est du type <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">string</span> </code> car s'il venait à y avoir un argument optionnel à la fonction testée, ce serait une chaine de caractères pour désigner la paire de devises).
<br />
Il y a aussi les fonctions de tests des deux autres, qui ont un argument mais obligatoire, donc dans ces deux cas l'exécution de la fonction testée ne se fait que si l'argument est différent de <code style="background-color: white; color: black; font-weight: bold;"> ARG_INT_EMPTY </code> et il n'y a pas de cas alternatif sans argument, juste une clause <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">if</span> </code> comme pour les deux précédentes.<br />
Puis pour les fonctions de cours médian et de cours pondéré, les arguments <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">Bars</span> </code> et <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">Bars</span>-1 </code> ne peuvent être mis dans la déclaration du tableau avec les autres valeurs car le compilateur, malgré sa version nouvelle, n'accepte toujours pas une variable lors de la déclaration d'un tableau. Nous devons donc y mettre une valeur, par exemple <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #38761d;">1</span> </code> et les remplacer desuite après par <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">Bars</span> </code> et <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: magenta;">Bars</span>-1 </code>.<br />
Enfin nous ajoutons pour une question de lisibilité des résultats de tests, un <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">Print</span>() </code> bilan du nombre d'erreurs de la fonction testée à la fin de chaque fonction de test, et encadré par deux <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">Print</span>() </code> de lignes de séparation. Pour une question de code clair et non redondant, nous plaçons ces trois lignes de code dans une fonction spéciale dans le fichier UtilitairesTests.mqh. On la nomme afficherBilanTestFonction() et on l'appellera en une ligne en lui passant le nom de la fonction testée et le nombre d'erreurs du test. Voici son code:<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">void</span> afficherBilanTestFonction(<span style="color: blue;">string</span> nomFonction, <span style="color: blue;">int</span> nbErreurs) {
<span style="color: #674ea7;">Print</span>(SEPARATEUR);
<span style="color: #674ea7;">Print</span>(nomFonction, msgBilanTestFonction, nbErreurs);
<span style="color: #674ea7;">Print</span>(SEPARATEUR_DOUBLE);
}
</code></pre>
Pour rappel les constantes des noms de fonctions sont désormais définies dans les fichiers où les fonctions sont codées, et non plus dans le fichier de tests. Le code correspondant à tout ça est donné en intégralité à la fin du post.</div>
<br />
<h3 style="text-decoration: underline;">
Le tutoriel vidéo et les trois codes complets:
</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='640' height='480' src='https://www.youtube.com/embed/NdeHNcuMH2U?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| UtilitairesTests.mqh |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2014, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#define</span> ARG_STRING_EMPTY <span style="color: #45818e;">"-#-EMPTY-#-"</span>
<span style="color: blue;">#define</span> ARG_INT_EMPTY <span style="color: #38761d;">2147483647</span>
<span style="color: blue;">#define</span> ARG_BOOL_EMPTY -<span style="color: #38761d;">1</span>
<span style="color: blue;">#define</span> ARG_DOUBLE_EMPTY <span style="color: #38761d;">123456789</span>.<span style="color: #38761d;">123456789</span>
<span style="color: blue;">#define</span> ARG_DATETIME_EMPTY <span style="color: #38761d;">4294967295</span>
<span style="color: blue;">#define</span> ARG_COLOR_EMPTY <span style="color: #38761d;">4294967295</span>
<span style="color: blue;">#define</span> MESSAGE_ERREUR <span style="color: #45818e;">" a produit une erreur de résultat avec le cas "</span>
<span style="color: blue;">#define</span> MESSAGE_SUCCES <span style="color: #45818e;">" a passé le test sans erreurs "</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| constantes de tests |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">string</span> msgBilanTestFonction = <span style="color: #45818e;">" a terminé ses tests avec un total d'erreurs de "</span>;
<span style="color: blue;">string</span> SEPARATEUR = <span style="color: #45818e;">"-------------------------------------------------------"</span>;
<span style="color: blue;">string</span> SEPARATEUR_DOUBLE = <span style="color: #45818e;">"================================================"</span>;
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Fonctions d'affichage |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">void</span> afficherBilanTestFonction(<span style="color: blue;">string</span> nomFonction, <span style="color: blue;">int</span> nbErreurs) {
<span style="color: #674ea7;">Print</span>(SEPARATEUR);
<span style="color: #674ea7;">Print</span>(nomFonction, msgBilanTestFonction, nbErreurs);
<span style="color: #674ea7;">Print</span>(SEPARATEUR_DOUBLE);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Fonctions d'analyse |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> analyserResultatDatetimeDuTest(
<span style="color: blue;">datetime</span> resultatTest, <span style="color: blue;">datetime</span> resultatAttendu,
<span style="color: blue;">string</span> nomFonction, <span style="color: blue;">string</span> parametresCas,
<span style="color: blue;">string</span> msgErreur = MESSAGE_ERREUR, <span style="color: blue;">string</span> msgSucces = MESSAGE_SUCCES) {
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">if</span>(resultatTest == resultatAttendu) {
<span style="color: #674ea7;">Print</span>(nomFonction, msgSucces, resultatTest);
} <span style="color: blue;">else</span> {
<span style="color: #674ea7;">Print</span>(nomFonction, msgErreur, parametresCas, resultatTest);
nbErreurs++;
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: blue;">int</span> analyserResultatIntDuTest(
<span style="color: blue;">int</span> resultatTest, <span style="color: blue;">int</span> resultatAttendu,
<span style="color: blue;">string</span> nomFonction, <span style="color: blue;">string</span> parametresCas,
<span style="color: blue;">string</span> msgErreur = MESSAGE_ERREUR, <span style="color: blue;">string</span> msgSucces = MESSAGE_SUCCES) {
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">if</span>(resultatTest == resultatAttendu) {
<span style="color: #674ea7;">Print</span>(nomFonction, msgSucces, resultatTest);
} <span style="color: blue;">else</span> {
<span style="color: #674ea7;">Print</span>(nomFonction, msgErreur, parametresCas, resultatTest);
nbErreurs++;
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: blue;">int</span> analyserResultatBoolDuTest(
<span style="color: blue;">bool</span> resultatTest, <span style="color: blue;">bool</span> resultatAttendu,
<span style="color: blue;">string</span> nomFonction, <span style="color: blue;">string</span> parametresCas,
<span style="color: blue;">string</span> msgErreur = MESSAGE_ERREUR, <span style="color: blue;">string</span> msgSucces = MESSAGE_SUCCES) {
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">if</span>(resultatTest == resultatAttendu) {
<span style="color: #674ea7;">Print</span>(nomFonction, msgSucces, resultatTest);
} <span style="color: blue;">else</span> {
<span style="color: #674ea7;">Print</span>(nomFonction, msgErreur, parametresCas, resultatTest);
nbErreurs++;
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: blue;">int</span> analyserResultatDoubleDuTest(
<span style="color: blue;">double</span> resultatTest, <span style="color: blue;">double</span> resultatAttendu,
<span style="color: blue;">string</span> nomFonction, <span style="color: blue;">string</span> parametresCas,
<span style="color: blue;">string</span> msgErreur = MESSAGE_ERREUR, <span style="color: blue;">string</span> msgSucces = MESSAGE_SUCCES) {
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">if</span>(resultatTest == resultatAttendu) {
<span style="color: #674ea7;">Print</span>(nomFonction, msgSucces, resultatTest);
} <span style="color: blue;">else</span> {
<span style="color: #674ea7;">Print</span>(nomFonction, msgErreur, parametresCas, <span style="color: #674ea7;">DoubleToStr</span>(resultatTest, <span style="color: #38761d;">10</span>));
nbErreurs++;
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: blue;">int</span> analyserResultatStringDuTest(
<span style="color: blue;">string</span> resultatTest, <span style="color: blue;">string</span> resultatAttendu,
<span style="color: blue;">string</span> nomFonction, <span style="color: blue;">string</span> parametresCas,
<span style="color: blue;">string</span> msgErreur = MESSAGE_ERREUR, <span style="color: blue;">string</span> msgSucces = MESSAGE_SUCCES) {
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">if</span>(resultatTest == resultatAttendu) {
<span style="color: #674ea7;">Print</span>(nomFonction, msgSucces, resultatTest);
} <span style="color: blue;">else</span> {
<span style="color: #674ea7;">Print</span>(nomFonction, msgErreur, parametresCas, resultatTest);
nbErreurs++;
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: blue;">int</span> analyserResultatColorDuTest(
<span style="color: blue;">color</span> resultatTest, <span style="color: blue;">color</span> resultatAttendu,
<span style="color: blue;">string</span> nomFonction, <span style="color: blue;">string</span> parametresCas,
<span style="color: blue;">string</span> msgErreur = MESSAGE_ERREUR, <span style="color: blue;">string</span> msgSucces = MESSAGE_SUCCES) {
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">if</span>(resultatTest == resultatAttendu) {
<span style="color: #674ea7;">Print</span>(nomFonction, msgSucces, resultatTest);
} <span style="color: blue;">else</span> {
<span style="color: #674ea7;">Print</span>(nomFonction, msgErreur, parametresCas, resultatTest);
nbErreurs++;
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span>
</code>
</pre>
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| ArithmetiqueCotations.mqh |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property</span> <span style="color: #30088c;">copyright</span> <span style="color: #45818e;">"Copyright 2014, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property</span> <span style="color: #30088c;"> link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: blue;">#property</span> <span style="color: #30088c;"> strict</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Defines |
//+------------------------------------------------------------------+</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Constantes |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">string</span> nomObtenirCoursReelActuel = <span style="color: #45818e;">"obtenirCoursReelActuel()"</span>;
<span style="color: blue;">string</span> nomObtenirCoursMedian = <span style="color: #45818e;">"obtenirCoursMedian()"</span>;
<span style="color: blue;">string</span> nomObtenirCoursPondere = <span style="color: #45818e;">"obtenirCoursPondere()"</span>;
<span style="color: blue;">string</span> nomObtenirSpreadActuel = <span style="color: #45818e;">"obtenirSpreadActuel()"</span>;
<span style="color: blue;">string</span> msgErrDecalageNonValide = <span style="color: #45818e;">" a reçu un argument de décalage
<span style="color: red; text-decoration: blink;">ligne coupée pour des raisons de largeur de post ! Recollez-là</span>
historique négatif ou alors supérieur à Bars: "</span>;
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Fonctions de contrôle |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">bool</span> leDecalageEstIlValide(<span style="color: blue;">int</span> decalage, <span style="color: blue;">string</span> nomFonction) {
<span style="color: blue;">bool</span> decalageEstValide = (decalage >= <span style="color: #38761d;">0</span>) && (decalage < <span style="color: magenta;">Bars</span>);
<span style="color: blue;">if</span>(!decalageEstValide) { <span style="color: #674ea7;">Alert</span>(nomFonction, msgErrDecalageNonValide, decalage); }
<span style="color: blue;">return</span>(decalageEstValide);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Fonctions de Moyennes |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">double</span> obtenirCoursReelActuel() {
<span style="color: blue;">double</span> coursReelActuel = (<span style="color: magenta;">Bid</span> + <span style="color: magenta;">Ask</span>) / <span style="color: #38761d;">2.0</span>;
<span style="color: blue;">return</span>(coursReelActuel);
}
<span style="color: blue;">double</span> obtenirCoursMedian(<span style="color: blue;">int</span> decalage) {
<span style="color: blue;">double</span> coursMedian = ERREUR_DOUBLE;
<span style="color: blue;">bool</span> decalageEstValide = leDecalageEstIlValide(decalage, nomObtenirCoursMedian);
<span style="color: blue;">if</span>(decalageEstValide) { coursMedian = (<span style="color: magenta;">High</span>[decalage] + <span style="color: magenta;">Low</span>[decalage]) / <span style="color: #38761d;">2.0</span>; }
<span style="color: blue;">return</span>(coursMedian);
}
<span style="color: blue;">double</span> obtenirCoursPondere(<span style="color: blue;">int</span> decalage) {
<span style="color: blue;">double</span> coursPondere = ERREUR_DOUBLE;
<span style="color: blue;">bool</span> decalageEstValide = leDecalageEstIlValide(decalage, nomObtenirCoursPondere);
<span style="color: blue;">if</span>(decalageEstValide) {
coursPondere = (<span style="color: magenta;">High</span>[decalage]+<span style="color: magenta;">Low</span>[decalage]+<span style="color: magenta;">Open</span>[decalage]+<span style="color: magenta;">Close</span>[decalage]) /<span style="color: #38761d;">4.0</span>;
}
<span style="color: blue;">return</span>(coursPondere);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Fonctions d'écarts |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">double</span> obtenirSpreadActuel() {
<span style="color: blue;">double</span> spread = <span style="color: magenta;">Ask</span> - <span style="color: magenta;">Bid</span>;
<span style="color: blue;">return</span>(spread);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span>
</code></pre>
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| testsArithmetiqueCotations.mq4 |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property</span> <span style="color: #30088c;">copyright</span> <span style="color: #45818e;">"Copyright 2014, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property</span> <span style="color: #30088c;"> link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: blue;">#property</span> <span style="color: #30088c;"> version</span> <span style="color: #45818e;">"1.00"</span>
<span style="color: blue;">#property</span> <span style="color: #30088c;"> strict</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Includes |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#include</span> <Constantes.mqh>
<span style="color: blue;">#include</span> <UtilitairesTests.mqh>
<span style="color: blue;">#include</span> <ArithmetiqueCotations.mqh>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Defines |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#define</span> NB_CAS_COURS_REEL_ACTUEL <span style="color: #38761d;">1</span>
<span style="color: blue;">#define</span> NB_CAS_COURS_MEDIAN <span style="color: #38761d;">6</span>
<span style="color: blue;">#define</span> NB_CAS_COURS_PONDERE <span style="color: #38761d;">6</span>
<span style="color: blue;">#define</span> NB_CAS_SPREAD_ACTUEL <span style="color: #38761d;">1</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Fonctions de tests |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">double</span> execObtenirCoursReelActuel(<span style="color: blue;">string</span> argument) {
<span style="color: blue;">double</span> resultat = ERREUR_DOUBLE;
<span style="color: blue;">if</span>(argument == ARG_STRING_EMPTY) { resultat = obtenirCoursReelActuel(); }
<span style="color: blue;">return</span>(resultat);
}
<span style="color: blue;">int</span> testObtenirCoursReelActuel() {
<span style="color: blue;">int</span> noCas, nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">double</span> resultat;
<span style="color: blue;">string</span> arguments[NB_CAS_COURS_REEL_ACTUEL] = {ARG_STRING_EMPTY};
<span style="color: blue;">string</span> parametresCas[NB_CAS_COURS_REEL_ACTUEL] = {<span style="color: #45818e;">" => "</span>};
<span style="color: blue;">double</span> resultatsAttendus[NB_CAS_COURS_REEL_ACTUEL];
resultatsAttendus[<span style="color: #38761d;">0</span>] = (<span style="color: magenta;">Bid</span> + <span style="color: magenta;">Ask</span>) / <span style="color: #38761d;">2.0</span>;
<span style="color: blue;">for</span>(noCas=<span style="color: #38761d;">0</span> ; noCas<NB_CAS_COURS_REEL_ACTUEL ; noCas++) {
resultat = execObtenirCoursReelActuel(arguments[noCas]);
nbErreurs += analyserResultatDoubleDuTest(resultat, resultatsAttendus[noCas],
nomObtenirCoursReelActuel, parametresCas[noCas]);
}
afficherBilanTestFonction(nomObtenirCoursReelActuel, nbErreurs);
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: blue;">double</span> execObtenirCoursMedian(<span style="color: blue;">int</span> argument) {
<span style="color: blue;">double</span> resultat = ERREUR_DOUBLE;
<span style="color: blue;">if</span>(argument != ARG_INT_EMPTY) { resultat = obtenirCoursMedian(argument); }
<span style="color: blue;">return</span>(resultat);
}
<span style="color: blue;">int</span> testObtenirCoursMedian() {
<span style="color: blue;">int</span> noCas, nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">double</span> resultat;
<span style="color: blue;">int</span> arguments[NB_CAS_COURS_MEDIAN] = {<span style="color: #38761d;">0</span>, <span style="color: #38761d;">10</span>, <span style="color: #38761d;">1</span>, <span style="color: #38761d;">-10</span>, <span style="color: #38761d;">1</span>, <span style="color: #38761d;">1000000</span>};
arguments[<span style="color: #38761d;">2</span>] = <span style="color: magenta;">Bars</span>-<span style="color: #38761d;">1</span>;
arguments[<span style="color: #38761d;">4</span>] = <span style="color: magenta;">Bars</span>;
<span style="color: blue;">string</span> parametresCas[NB_CAS_COURS_MEDIAN] = {<span style="color: #45818e;">" 0 => "</span>,<span style="color: #45818e;">" 10 => "</span>,<span style="color: #45818e;">" Bars-1 => "</span>,
<span style="color: #45818e;">" -10 => "</span>,<span style="color: #45818e;">" Bars => "</span>,<span style="color: #45818e;">" 1000000 => "</span>};
<span style="color: blue;">double</span> resultatsAttendus[NB_CAS_COURS_MEDIAN];
resultatsAttendus[<span style="color: #38761d;">0</span>] = (<span style="color: magenta;">High</span>[<span style="color: #38761d;">0</span>] + <span style="color: magenta;">Low</span>[<span style="color: #38761d;">0</span>]) / <span style="color: #38761d;">2.0</span>;
resultatsAttendus[<span style="color: #38761d;">1</span>] = (<span style="color: magenta;">High</span>[<span style="color: #38761d;">10</span>] + <span style="color: magenta;">Low</span>[<span style="color: #38761d;">10</span>]) / <span style="color: #38761d;">2.0</span>;
resultatsAttendus[<span style="color: #38761d;">2</span>] = (<span style="color: magenta;">High</span>[<span style="color: magenta;">Bars</span>-<span style="color: #38761d;">1</span>] + <span style="color: magenta;">Low</span>[<span style="color: magenta;">Bars</span>-<span style="color: #38761d;">1</span>]) / <span style="color: #38761d;">2.0</span>;
resultatsAttendus[<span style="color: #38761d;">3</span>] = ERREUR_DOUBLE;
resultatsAttendus[<span style="color: #38761d;">4</span>] = ERREUR_DOUBLE;
resultatsAttendus[<span style="color: #38761d;">5</span>] = ERREUR_DOUBLE;
<span style="color: blue;">for</span>(noCas=<span style="color: #38761d;">0</span> ; noCas<NB_CAS_COURS_MEDIAN ; noCas++) {
resultat = execObtenirCoursMedian(arguments[noCas]);
nbErreurs += analyserResultatDoubleDuTest(resultat, resultatsAttendus[noCas],
nomObtenirCoursMedian, parametresCas[noCas]);
}
afficherBilanTestFonction(nomObtenirCoursMedian, nbErreurs);
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: blue;">double</span> execObtenirCoursPondere(<span style="color: blue;">int</span> argument) {
<span style="color: blue;">double</span> resultat = ERREUR_DOUBLE;
<span style="color: blue;">if</span>(argument != ARG_INT_EMPTY) { resultat = obtenirCoursPondere(argument); }
<span style="color: blue;">return</span>(resultat);
}
<span style="color: blue;">int</span> testObtenirCoursPondere() {
<span style="color: blue;">int</span> noCas, nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">double</span> resultat;
<span style="color: blue;">int</span> arguments[NB_CAS_COURS_PONDERE] = {<span style="color: #38761d;">0</span>, <span style="color: #38761d;">10</span>, <span style="color: #38761d;">1</span>, <span style="color: #38761d;">-10</span>, <span style="color: #38761d;">1</span>, <span style="color: #38761d;">1000000</span>};
arguments[<span style="color: #38761d;">2</span>] = <span style="color: magenta;">Bars</span>-<span style="color: #38761d;">1</span>;
arguments[<span style="color: #38761d;">4</span>] = <span style="color: magenta;">Bars</span>;
<span style="color: blue;">string</span> parametresCas[NB_CAS_COURS_PONDERE] = {<span style="color: #45818e;">" 0 => "</span>,<span style="color: #45818e;">" 10 => "</span>,<span style="color: #45818e;">" Bars-1 => "</span>,
<span style="color: #45818e;">" -10 => "</span>,<span style="color: #45818e;">" Bars => "</span>,<span style="color: #45818e;">" 1000000 => "</span>};
<span style="color: blue;">double</span> resultatsAttendus[NB_CAS_COURS_MEDIAN];
resultatsAttendus[<span style="color: #38761d;">0</span>] = (<span style="color: magenta;">High</span>[<span style="color: #38761d;">0</span>] + <span style="color: magenta;">Low</span>[<span style="color: #38761d;">0</span>] + <span style="color: magenta;">Open</span>[<span style="color: #38761d;">0</span>] + <span style="color: magenta;">Close</span>[<span style="color: #38761d;">0</span>]) / <span style="color: #38761d;">4.0</span>;
resultatsAttendus[<span style="color: #38761d;">1</span>] = (<span style="color: magenta;">High</span>[<span style="color: #38761d;">10</span>] + <span style="color: magenta;">Low</span>[<span style="color: #38761d;">10</span>] + <span style="color: magenta;">Open</span>[<span style="color: #38761d;">10</span>] + <span style="color: magenta;">Close</span>[<span style="color: #38761d;">10</span>]) / <span style="color: #38761d;">4.0</span>;
resultatsAttendus[<span style="color: #38761d;">2</span>] = (<span style="color: magenta;">High</span>[<span style="color: magenta;">Bars</span>-<span style="color: #38761d;">1</span>] + <span style="color: magenta;">Low</span>[<span style="color: magenta;">Bars</span>-<span style="color: #38761d;">1</span>] + <span style="color: magenta;">Open</span>[<span style="color: magenta;">Bars</span>-<span style="color: #38761d;">1</span>] + <span style="color: magenta;">Close</span>[<span style="color: magenta;">Bars</span>-<span style="color: #38761d;">1</span>]) / <span style="color: #38761d;">4.0</span>;
resultatsAttendus[<span style="color: #38761d;">3</span>] = ERREUR_DOUBLE;
resultatsAttendus[<span style="color: #38761d;">4</span>] = ERREUR_DOUBLE;
resultatsAttendus[<span style="color: #38761d;">5</span>] = ERREUR_DOUBLE;
<span style="color: blue;">for</span>(noCas=<span style="color: #38761d;">0</span> ; noCas<NB_CAS_COURS_PONDERE ; noCas++) {
resultat = execObtenirCoursPondere(arguments[noCas]);
nbErreurs += analyserResultatDoubleDuTest(resultat, resultatsAttendus[noCas],
nomObtenirCoursPondere, parametresCas[noCas]);
}
afficherBilanTestFonction(nomObtenirCoursPondere, nbErreurs);
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: blue;">double</span> execObtenirSpreadActuel(<span style="color: blue;">string</span> argument) {
<span style="color: blue;">double</span> resultat = ERREUR_DOUBLE;
<span style="color: blue;">if</span>(argument == ARG_STRING_EMPTY) { resultat = obtenirSpreadActuel(); }
<span style="color: blue;">return</span>(resultat);
}
<span style="color: blue;">int</span> testObtenirSpreadActuel() {
<span style="color: blue;">int</span> noCas, nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">double</span> resultat;
<span style="color: blue;">string</span> arguments[NB_CAS_SPREAD_ACTUEL] = {ARG_STRING_EMPTY};
<span style="color: blue;">string</span> parametresCas[NB_CAS_SPREAD_ACTUEL] = {<span style="color: #45818e;">" => "</span>};
<span style="color: blue;">double</span> resultatsAttendus[NB_CAS_SPREAD_ACTUEL];
resultatsAttendus[<span style="color: #38761d;">0</span>] = <span style="color: magenta;">Ask</span> - <span style="color: magenta;">Bid</span>;
<span style="color: blue;">for</span>(noCas=<span style="color: #38761d;">0</span> ; noCas<NB_CAS_SPREAD_ACTUEL ; noCas++) {
resultat = execObtenirSpreadActuel(arguments[noCas]);
nbErreurs += analyserResultatDoubleDuTest(resultat, resultatsAttendus[noCas],
nomObtenirSpreadActuel, parametresCas[noCas]);
}
afficherBilanTestFonction(nomObtenirSpreadActuel, nbErreurs);
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> <span style="color: #674ea7;">OnInit</span>() {
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
nbErreurs += testObtenirCoursReelActuel();
nbErreurs += testObtenirCoursMedian();
nbErreurs += testObtenirCoursPondere();
nbErreurs += testObtenirSpreadActuel();
<span style="color: #674ea7;">Print</span>(SEPARATEUR_DOUBLE);
<span style="color: #674ea7;">Print</span>(<span style="color: #45818e;">" TESTS DE ArithmetiqueCotations.mqh TERMINES AVEC "</span>, nbErreurs, <span style="color: #45818e;">" ERREUR(S)."</span>);
<span style="color: #674ea7;">Print</span>(SEPARATEUR_DOUBLE);
<span style="color: blue;">return</span>(<span style="color: #0b5394;">INIT_SUCCEEDED</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">void</span> <span style="color: #674ea7;">OnDeinit</span>(<span style="color: blue;">const int</span> reason) {
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">void</span> <span style="color: #674ea7;">OnTick</span>() {
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span>
</code></pre>
<br />
<div style="text-align: justify; text-indent: 3em;">
Vous pouvez constater qu'il y a des différences avec les fichiers précédemment réalisés. Il y a deux <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">#property</span> </code> en plus au début du fichier: un qui donne la version de l'expert qu'on créé et un autre qui dit que nos lignes de code sont en version stricte. (on pourrait utiliser des variantes de code qui s'éloignent du standard!) Il y a un autre changement de taille: le nom des fonctions prédéfinies: elles ne s'appelent plus <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">init</span>() </code>, <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">deinit</span>() </code> et <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">start</span>() </code>, mais <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">OnInit</span>() </code>, <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">OnDeinit</span>() </code> et <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">OnTick</span>() </code>. Ce nouveau nommage est compatible avec MQL5, et correspond au nommage standard dans tous les langages de programmation pour des fonctions déclenchées sur des évènements (initialisation de l'expert, arrêt de l'expert avec d'ailleurs un paramètre entier fourni par MetaTrader4 lors de l'appel pour indiquer la raison de l'arrêt et l'arrivée d'un tick, d'où un nom plus cohérent avec ce qu'il représente: OnTick = SurUnTick). Il y a aussi les valeurs des retours: celle de la fonction d'initialisation est indiquée par une constante <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #0b5394;">INIT_SUCCEEDED</span> </code> qui signifie succès d'initialisation et qui vaut zéro comme la valeur qu'on retournait avant pour dire qu'il n'y a pas eu d'erreur. Pour les deux autres fonctions, apparemment nous ne sommes plus obligés de retourner une valeur, car il n'y a pas d'instruction <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">return</span> </code> préparées et surtout leur type de retour est <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">void</span> </code>, donc ne pas retourner de valeur.<br />
C'est un post marathon qui se termine, ouf ! Ça nous fait quatre nouvelles fonctions de calcul dans un nouveau fichier header (include) et des modfications dans l'include des utilitaires de tests et un expert de tests pour ces quatre fonctions. Comme vous pouvez le constater, nous accélérons le rythme pour la création de code utilitaire pour nos futurs indicateurs et experts advisors. Avec la nouvelle mise à jour de cette semaine, MetaTrader4, MetaEditor et son aide sont traduits en français, la compatibilité avec le MQL5 est améliorée, et l'éditeur nous propose une nouvelle ergonomie. Nous ne pouvons plus taper les noms prédéfinis sans la majuscule et attendre que l'autocomplétion nous propose un nom, maintenant il faut mettre la majuscule pour que l'éditeur le reconnaisse et propose l'autocomplétion (une liste de possibilités). C'est dommage, mais en contrepartie, l'autocomplétion fonctionne désormais avec nos propres noms: toutes nos variables et fonctions, et ça c'est bien mieux ! La raison est qu'on peut maintenant inclure des fonctions du langage C. Par exemple, si vous ne mettez pas la majuscule à Print(), l'éditeur vous propose en autocomplétion printf(), une fonction du langage C, nos formatages de chaines à afficher en seraient facilités. Nous l'utiliserons peut-être à l'avenir. En tout cas, bon courage pour étudier et pratiquer tout ce qu'on vient de voir, et à la prochaine !
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-82695954735235437452014-02-23T16:48:00.001+01:002014-02-23T16:48:18.527+01:00Le numéro d'une période (bar) en MQL4 partie 2 / 2<div style="text-align: justify; text-indent: 3em;">
Suite du post précédent, nous allons réaliser une fonction qui donne le numéro d'une période selon le calcul (très réfléchi) que je vous ai présenté précédemment. Comme je l'ai expliqué, nous n'utilisons pas la valeur de la variable prédéfinie <span style="color: magenta;">Bars</span> car cette valeur qui est sensée augmenter de 1 à chaque nouvelle période, peut ne pas augmenter pour des raisons de gestion de mémoire, voire elle peut même diminuer brutalement. Il y a donc des bugs potentiels, latents dans cette façon de faire (et que beaucoup utilisent). Nous utiliserons donc l'horodatage fourni avec la cotation par le serveur, là, au moins il n'y a pas de risque d'arrêt du temps ou de retour dans le passé
</div>
<br />
<h3 style="text-decoration: underline;">
Une fonction donnant un numéro de période:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Pour rappel, pour obtenir le numéro d'une période depuis l'epoch, nous faisons la division euclidienne, c'est-à-dire, prendre la partie entière du résultat de la division de l'horodatage (nombre de secondes depuis l'epoch) par le nombre de secondes dans une période. Et pour cela on exploite les subtilités du langage MQL4 en effectuant simplement la division entre des nombres entiers, ce qui nous donne un résultat entier. Notre fonction sera construite de la même manière que les deux précédentes, et autour de ce calcul. Nous recevons donc en argument obligatoire un horodatage et en argument optionnel le nombre de secondes dans la période voulue, et ce nombre doit être positif. Nous l'initialisons à zéro avec la constante <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #0b5394;">NULL</span> </code>. La valeur de l'argument ne doit pas être négative. Dans le cas contraire, on ne fera pas le calcul et nous renvoyons la valeur <code style="background-color: white; color: black; font-weight: bold;"> ERREUR_INT_POSITIF </code>, constante définie précédemment dans un include. La séquence des instructions est alors comme celle des deux fonctions précédentes:
<br />
<ol>
<li style="text-indent: 0;">Initialisation de la variable à retourner à la valeur <code style="background-color: white; color: black; font-weight: bold;"> ERREUR_INT_POSITIF </code></li>
<li style="text-align: justify; text-indent: 0;">Test si la valeur de l'argument est celle par défaut: <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #0b5394;">NULL</span> </code>, et dans l'affirmative remplacement par la valeur pour la période courante, à demander à la fonction <code style="background-color: white; color: black; font-weight: bold;"> obtenirNbSecsDsPeriode() </code> précédemment définie.</li>
<li style="text-indent: 0;">Test si l'argument est positif.</li>
<li style="text-indent: 0;">Si l'argument est positif, alors faire le calcul et l'affecter à la variable à retourner.</li>
<li style="text-indent: 0;">Sinon, afficher une alerte avec un message explicatif et la valeur erronée.</li>
<li style="text-indent: 0;">Retourner la variable.</li>
</ol>
Ce qu'il faut craindre en priorité lorsqu'on fait une division en programmation, c'est la division par zéro. Ici elle est évitée car le nombre de secondes n'est valide que s'il est strictement supérieur à 0, donc différent de zéro. Pour le message d'erreur, on réutilise le message pour les secondes erronées. Voici le code de la fonction à ajouter au fichier header ArithmetiqueTemporelle.mqh:
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">int</span> obtenirNoPeriode(<span style="color: blue;">datetime</span> horodatage, <span style="color: blue;">int</span> nbSecsDansPeriode=<span style="color: #0b5394;">NULL</span>) {
<span style="color: blue;">int</span> noPeriode = ERREUR_INT_POSITIF;
<span style="color: blue;">if</span>(nbSecsDansPeriode == <span style="color: #0b5394;">NULL</span>) { nbSecsDansPeriode = obtenirNbSecsDsPeriode(); }
<span style="color: blue;">bool</span> nbSecsEstValide = (nbSecsDansPeriode > <span style="color: #38761d;">0</span>);
<span style="color: blue;">if</span>(nbSecsEstValide) { noPeriode = horodatage / nbSecsDansPeriode; }
<span style="color: blue;">else</span> { <span style="color: #674ea7;">Alert</span>(<span style="color: #45818e;">" ObtenirNoPeriode() "</span>, msgErrNbSecsNonValide, nbSecsDansPeriode); }
<span style="color: blue;">return</span>(noPeriode);
}
</code>
</pre>
</div>
<h3 style="text-decoration: underline;">
Code de test de cette fonction:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Comme pour les fonctions précédentes, et comme pour toutes les suivantes, nous créons le code de test de la fonction pour s'assurer qu'elle répond aux spécifications qu'on lui demande au travers de différents cas de tests. Nous devons donc lui fournir différents horodatages ( 0 et un autre horodatage ) et soit aucune valeur soit des valeurs de nombre de secondes dans la période aussi bien positifs que négatifs et aussi nul. Les cas proposés sont donc:<br />
<br />
<table border="1" style="left: auto; right: auto; text-align: center; width: 100%;">
<caption>Cas de tests:</caption>
<thead style="background-color: #dddddd; color: black;">
<tr><th>n° cas</th><th>horodatage</th><th>nbSecsDsPeriode</th><th>résultat retourné</th><th>commentaires</th>
</tr>
</thead>
<tbody>
<tr><td>1</td><td>0</td><td>0</td><td>0</td><td>0 divisé par le nombre de secondes dans la période courante</td></tr>
<tr><td>2</td><td>0</td><td>300</td><td>0</td><td>0 / 300 = 0</td></tr>
<tr><td>3</td><td>0</td><td>-10</td><td>ERREUR_INT_POSITIF</td><td>le mauvais argument compte en priorité</td></tr>
<tr><td>4</td><td>0</td><td>ARG_INT_EMPTY</td><td>0</td><td>0 divisé par le nombre de secondes dans la période courante</td></tr>
<tr><td>5</td><td>1207</td><td>0</td><td>1207 / (60 * Period())</td><td>1207 divisé par le nombre de secondes dans la période courante</td></tr>
<tr><td>6</td><td>1207</td><td>300</td><td>4</td><td>1207 / 300 = 4 + un reste fractionnaire non pris en compte</td></tr>
<tr><td>7</td><td>1207</td><td>-10</td><td>ERREUR_INT_POSITIF</td><td>mauvais argument</td></tr>
<tr><td>8</td><td>1207</td><td>ARG_INT_EMPTY</td><td>1207 / (60 * Period())</td><td>1207 divisé par le nombre de secondes dans la période courante</td></tr>
</tbody>
</table>
<br />
Dans le code de test, on ne doit pas oublier de déclarer le nombre de cas de tests en début de code dans la section defines. Et dans la section constantes: le nom de la fonction pour les messages affichés. On créé les deux fonctions: une pour exécuter la fonction testée avec ou sans le paramètre optionnel et l'autre pour définir les cas de tests et les faire exécuter et analyser en boucle. On inscrit une ligne dans la fonction init() pour exécuter les tests de cette fonction nouvellement créée. Voici les lignes à ajouter dans le fichier testsArithmetiqueTemporelle.mq4:
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">// section defines</span>
<span style="color: blue;">#define</span> NB_CAS_NO_PERIOD <span style="color: #38761d;">8</span>
<span style="color: #999999;">// section constantes</span>
<span style="color: blue;">string</span> nomObtenirNoPeriode = <span style="color: #45818e;">"obtenirNoPeriode()"</span>
<span style="color: #999999;">// section fonctions</span>
<span style="color: blue;">int</span> execObtenirNoPeriode(<span style="color: blue;">datetime</span> argumentHorodatage, <span style="color: blue;">int</span> argumentNbSecsDsPeriode) {
<span style="color: blue;">int</span> resultat;
<span style="color: blue;">if</span>(argumentNbSecsDsPeriode == ARG_INT_EMPTY) {
resultat = obtenirNoPeriode(argumentHorodatage); }
<span style="color: blue;">else</span> { resultat = obtenirNoPeriode(argumentHorodatage, argumentNbSecsDsPeriode); }
<span style="color: blue;">return</span>(resultat);
}
<span style="color: blue;">int</span> testObtenirNoPeriode() {
<span style="color: blue;">int</span> noCas, nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">int</span> resultat;
<span style="color: blue;">datetime</span> argumentsHorodatages[NB_CAS_NO_PERIOD] = {<span style="color: #38761d;">0</span>,
<span style="color: #38761d;">0</span>,
<span style="color: #38761d;">0</span>,
<span style="color: #38761d;">0</span>,
<span style="color: #38761d;">1207</span>,
<span style="color: #38761d;">1207</span>,
<span style="color: #38761d;">1207</span>,
<span style="color: #38761d;">1207</span>};
<span style="color: blue;">int</span> argumentsNbSecsDsPeriode[NB_CAS_NO_PERIOD] = {<span style="color: #38761d;">0</span>,
<span style="color: #38761d;">300</span>,
-<span style="color: #38761d;">10</span>,
ARG_INT_EMPTY,
<span style="color: #38761d;">0</span>,
<span style="color: #38761d;">300</span>,
-<span style="color: #38761d;">10</span>,
ARG_INT_EMPTY};
<span style="color: blue;">string</span> parametresCas[NB_CAS_NO_PERIOD] = {<span style="color: #45818e;">" 0, 0 => "</span>,
<span style="color: #45818e;">" 0, 300 => "</span>,
<span style="color: #45818e;">" 0, -10 => "</span>,
<span style="color: #45818e;">" 0, => "</span>,
<span style="color: #45818e;">" 1207, 0 => "</span>,
<span style="color: #45818e;">" 1207, 300 => "</span>,
<span style="color: #45818e;">" 1207, -10 => "</span>,
<span style="color: #45818e;">" 1207, => "</span>};
<span style="color: blue;">int</span> resultatsAttendus[NB_CAS_NO_PERIOD];
resultatsAttendus[<span style="color: #38761d;">0</span>] = <span style="color: #38761d;">0</span>;
resultatsAttendus[<span style="color: #38761d;">1</span>] = <span style="color: #38761d;">0</span>;
resultatsAttendus[<span style="color: #38761d;">2</span>] = ERREUR_INT_POSITIF;
resultatsAttendus[<span style="color: #38761d;">3</span>] = <span style="color: #38761d;">0</span>;
resultatsAttendus[<span style="color: #38761d;">4</span>] = (<span style="color: #38761d;">1207</span> / (<span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>()));
resultatsAttendus[<span style="color: #38761d;">5</span>] = <span style="color: #38761d;">4</span>;
resultatsAttendus[<span style="color: #38761d;">6</span>] = ERREUR_INT_POSITIF;
resultatsAttendus[<span style="color: #38761d;">7</span>] = (<span style="color: #38761d;">1207</span> / (<span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>()));
<span style="color: blue;">for</span>(noCas=<span style="color: #38761d;">0</span> ; noCas<NO_CAS_NB_SEC_IN_PERIOD ; noCas++) {
resultat = execObtenirNoPeriode(argumentsHorodatages[noCas],
argumentsNbSecsDsPeriode[noCas]);
nbErreurs += analyserResultatIntDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNoPeriode,
parametresCas[noCas]);
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: #999999;">// ajouter dans la fonction init()</span>
nbErreurs += testObtenirNoPeriode();
</code>
</pre>
</div>
<br />
<h3 style="text-decoration: underline;">
Le tutoriel vidéo et les codes complets de l'include et de l'expert de test:
</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='640' height='480' src='https://www.youtube.com/embed/DyhLoOzoDUc?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<div style="text-align: justify; text-indent: 3em;">
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| ArithmetiqueTemporelle.mqh |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2014, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| DLL imports |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| EX4 imports |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| includes |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| variables globales |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| constantes globales |
//+------------------------------------------------------------------+
<span style="color: blue;">string</span> msgErrNbMinsNonValide = <span style="color: #45818e;">" a reçu un nombre de minutes non valide: "</span>;
<span style="color: blue;">string</span> msgErrNbSecsNonValide = <span style="color: #45818e;">" a reçu un nombre de secondes non valide: "</span>;
//+------------------------------------------------------------------+
//| fonctions comptage |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">datetime</span> obtenirNoDerniereSecConnue(<span style="color: blue;">string</span> paire=<span style="color: #45818e;">"NULL"</span>) {
<span style="color: blue;">datetime</span> horodatage;
<span style="color: blue;">if</span>(paire==<span style="color: #45818e;">"NULL"</span>) { horodatage = <span style="color: #674ea7;">TimeCurrent</span>(); }
<span style="color: blue;">else</span> { horodatage = <span style="color: #674ea7;">MarketInfo</span>(paire, <span style="color: #0b5394;">MODE_TIME</span>); }
<span style="color: blue;">return</span>(horodatage);
}
<span style="color: blue;">int</span> obtenirNbSecsDsPeriode(<span style="color: blue;">int</span> nbMinsDansPeriode=<span style="color: #0b5394;">NULL</span>) {
<span style="color: blue;">int</span> nbSecsDsPeriode = ERREUR_INT_POSITIF;
<span style="color: blue;">if</span>(nbMinsDansPeriode == <span style="color: #0b5394;">NULL</span>) { nbMinsDansPeriode = <span style="color: #674ea7;">Period</span>(); }
<span style="color: blue;">bool</span> nbMinsEstValide = (nbMinsDansPeriode > <span style="color: #38761d;">0</span>);
<span style="color: blue;">if</span>(nbMinsEstValide) { nbSecsDsPeriode = <span style="color: #38761d;">60</span> * nbMinsDansPeriode; }
<span style="color: blue;">else</span> { <span style="color: #674ea7;">Alert</span>(<span style="color: #45818e;">"ObtenirNbSecsDsPeriode() "</span>, msgErrNbMinsNonValide, nbMinsDansPeriode); }
<span style="color: blue;">return</span>(nbSecsDsPeriode);
}
<span style="color: blue;">int</span> obtenirNoSecDsPeriode(<span style="color: blue;">datetime</span> horodatageSec, <span style="color: blue;">int</span> nbSecsDansPeriode=<span style="color: #0b5394;">NULL</span>) {
<span style="color: blue;">int</span> noSecDansPeriode = ERREUR_INT_POSITIF;
<span style="color: blue;">if</span>(nbSecsDansPeriode == <span style="color: #0b5394;">NULL</span>) { nbSecsDansPeriode = obtenirNbSecsDsPeriode(); }
<span style="color: blue;">bool</span> nbSecsEstValide = (nbSecsDansPeriode > <span style="color: #38761d;">0</span>);
<span style="color: blue;">if</span>(nbSecsEstValide) { noSecDansPeriode = horodatageSec % nbSecsDansPeriode; }
<span style="color: blue;">else</span> { <span style="color: #674ea7;">Alert</span>(<span style="color: #45818e;">"ObtenirNoSecDsPeriode() "</span>, msgErrNbSecsNonValide, nbSecsDansPeriode); }
<span style="color: blue;">return</span>(noSecDansPeriode);
}
<span style="color: blue;">int</span> obtenirNoPeriode(<span style="color: blue;">datetime</span> horodatage, <span style="color: blue;">int</span> nbSecsDansPeriode=<span style="color: #0b5394;">NULL</span>) {
<span style="color: blue;">int</span> noPeriode = ERREUR_INT_POSITIF;
<span style="color: blue;">if</span>(nbSecsDansPeriode == <span style="color: #0b5394;">NULL</span>) { nbSecsDansPeriode = obtenirNbSecsDsPeriode(); }
<span style="color: blue;">bool</span> nbSecsEstValide = (nbSecsDansPeriode > <span style="color: #38761d;">0</span>);
<span style="color: blue;">if</span>(nbSecsEstValide) { noPeriode = horodatage / nbSecsDansPeriode; }
<span style="color: blue;">else</span> { <span style="color: #674ea7;">Alert</span>(<span style="color: #45818e;">"ObtenirNoPeriode() "</span>, msgErrNbSecsNonValide, nbSecsDansPeriode); }
<span style="color: blue;">return</span>(noPeriode);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span>
</code>
</pre>
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| testsArithmetiqueTemporelle.mqh |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2014, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: blue;">#include</span> <Constantes.mqh>
<span style="color: blue;">#include</span> <UtilitairesTests.mqh>
<span style="color: blue;">#include</span> <ArithmetiqueTemporelle.mqh>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#define</span> NB_CAS_LAST_KNOWN_SEC_NO <span style="color: #38761d;">5</span>
<span style="color: blue;">#define</span> NB_CAS_NB_SECS_IN_PERIOD <span style="color: #38761d;">5</span>
<span style="color: blue;">#define</span> NB_CAS_NO_SEC_IN_PERIOD <span style="color: #38761d;">7</span>
<span style="color: blue;">#define</span> NB_CAS_NO_PERIOD <span style="color: #38761d;">8</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| constantes de tests |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">string</span> nomObtenirNoDerniereSecConnue = <span style="color: #45818e;">"obtenirNoDerniereSecConnue()"</span>;
<span style="color: blue;">string</span> nomObtenirNbSecsDsPeriode = <span style="color: #45818e;">"obtenirNbSecsDsPeriode()"</span>
<span style="color: blue;">string</span> nomObtenirNoSecDsPeriode = <span style="color: #45818e;">"obtenirNoSecDsPeriode()"</span>
<span style="color: blue;">string</span> nomObtenirNoPeriode = <span style="color: #45818e;">"obtenirNoPeriode()"</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| fonctions de tests |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">datetime</span> execObtenirNoDerniereSecConnue(<span style="color: blue;">string</span> argument) {
<span style="color: blue;">datetime</span> resultat;
<span style="color: blue;">if</span>(argument == ARG_STRING_EMPTY) { resultat = obtenirNoDerniereSecConnue(); }
<span style="color: blue;">else</span> { resultat = obtenirNoDerniereSecConnue(argument); }
<span style="color: blue;">return</span>(resultat);
}
<span style="color: blue;">int</span> testObtenirNoDerniereSecConnue() {
<span style="color: blue;">int</span> noCas, nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">datetime</span> resultat;
<span style="color: blue;">string</span> arguments[NB_CAS_LAST_KNOWN_SEC_NO] = {ARG_STRING_EMPTY,
<span style="color: #45818e;">"EURUSD"</span>,
<span style="color: #45818e;">"GBPJPY"</span>,
<span style="color: #45818e;">"EUR"</span>,
<span style="color: #45818e;">""</span>};
<span style="color: blue;">string</span> parametresCas[NB_CAS_LAST_KNOWN_SEC_NO] = {<span style="color: #45818e;">" sans paramètre => "</span>,
<span style="color: #45818e;">" \"EURUSD\" => "</span>,
<span style="color: #45818e;">" \"GBPJPY\" => "</span>,
<span style="color: #45818e;">" \"EUR\" => "</span>,
<span style="color: #45818e;">" \"\" => "</span>};
<span style="color: blue;">datetime</span> resultatsAttendus[NB_CAS_LAST_KNOWN_SEC_NO];
resultatsAttendus[<span style="color: #38761d;">0</span>] = <span style="color: #674ea7;">TimeCurrent</span>();
resultatsAttendus[<span style="color: #38761d;">1</span>] = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #45818e;">"EURUSD"</span>, <span style="color: #0b5394;">MODE_TIME</span>);
resultatsAttendus[<span style="color: #38761d;">2</span>] = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #45818e;">"GBPJPY"</span>, <span style="color: #0b5394;">MODE_TIME</span>);
resultatsAttendus[<span style="color: #38761d;">3</span>] = <span style="color: #38761d;">0</span>;
resultatsAttendus[<span style="color: #38761d;">4</span>] = <span style="color: #38761d;">0</span>;
<span style="color: blue;">for</span>(noCas=<span style="color: #38761d;">0</span> ; noCas<NB_CAS_LAST_KNOWN_SEC_NO ; noCas++) {
resultat = execObtenirNoDerniereSecConnue(arguments[noCas]);
nbErreurs += analyserResultatDatetimeDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNoDerniereSecConnue,
parametresCas[noCas]);
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: blue;">int</span> execObtenirNbSecsDsPeriode(<span style="color: blue;">int</span> argument) {
<span style="color: blue;">int</span> resultat;
<span style="color: blue;">if</span>(argument == ARG_INT_EMPTY) { resultat = obtenirNbSecsDsPeriode(); }
<span style="color: blue;">else</span> { resultat = obtenirNbSecsDsPeriode(argument); }
<span style="color: blue;">return</span>(resultat);
}
<span style="color: blue;">int</span> testObtenirNbSecsDsPeriode() {
<span style="color: blue;">int</span> noCas, nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">int</span> resultat;
<span style="color: blue;">int</span> arguments[NB_CAS_NB_SECS_IN_PERIOD] = {ARG_INT_EMPTY, <span style="color: #38761d;">5</span>, <span style="color: #38761d;">240</span>, -<span style="color: #38761d;">2</span>, <span style="color: #38761d;">0</span>};
<span style="color: blue;">string</span> parametresCas[NB_CAS_NB_SECS_IN_PERIOD] = {<span style="color: #45818e;">" sans paramètres => "</span>,
<span style="color: #45818e;">" 5 => "</span>,
<span style="color: #45818e;">" 240 => "</span>,
<span style="color: #45818e;">" -2 => "</span>,
<span style="color: #45818e;">" 0 => "</span>};
<span style="color: blue;">int</span> resultatsAttendus[NB_CAS_NB_SECS_IN_PERIOD];
resultatsAttendus[<span style="color: #38761d;">0</span>] = <span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>();
resultatsAttendus[<span style="color: #38761d;">1</span>] = <span style="color: #38761d;">300</span>;
resultatsAttendus[<span style="color: #38761d;">2</span>] = <span style="color: #38761d;">14400</span>;
resultatsAttendus[<span style="color: #38761d;">3</span>] = ERREUR_INT_POSITIF;
resultatsAttendus[<span style="color: #38761d;">4</span>] = <span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>();
<span style="color: blue;">for</span>(noCas=<span style="color: #38761d;">0</span> ; noCas<NB_CAS_NB_SECS_IN_PERIOD ; noCas++) {
resultat = execObtenirNbSecsDsPeriode(arguments[noCas]);
nbErreurs += analyserResultatIntDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNbSecsDsPeriode,
parametresCas[noCas]);
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: blue;">int</span> execObtenirNoSecDsPeriode(<span style="color: blue;">datetime</span> argumentHorodatage, <span style="color: blue;">int</span> argumentNbSecsDsPeriode) {
<span style="color: blue;">int</span> resultat;
<span style="color: blue;">if</span>(argumentNbSecsDsPeriode == ARG_INT_EMPTY) {
resultat = obtenirNoSecDsPeriode(argumentHorodatage); }
<span style="color: blue;">else</span> { resultat = obtenirNoSecDsPeriode(argumentHorodatage, argumentNbSecsDsPeriode); }
<span style="color: blue;">return</span>(resultat);
}
<span style="color: blue;">int</span> testObtenirNoSecDsPeriode() {
<span style="color: blue;">int</span> noCas, nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">int</span> resultat;
<span style="color: blue;">datetime</span> argumentsHorodatages[NB_CAS_NO_SEC_IN_PERIOD] = {<span style="color: #38761d;">127</span>,
<span style="color: #38761d;">123456789</span>,
<span style="color: #38761d;">123456789</span>,
<span style="color: #38761d;">123456789</span>,
<span style="color: #38761d;">127</span>,
<span style="color: #38761d;">127</span>,
<span style="color: #38761d;">127</span>};
<span style="color: blue;">int</span> argumentsNbSecsDsPeriode[NB_CAS_NO_SEC_IN_PERIOD] = {ARG_INT_EMPTY,
ARG_INT_EMPTY,
<span style="color: #38761d;">240</span>,
<span style="color: #38761d;">900</span>,
<span style="color: #38761d;">60</span>,
<span style="color: #38761d;">0</span>,
-<span style="color: #38761d;">4</span>};
<span style="color: blue;">string</span> parametresCas[NB_CAS_NO_SEC_IN_PERIOD] = {<span style="color: #45818e;">" 127, EMPTY => "</span>,
<span style="color: #45818e;">" 123456789, EMPTY => "</span>,
<span style="color: #45818e;">" 123456789, 240 => "</span>,
<span style="color: #45818e;">" 123456789, 900 => "</span>,
<span style="color: #45818e;">" 127, 60 => "</span>,
<span style="color: #45818e;">" 127, 0 => "</span>,
<span style="color: #45818e;">" 127, -4 => "</span>};
<span style="color: blue;">int</span> resultatsAttendus[NB_CAS_NO_SEC_IN_PERIOD];
resultatsAttendus[<span style="color: #38761d;">0</span>] = <span style="color: #38761d;">127</span> % (<span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>());
resultatsAttendus[<span style="color: #38761d;">1</span>] = <span style="color: #38761d;">123456789</span> % (<span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>());
resultatsAttendus[<span style="color: #38761d;">2</span>] = <span style="color: #38761d;">69</span>;
resultatsAttendus[<span style="color: #38761d;">3</span>] = <span style="color: #38761d;">189</span>;
resultatsAttendus[<span style="color: #38761d;">4</span>] = <span style="color: #38761d;">7</span>;
resultatsAttendus[<span style="color: #38761d;">5</span>] = <span style="color: #38761d;">127</span> % (<span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>());
resultatsAttendus[<span style="color: #38761d;">6</span>] = ERREUR_INT_POSITIF;
<span style="color: blue;">for</span>(noCas=<span style="color: #38761d;">0</span> ; noCas<NO_CAS_NB_SEC_IN_PERIOD ; noCas++) {
resultat = execObtenirNbSecsDsPeriode(argumentsHorodatages[noCas],
argumentsNbSecsDsPeriode[noCas]);
nbErreurs += analyserResultatIntDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNoSecDsPeriode,
parametresCas[noCas]);
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: blue;">int</span> execObtenirNoPeriode(<span style="color: blue;">datetime</span> argumentHorodatage, <span style="color: blue;">int</span> argumentNbSecsDsPeriode) {
<span style="color: blue;">int</span> resultat;
<span style="color: blue;">if</span>(argumentNbSecsDsPeriode == ARG_INT_EMPTY) {
resultat = obtenirNoPeriode(argumentHorodatage); }
<span style="color: blue;">else</span> { resultat = obtenirNoPeriode(argumentHorodatage, argumentNbSecsDsPeriode); }
<span style="color: blue;">return</span>(resultat);
}
<span style="color: blue;">int</span> testObtenirNoPeriode() {
<span style="color: blue;">int</span> noCas, nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">int</span> resultat;
<span style="color: blue;">datetime</span> argumentsHorodatages[NB_CAS_NO_PERIOD] = {<span style="color: #38761d;">0</span>,
<span style="color: #38761d;">0</span>,
<span style="color: #38761d;">0</span>,
<span style="color: #38761d;">0</span>,
<span style="color: #38761d;">1207</span>,
<span style="color: #38761d;">1207</span>,
<span style="color: #38761d;">1207</span>,
<span style="color: #38761d;">1207</span>};
<span style="color: blue;">int</span> argumentsNbSecsDsPeriode[NB_CAS_NO_PERIOD] = {<span style="color: #38761d;">0</span>,
<span style="color: #38761d;">300</span>,
-<span style="color: #38761d;">10</span>,
ARG_INT_EMPTY,
<span style="color: #38761d;">0</span>,
<span style="color: #38761d;">300</span>,
-<span style="color: #38761d;">10</span>,
ARG_INT_EMPTY};
<span style="color: blue;">string</span> parametresCas[NB_CAS_NO_PERIOD] = {<span style="color: #45818e;">" 0, 0 => "</span>,
<span style="color: #45818e;">" 0, 300 => "</span>,
<span style="color: #45818e;">" 0, -10 => "</span>,
<span style="color: #45818e;">" 0, => "</span>,
<span style="color: #45818e;">" 1207, 0 => "</span>,
<span style="color: #45818e;">" 1207, 300 => "</span>,
<span style="color: #45818e;">" 1207, -10 => "</span>,
<span style="color: #45818e;">" 1207, => "</span>};
<span style="color: blue;">int</span> resultatsAttendus[NB_CAS_NO_PERIOD];
resultatsAttendus[<span style="color: #38761d;">0</span>] = <span style="color: #38761d;">0</span>;
resultatsAttendus[<span style="color: #38761d;">1</span>] = <span style="color: #38761d;">0</span>;
resultatsAttendus[<span style="color: #38761d;">2</span>] = ERREUR_INT_POSITIF;
resultatsAttendus[<span style="color: #38761d;">3</span>] = <span style="color: #38761d;">0</span>;
resultatsAttendus[<span style="color: #38761d;">4</span>] = (<span style="color: #38761d;">1207</span> / (<span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>()));
resultatsAttendus[<span style="color: #38761d;">5</span>] = <span style="color: #38761d;">4</span>;
resultatsAttendus[<span style="color: #38761d;">6</span>] = ERREUR_INT_POSITIF;
resultatsAttendus[<span style="color: #38761d;">7</span>] = (<span style="color: #38761d;">1207</span> / (<span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>()));
<span style="color: blue;">for</span>(noCas=<span style="color: #38761d;">0</span> ; noCas<NO_CAS_NB_SEC_IN_PERIOD ; noCas++) {
resultat = execObtenirNoPeriode(argumentsHorodatages[noCas],
argumentsNbSecsDsPeriode[noCas]);
nbErreurs += analyserResultatIntDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNoPeriode,
parametresCas[noCas]);
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> init()
{
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
nbErreurs += testObtenirNoDerniereSecConnue();
nbErreurs += testObtenirNbSecsDsPeriode();
nbErreurs += testObtenirNoSecDsPeriode();
nbErreurs += testObtenirNoPeriode();
<span style="color: #674ea7;">Print</span>(<span style="color: #45818e;">"-------------------------------------------------------------------"</span>);
<span style="color: #674ea7;">Print</span>(<span style="color: #45818e;">"TESTS DE ArithmetiqueTemporelle.mqh TERMINES AVEC "</span>, nbErreurs, <span style="color: #45818e;">" ERREUR(S)."</span>);
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> deinit()
{
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> start()
{
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span>
</code>
</pre>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-36418625585997116342014-02-21T13:28:00.000+01:002014-02-21T13:57:59.583+01:00Le numéro d'une période (bar) en MQL4 partie 1 / 2<div style="text-align: justify; text-indent: 3em;">
Metatrader nous met à disposition une variable prédéfinie, bien pratique: <span style="color: magenta;">Bars</span>. Cette variable disponible n'importe où dans le code contient le nombre de périodes actuellement dans l'historique. Si on a besoin de parcourir l'historique, il faut l'utiliser pour connaître le nombre de périodes dans cet historique. Elle pose cependant un problème. J'ai vu des codes utilisant la variable prédéfinie <span style="color: magenta;">Bars</span> comme indicateur de changement de période. Et je l'ai même, au début, utilisée pour établir un numéro temporel à chaque période comme si c'était un numéro de référence temporelle absolu. J'ai vite déchanté. </div>
<br />
<div style="text-align: justify; text-indent: 3em;">
Le problème de la variable prédéfinie <span style="color: magenta;">Bars</span> est qu'elle ne représente <i style="font-weight: bold;">que</i> le nombre de périodes (bar) dans l'historique. Et ce nombre varie avec la taille de l'historique, qui elle dépend de la gestion interne de Metatrader. C'est-à-dire que ce nombre ne va pas forcément augmenter. Par expérience personnelle, je peux dire qu'il faut faire attention, et notamment quand on utilise ce nombre pour déterminer un numéro de période où pour déterminer s'il y a une nouvelle période ( Bars n'augmente pas forcément ). Pour déterminer un numéro de période, il faut se baser sur les horodatages, ceux-ci proviennent du serveur et sont associés aux données du cours et indissociables de ces cotations. A chaque tick qu'on reçoit, il s'agit surtout de lire la cotation, mais cette information, le serveur la fournie liée à un horodatage indissociable. La cotation a une position temporelle bien définie, sinon elle ne veux rien dire du tout.</div>
<br />
<h3 style="text-decoration: underline;">
Le principe du calcul:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Prenons par exemple une période qui durerait 5 secondes, cela signifierait que toutes les 5 secondes il y aurait une nouvelle période. C'est-à-dire que les secondes dont l'horodatage serait 0, 1, 2, 3 et 4 appartiennent à la période n°0, que les secondes n° 5, 6, 7, 8 et 9 appartiennent à la période n° 1, et que les secondes n° 10, 11, 12, 13 et 14 appartiennent à la période n° 2, etc. Vous constatez que dans les numéros des secondes de la période n°0, il y a 0 fois le nombre 5. On ne peut pas retirer le nombre 5 de ces numéros. Pour ceux de la période n°1, on peut par contre retirer 1 fois le nombre 5: 5-5=0, 6-5=1, 7-5=2, 8-5=3 et 9-5=4. Et 2 fois le nombre 5 pour ceux de la période n°2: 10-2x5=0, 11-2x5=1, 12-2x5=2, 13-2x5=3 et 14-2x5=4. Arithmétiquement c'est faire une division euclidienne (entière) c'est-à-dire une division dont on ne prend que la partie entière du résultat, soit le nombre de fois qu'on peut retirer le diviseur entier (les résultats des soustractions précédentes sont les restes de ces divisions, c'est ce qu'il reste qui n'est plus assez grand pour y retirer encore le diviseur). Faisons les divisions décimales et voyons:<br />
<ul style="text-indent: 0;">
<li><math><mrow><mfrac><mrow><mn>1</mn></mrow><mrow><mn>5</mn></mrow></mfrac><mo>=</mo><mn>0,2</mn></mrow></math> dont la partie entière est 0.</li>
<li><math><mrow><mfrac><mrow><mn>2</mn></mrow><mrow><mn>5</mn></mrow></mfrac><mo>=</mo><mn>0,4</mn></mrow></math> dont la partie entière est 0.</li>
<li><math><mrow><mfrac><mrow><mn>4</mn></mrow><mrow><mn>5</mn></mrow></mfrac><mo>=</mo><mn>0,8</mn></mrow></math> dont la partie entière est 0.</li>
<li><math><mrow><mfrac><mrow><mn>5</mn></mrow><mrow><mn>5</mn></mrow></mfrac><mo>=</mo><mn>1</mn></mrow></math> dont la partie entière est 1.</li>
<li><math><mrow><mfrac><mrow><mn>7</mn></mrow><mrow><mn>5</mn></mrow></mfrac><mo>=</mo><mn>1,4</mn></mrow></math> dont la partie entière est 1.</li>
<li><math><mrow><mfrac><mrow><mn>9</mn></mrow><mrow><mn>5</mn></mrow></mfrac><mo>=</mo><mn>1,8</mn></mrow></math> dont la partie entière est 1.</li>
<li><math><mrow><mfrac><mrow><mn>10</mn></mrow><mrow><mn>5</mn></mrow></mfrac><mo>=</mo><mn>2</mn></mrow></math> dont la partie entière est 2.</li>
<li><math><mrow><mfrac><mrow><mn>11</mn></mrow><mrow><mn>5</mn></mrow></mfrac><mo>=</mo><mn>2,2</mn></mrow></math> dont la partie entière est 2.</li>
<li><math><mrow><mfrac><mrow><mn>37</mn></mrow><mrow><mn>5</mn></mrow></mfrac><mo>=</mo><mn>5,4</mn></mrow></math> dont la partie entière est 5.</li>
<li><math><mrow><mfrac><mrow><mn>378</mn></mrow><mrow><mn>5</mn></mrow></mfrac><mo>=</mo><mn>75,6</mn></mrow></math> dont la partie entière est 75.</li>
</ul>
Les parties entières de ces divisions sont donc les numéros des périodes, et de manière absolue si on utilise les horodatages fournis par le serveur. Et les numéros de périodes seront donc très grands car les horodatages le sont encore plus. Évidemment ces numéros de périodes dépendent de la taille desdites périodes, et c'est normal car depuis le 1<sup>er</sup> janvier 1970 il y a plus de périodes de 60 secondes que de périodes à 300 secondes (Cinq minutes). Si on divise par 300, nous obtiendrons évidemment des numéros plus petits.
</div>
<br />
<h3 style="text-decoration: underline;">
La fonction MathFloor():
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Certains langages de programmation proposent d'obtenir directement la partie entière de la division euclidienne et d'autres non. Ici ont peut utiliser deux méthodes:<br />
<ol style="text-indent: 0;">
<li>Approche triviale: division de nombres décimaux avec pour résultat un nombre décimal dont on pourra extraire la partie entière avec la fonction MathFloor().</li>
<li> Utilisation du casting implicite par une division entre nombres entiers donnant un résultat entier.</li>
</ol>
On voit donc de suite l'approche que je qualifie de triviale car c'est celle qui vient à l'esprit en premier (la deuxième ne m'est venue que récemment). Quand on fait une division d'un nombre par un autre on s'attend en général à obtenir un nombre avec des décimales. D'où la logique qui vient à l'esprit du programmeur d'utiliser une fonction arithmétique très souvent disponible: <code style="background-color: white; color:black; font-weight: bold;"> <span style="color: #674ea7;">MathFloor</span>() </code>. On passe en paramètre à cette fonction un nombre avec des décimales et elle nous retourne le même nombre sans les décimales. Donc pour notre problème, il suffit de faire la division de l'horodatage du tick, qui est le nombre de secondes depuis le 1<sup>er</sup> janvier 1970, par le nombre de secondes dans la période. On obtient alors un nombre fractionnaire qu'on passe à la fonction pour avoir en retour ce même nombre débarrassé de ses décimales, et qui se trouve donc être le numéro de la période depuis le 1<sup>er</sup> janvier 1970. Du coup ce numéro est vraiment une référence qui ne risque pas de varier pour ce tick-là, à la différence de <span style="color: magenta;">Bars</span>. Les lignes de code pour ceci:
<br />
<pre style="background-color: white; color:black; font-weight: bold;padding:0 1em 0 1em;"><code>
<span style="color: blue;">double</span> noPeriodeFractionnaire = horodatage / nbSecondesDansPeriode;
<span style="color: blue;">int</span> noPeriode = <span style="color: #674ea7;">MathFloor</span>(noPeriodeFractionnaire);
</code>
</pre>
</div>
<br />
<h3 style="text-decoration: underline;">
divisions entre entiers:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Quand on a fait le code précédent, on a fait deux erreurs car on a oublié deux choses que le langage MQL4 fait et qui, ici se compensent:<br />
<ol style="text-indent: 0;">
<li>La fonction <code style="background-color: white; color:black; font-weight: bold;"> <span style="color: #764ea7;">MathFloor</span>() </code> prend un nombre décimal en paramètre du genre 12.3 ou 4.157 mais retourne aussi un nombre décimal, c'est-à-dire que le résultat qu'elle retourne est du genre 12.0 ou 4.0 (type <span style="color: blue;">double</span>). Or nous voulons 12 ou 4, des nombres entiers (type <span style="color: blue;">int</span>).</li>
<li>Le langage MQL4 réalise un cast implicite. Le cast est un changement de type de données opéré par le compilateur qui rajoute des instructions pour le processeur que nous n'avons pas mises et cela pour convertir le type de donnée. Dans notre cas, quand nous déclarons une variable de type <span style="color: blue;">int</span> et que nous lui demandons d'y mettre la valeur 4.0 du type <span style="color: blue;">double</span>, le compilateur va se débrouiller pour convertir le type et le 4.0 devient un 4. Mais ! En y réfléchissant bien, la fonction <code style="background-color: white; color:black; font-weight: bold;"> <span style="color: #764ea7;">MathFloor</span>() </code> ne sert à rien ! On aurait tout aussi bien pu faire la division et demander en même temps de stocker le résultat dans une variable entière ce qui aurait provoqué la suppression des décimales ! Au final le cast implicite nous sauve la mise car nous avons comme résultat un nombre décimal et qu'on ne voulait pas ça, et que le cast convertit dans le bon type. On va continuer dans la réflexion et ceux qui l'ont testé le savent: les opérations aussi dépendent des types. Lors d'une opération arithmétique avec MQL4, s'il n'y a que des nombres entiers le résultat est entier et dès qu'un nombre décimal est en jeu, le résultat est décimal. Il y a un cast implicite aussi pour les opérations arithmétiques. Quand nous divisons deux nombres entiers, le résultat sera entier: <math><mrow><mfrac><mrow><mn>7</mn></mrow><mrow><mn>2</mn></mrow></mfrac>=3</mrow></math> à la différence de la même division avec au moins un nombre décimal: <math><mrow><mfrac><mrow><mn>7</mn></mrow><mrow><mn>2.0</mn></mrow></mfrac>=3.5</mrow></math> qui donne un résultat décimal. Or la division qu'on souhaite faire se fait entre deux nombres entiers ! Conclusion la fonction d'extraction de partie entière ne sert à rien ! La ligne de code que nous devons mettre est simplement
<pre style="background-color: white; color:black; font-weight: bold;padding:0 1em 0 1em;"><code>
<span style="color: blue;">int</span> noPeriode = horodatage / nbSecondesDansPeriode;
</code>
</pre>
</li>
</ol>
Je me suis sérieusement fait avoir par ce genre de choses: j'avais un code assez copieux, qu'il a fallu tout décortiquer pour trouver le problème. Et c'était une division qui me donnait toujours zéro au lieu d'un nombre fractionnaire entre 0 et 1. =D Vous comprenez l'origine du bug ! Prévu initialement en un seul post, ça commence à faire long, je vais donc vous proposer la suite au post suivant. Prenez le temps d'assimiler ce qu'on vient de voir. A chaque jour suffit sa peine.
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-85159620562537266102014-02-19T20:19:00.003+01:002014-02-23T16:51:32.711+01:00Gestion des valeurs erronées des arguments en MQL4<div style="text-align: justify; text-indent: 3em;">
Nous avons vu avec les tests des trois premières fonctions du fichier include d'arithmétique temporelle qu'il pouvait y avoir des valeurs reçues en argument auxquelles aucune signification n'est attachée. Par exemple, pour obtenir le nombre de secondes dans une période, nous recevons en argument un nombre entier qui donne le nombre de minutes de la période. Mais ce nombre entier fourni pourrait être négatif ou nul et la fonction fournirait quand même un résultat. Mais un nombre de minutes dans une période négatif ou nul n'a aucune signification et il s'agit clairement d'une valeur erronée. Et le résultat fourni par la fonction n'a pas plus de sens. Que faire dans ce cas-là, parce que ces valeurs peuvent arriver, ne serait-ce que par un bug de l'expert advisor qui appelle la fonction. Nous allons réfléchir à ce problème dans ce post, et proposer une modification de code.
</div>
<br />
<h3 style="text-decoration: underline;">
Contrôler la validité des arguments:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Nous ne pouvons clairement pas laisser les fonctions donner un résultat qui n'a aucun sens et qui induirait des bugs dans le programme. Il faut constamment contrôler les valeurs pour détecter les problèmes. Donc quand une fonction reçoit une valeur pour faire un calcul ou un traitement quelconque, nous devons vérifier que nous n'allons pas provoquer un problème ou propager une erreur. Une chose est sûre, il ne faut pas retourner un résultat qui n'a pas de sens et qui provoquerait des erreurs. Imaginez par exemple un nombre de secondes dans la période qui serait négatif, nous ferions des calculs ensuite avec et nous aurons forcément un résultat faux et notre programme pourrait envoyer un ordre de position sur le marché alors qu'il ne faudrait surtout pas, et nous faire perdre du capital. Nous allons donc introduire une condition dans la fonction: nous ferons le calcul que si l'argument est valide et nous déclencherons une alerte avec un message d'erreur dans le cas contraire. Nous plaçons ce test de validité après le contrôle de la valeur vide, car il peut y avoir interférence par recouvrement entre la valeur vide (valeur par défaut) et les valeurs erronées.</div>
<br />
<h3 style="text-decoration: underline;">
Retourner un code d'erreur:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Une fois que nous avons vérifié que l'argument est non valide et que nous avons déclenché une alerte, nous ne pouvons pas retourner un résultat comme si de rien n'était. Parce que le code qui a appelé la fonction va recevoir ce résultat et l'utiliser. Il faut un moyen pour l'avertir qu'il n'y a pas de résultat et qu'il y a un problème et qu'il ne doit pas continuer à faire son traitement normal. Nous n'avons qu'un seul moyen de l'avertir, c'est la valeur de retour. Il faut donc trouver une valeur dans chaque cas qui n'est pas utilisée, pour signifier qu'il y a eu une erreur. Souvent le résultat de retour est toujours positif, on peut alors utiliser les valeurs négatives, ou selon le cas une valeur nulle. Si la valeur de retour est du type <span style="color: blue;">string</span> nous pouvons utiliser une chaîne de caractères très spécifique. Nous pouvons utiliser la valeur -1 pour les booléens, car elle est acceptée et compatible, et surtout non utilisée (faux=0 et vrai=1). Pour le type <span style="color: blue;">color</span> nous pouvons utiliser une valeur sur quatre octets (-1 où tous les bits sont à 1) car seuls trois octets sont utilisés (un par composante primaire rouge, vert et bleu) et les valeurs entières sont acceptées. La valeur 0 peut signifier pour un horodatage qu'il y a une erreur, car elle ne sera pas utilisée parce qu'il n'y avait pas le forex actuel le 1<sup>er</sup> janvier 1970. C'est seulement à partir de 1973, que les monnaies ont été flottantes. Pour les valeurs décimales, il va falloir trouver un nombre très particulier qui ne sera pas utilisé. Pour les <span style="color: blue;">double</span> il y a un problème, ce sont les possibilités d'écriture d'un nombre décimal avec MQL4 qui ne permet que les chiffres et le point décimal. Les valeurs possibles peuvent être très grandes et impossible à écrire de cette manière puisqu'il nous faudrait écrire un nombre de 308 chiffres pour écrire le nombre maximum. Il nous faudrait à la place une notation exponentielle qui n'existe pas en MQL4. Nous allons mettre -9876543210.0123456789 car il y a peu de chances de l'utiliser et la probabilité de tomber pile sur celle-la dans un calcul est extrêmement faible. Pour le type <span style="color: blue;">int</span> il y a deux cas à distinguer: si la valeur retournée n'est jamais négative, on peut utiliser -1. Si la valeur retournée peut être négative (signée, car affectée d'un signe) -1 ne convient pas, alors on va utiliser une autre valeur: la plus grande possible pour un nombre entier positif qui a très peu de probabilités d'être utilisée. Cette valeur, pour un nombre sur 4 octets, est précisément 2 147 483 647.</div>
<br />
<h3 style="text-decoration: underline;">
Un fichier include des constantes d'erreurs
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Nous allons utiliser ces constantes d'erreurs dans tous les codes que nous allons faire. Nous mettrons donc ces constantes dans un fichier header .mqh à inclure en premier dans les Experts Advisors et les indicateurs. Nommé «Contantes.mqh», en voici le code complet:
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Constantes.mq4 |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2014, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Constantes |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> ERREUR_INT_POSITIF = -<span style="color: #38761d;">1</span>;
<span style="color: blue;">int</span> ERREUR_INT_SIGNE = <span style="color: #38761d;">2147483647</span>;
<span style="color: blue;">bool</span> ERREUR_BOOL = -<span style="color: #38761d;">1</span>;
<span style="color: blue;">datetime</span> ERREUR_DATETIME = <span style="color: #38761d;">0</span>;
<span style="color: blue;">double</span> ERREUR_DOUBLE = -<span style="color: #38761d;">9876543210.0123456789</span>;
<span style="color: blue;">color</span> ERREUR_COLOR = -<span style="color: #38761d;">1</span>;
<span style="color: blue;">string</span> ERREUR_STRING = <span style="color: #45818e;">"-#-ERREUR-#-";</span>
<span style="color: #999999;">//+------------------------------------------------------------------+</span>
</code>
</pre>
Ce fichier header est bien évidemment à inclure, mais au début du fichier principal de notre programme, et il sera valable pour tous les includes qui utilisent ces constantes mais qui ne l'incluent pas. On ne peut pas l'inclure dans chaque fichier qui l'utilise, car avec les inclusions multiples, ce qu'il contient serait alors répété plusieurs fois dans le code, ce que le compilateur n'accepterait pas forcément.
</div>
<br />
<h3 style="text-decoration: underline;">
Ajout du test de validité dans les fonctions:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
La valeur <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #0b5394;">EMPTY</span> </code> est représentée par la constante <code style="background-color: white; color: black; font-weight: bold;"> -<span style="color: #38761d;">1</span> </code>, or les nombres négatifs sont non valides. Donc notre valeur par défaut provoquera une erreur. Il faut donc vérifier notre valeur par défaut avant, et la changer pour la valeur de la période courante avant de tester la validité. Puis nous testons la validité et exécutons le calcul seulement si elle est valide. Dans le cas contraire nous affichons une alerte avec la valeur reçue. Le test de validité est fait hors du <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">if</span> </code> et est stocké dans une variable booléenne juste avant pour une question de lisibilité de l'algorithme. Le nommage des variables nous permet dévoiler nos intentions dans l'algorithme. J'aurais pu placer ce test directement dans le <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">if</span> </code>. Nous mettons la valeur d'erreur <code style="background-color: white; color: black; font-weight: bold;"> ERREUR_INT_POSITIF </code> par défaut à l'initialisation de la variable qui contient la valeur retournée, comme ça lorsque le calcul n'est pas fait, le code d'erreur à retourner est déjà présent dans la variable de retour. Et si le calcul est fait, son résultat écrasera le code d'erreur. Les horodatages, n'ont pas de valeurs invalides car toutes positives et on toutes une signification, mais quelques valeurs ont très peu de probabilité d'être utilisées. On ne teste pas la validité des horodatages reçus en argument. On remarque tout de même qu'il y a un défaut à cette manière de faire, c'est le recouvrement des valeurs. Si le code produit une valeur erronée qui est exactement -1 et la passe en argument à une de nos fonction, cette valeur erronée sera considérée comme une demande d'utiliser la période courante. Il faut garder ceci à l'esprit, et il n'est pas bon de laisser un bug potentiel ! Il faut y remédier. Dans l'immédiat on déplace le problème en mettant la constante <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #0b5394;">NULL</span> </code> en valeur par défaut et dans le test correspondant. Le problème n'est pas réglé mais la valeur de recouvrement est située dans la partie positive et n'est pas utilisée. Le code appelant la fonction peut toujours produire une erreur en mettant en argument la valeur 0 qui sera prise comme une demande d'utiliser la période courante. Pour régler ce problème il faudrait séparer les demandes: une fonction pour la période courante sans argument et une fonction généraliste qui reçoit un argument. Je fais le choix de garder une unique fonction, bien que j'ai sûrement tord :( Voici le code des deux fonctions modifiées avec la définition des constantes chaînes des messages d'erreur dans la section constantes globales à ne pas oublier:
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">string</span> msgErrNbMinsNonValide = <span style="color: #45818e;">" a reçu un nombre de minutes non valide: "</span>;
<span style="color: blue;">string</span> msgErrNbSecsNonValide = <span style="color: #45818e;">" a reçu un nombre de secondes non valide: "</span>;
<span style="color: blue;">int</span> obtenirNbSecsDsPeriode(<span style="color: blue;">int</span> nbMinsDansPeriode=<span style="color: #0b5394;">NULL</span>) {
<span style="color: blue;">int</span> nbSecsDsPeriode = ERREUR_INT_POSITIF;
<span style="color: blue;">if</span>(nbMinsDansPeriode == <span style="color: #0b5394;">NULL</span>) { nbMinsDansPeriode = <span style="color: #674ea7;">Period</span>(); }
<span style="color: blue;">bool</span> nbMinsEstValide = (nbMinsDansPeriode > <span style="color: #38761d;">0</span>);
<span style="color: blue;">if</span>(nbMinsEstValide) { nbSecsDsPeriode = <span style="color: #38761d;">60</span> * nbMinsDansPeriode; }
<span style="color: blue;">else</span> { <span style="color: #674ea7;">Alert</span>(<span style="color: #45818e;">"ObtenirNbSecsDsPeriode() "</span>, msgErrNbMinsNonValide, nbMinsDansPeriode); }
<span style="color: blue;">return</span>(nbSecsDsPeriode);
}
<span style="color: blue;">int</span> obtenirNoSecDsPeriode(<span style="color: blue;">datetime</span> horodatageSec, <span style="color: blue;">int</span> nbSecsDansPeriode=<span style="color: #0b5394;">NULL</span>) {
<span style="color: blue;">int</span> noSecDansPeriode = ERREUR_INT_POSITIF;
<span style="color: blue;">if</span>(nbSecsDansPeriode == <span style="color: #0b5394;">NULL</span>) { nbSecsDansPeriode = obtenirNbSecsDsPeriode(); }
<span style="color: blue;">bool</span> nbSecsEstValide = (nbSecsDansPeriode > <span style="color: #38761d;">0</span>);
<span style="color: blue;">if</span>(nbSecsEstValide) { noSecDansPeriode = horodatageSec % nbSecsDansPeriode; }
<span style="color: blue;">else</span> { <span style="color: #674ea7;">Alert</span>(<span style="color: #45818e;">"ObtenirNoSecDsPeriode() "</span>, msgErrNbSecsNonValide, nbSecsDansPeriode); }
<span style="color: blue;">return</span>(noSecDansPeriode);
}
</code>
</pre>
</div>
<br />
<h3 style="text-decoration: underline;">
Modification des cas de tests:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Nous avons changé le comportement des fonctions vis à vis de valeurs reçues, il faut changer les cas de tests en conséquence. Pour la fonction obtenirNoDerniereSecConnue(), il n'y a pas de problèmes, d'ailleurs elle n'a pas été modifiée. Pour la fonction obtenirNbSecsDsPeriode() on modifie:<br />
<ul style="text-indent: 0;">
<li>le résultat attendu pour l'argument -2 qui est désormais ERREUR_INT_POSITIF</li>
<li>le résultat attendu pour l'argument 0 qui est la même valeur que le premier cas.</li>
</ul>
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
resultatsAttendus[<span style="color: #38761d;">3</span>] = ERREUR_INT_POSITIF;
resultatsAttendus[<span style="color: #38761d;">4</span>] = <span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>();
</code>
</pre>
Et Pour la fonction obtenirNoSecDsPeriode(), nous ajoutons ces deux cas:<br />
<ul style="text-indent: 0;">
<li>arguments 127 et 0 pour un résultat attendu identique au premier cas</li>
<li>arguments 127 et -4 pour un résultat attendu à ERREUR_INT_POSITIF. </li>
</ul>
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #38761d;">127</span>,
<span style="color: #38761d;">127</span>};
<span style="color: #38761d;">0</span>,
-<span style="color: #38761d;">4</span>};
<span style="color: #45818e;">" 127, 0 => "</span>,
<span style="color: #45818e;">" 127, -4 => "</span>};
resultatsAttendus[<span style="color: #38761d;">5</span>] = <span style="color: #38761d;">127</span> % (<span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>());
resultatsAttendus[<span style="color: #38761d;">6</span>] = ERREUR_INT_POSITIF;
</code>
</pre>
Et on n'oublie surtout pas d'ajouter l'include des constantes en haut du fichier ! Et de changer le nombre de cas de tests de 5 à 7 dans la définition de la constante ! =D
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">#include</span> <Constantes.mqh>
<span style="color: blue;">#define</span> NB_CAS_NO_SEC_IN_PERIOD <span style="color: #38761d;">7</span>
</code>
</pre>
</div>
<br />
<h3 style="text-decoration: underline;">
Le tutoriel vidéo et le code des deux fichiers modifiés :
</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='640' height='480' src='https://www.youtube.com/embed/OWs07DPLjCs?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<div style="text-align: justify; text-indent: 3em;">
Le fichier include des constantes créé dans ce post est déjà donné plus haut en intégralité. Ici, seulement les deux fichiers modifiés. J'ai ajouté un affichage d'une ligne de séparation pour bien distinguer l'annonce du total des erreurs à la fin des tests.<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| ArithmetiqueTemporelle.mqh |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2014, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| DLL imports |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| EX4 imports |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| includes |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| variables globales |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| constantes globales |
//+------------------------------------------------------------------+
<span style="color: blue;">string</span> msgErrNbMinsNonValide = <span style="color: #45818e;">" a reçu un nombre de minutes non valide: "</span>;
<span style="color: blue;">string</span> msgErrNbSecsNonValide = <span style="color: #45818e;">" a reçu un nombre de secondes non valide: "</span>;
//+------------------------------------------------------------------+
//| fonctions comptage |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">datetime</span> obtenirNoDerniereSecConnue(<span style="color: blue;">string</span> paire=<span style="color: #45818e;">"NULL"</span>) {
<span style="color: blue;">datetime</span> horodatage;
<span style="color: blue;">if</span>(paire==<span style="color: #45818e;">"NULL"</span>) { horodatage = <span style="color: #674ea7;">TimeCurrent</span>(); }
<span style="color: blue;">else</span> { horodatage = <span style="color: #674ea7;">MarketInfo</span>(paire, <span style="color: #0b5394;">MODE_TIME</span>); }
<span style="color: blue;">return</span>(horodatage);
}
<span style="color: blue;">int</span> obtenirNbSecsDsPeriode(<span style="color: blue;">int</span> nbMinsDansPeriode=<span style="color: #0b5394;">NULL</span>) {
<span style="color: blue;">int</span> nbSecsDsPeriode = ERREUR_INT_POSITIF;
<span style="color: blue;">if</span>(nbMinsDansPeriode == <span style="color: #0b5394;">NULL</span>) { nbMinsDansPeriode = <span style="color: #674ea7;">Period</span>(); }
<span style="color: blue;">bool</span> nbMinsEstValide = (nbMinsDansPeriode > <span style="color: #38761d;">0</span>);
<span style="color: blue;">if</span>(nbMinsEstValide) { nbSecsDsPeriode = <span style="color: #38761d;">60</span> * nbMinsDansPeriode; }
<span style="color: blue;">else</span> { <span style="color: #674ea7;">Alert</span>(<span style="color: #45818e;">"ObtenirNbSecsDsPeriode() "</span>, msgErrNbMinsNonValide, nbMinsDansPeriode); }
<span style="color: blue;">return</span>(nbSecsDsPeriode);
}
<span style="color: blue;">int</span> obtenirNoSecDsPeriode(<span style="color: blue;">datetime</span> horodatageSec, <span style="color: blue;">int</span> nbSecsDansPeriode=<span style="color: #0b5394;">NULL</span>) {
<span style="color: blue;">int</span> noSecDansPeriode = ERREUR_INT_POSITIF;
<span style="color: blue;">if</span>(nbSecsDansPeriode == <span style="color: #0b5394;">NULL</span>) { nbSecsDansPeriode = obtenirNbSecsDsPeriode(); }
<span style="color: blue;">bool</span> nbSecsEstValide = (nbSecsDansPeriode > <span style="color: #38761d;">0</span>);
<span style="color: blue;">if</span>(nbSecsEstValide) { noSecDansPeriode = horodatageSec % nbSecsDansPeriode; }
<span style="color: blue;">else</span> { <span style="color: #674ea7;">Alert</span>(<span style="color: #45818e;">"ObtenirNoSecDsPeriode() "</span>, msgErrNbSecsNonValide, nbSecsDansPeriode); }
<span style="color: blue;">return</span>(noSecDansPeriode);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span>
</code>
</pre>
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| testsArithmetiqueTemporelle.mqh |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2014, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: blue;">#include</span> <Constantes.mqh>
<span style="color: blue;">#include</span> <UtilitairesTests.mqh>
<span style="color: blue;">#include</span> <ArithmetiqueTemporelle.mqh>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#define</span> NB_CAS_LAST_KNOWN_SEC_NO <span style="color: #38761d;">5</span>
<span style="color: blue;">#define</span> NB_CAS_NB_SECS_IN_PERIOD <span style="color: #38761d;">5</span>
<span style="color: blue;">#define</span> NB_CAS_NO_SEC_IN_PERIOD <span style="color: #38761d;">7</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| constantes de tests |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">string</span> nomObtenirNoDerniereSecConnue = <span style="color: #45818e;">"obtenirNoDerniereSecConnue()"</span>;
<span style="color: blue;">string</span> nomObtenirNbSecsDsPeriode = <span style="color: #45818e;">"obtenirNbSecsDsPeriode()"</span>
<span style="color: blue;">string</span> nomObtenirNoSecDsPeriode = <span style="color: #45818e;">"obtenirNoSecDsPeriode()"</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| fonctions de tests |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">datetime</span> execObtenirNoDerniereSecConnue(<span style="color: blue;">string</span> argument) {
<span style="color: blue;">datetime</span> resultat;
<span style="color: blue;">if</span>(argument == ARG_STRING_EMPTY) { resultat = obtenirNoDerniereSecConnue(); }
<span style="color: blue;">else</span> { resultat = obtenirNoDerniereSecConnue(argument); }
<span style="color: blue;">return</span>(resultat);
}
<span style="color: blue;">int</span> testObtenirNoDerniereSecConnue() {
<span style="color: blue;">int</span> noCas, nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">datetime</span> resultat;
<span style="color: blue;">string</span> arguments[NB_CAS_LAST_KNOWN_SEC_NO] = {ARG_STRING_EMPTY,
<span style="color: #45818e;">"EURUSD"</span>,
<span style="color: #45818e;">"GBPJPY"</span>,
<span style="color: #45818e;">"EUR"</span>,
<span style="color: #45818e;">""</span>};
<span style="color: blue;">string</span> parametresCas[NB_CAS_LAST_KNOWN_SEC_NO] = {<span style="color: #45818e;">" sans paramètre => "</span>,
<span style="color: #45818e;">" \"EURUSD\" => "</span>,
<span style="color: #45818e;">" \"GBPJPY\" => "</span>,
<span style="color: #45818e;">" \"EUR\" => "</span>,
<span style="color: #45818e;">" \"\" => "</span>};
<span style="color: blue;">datetime</span> resultatsAttendus[NB_CAS_LAST_KNOWN_SEC_NO];
resultatsAttendus[<span style="color: #38761d;">0</span>] = <span style="color: #674ea7;">TimeCurrent</span>();
resultatsAttendus[<span style="color: #38761d;">1</span>] = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #45818e;">"EURUSD"</span>, <span style="color: #0b5394;">MODE_TIME</span>);
resultatsAttendus[<span style="color: #38761d;">2</span>] = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #45818e;">"GBPJPY"</span>, <span style="color: #0b5394;">MODE_TIME</span>);
resultatsAttendus[<span style="color: #38761d;">3</span>] = <span style="color: #38761d;">0</span>;
resultatsAttendus[<span style="color: #38761d;">4</span>] = <span style="color: #38761d;">0</span>;
<span style="color: blue;">for</span>(noCas=<span style="color: #38761d;">0</span> ; noCas<NB_CAS_LAST_KNOWN_SEC_NO ; noCas++) {
resultat = execObtenirNoDerniereSecConnue(arguments[noCas]);
nbErreurs += analyserResultatDatetimeDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNoDerniereSecConnue,
parametresCas[noCas]);
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: blue;">int</span> execObtenirNbSecsDsPeriode(<span style="color: blue;">int</span> argument) {
<span style="color: blue;">int</span> resultat;
<span style="color: blue;">if</span>(argument == ARG_INT_EMPTY) { resultat = obtenirNbSecsDsPeriode(); }
<span style="color: blue;">else</span> { resultat = obtenirNbSecsDsPeriode(argument); }
<span style="color: blue;">return</span>(resultat);
}
<span style="color: blue;">int</span> testObtenirNbSecsDsPeriode() {
<span style="color: blue;">int</span> noCas, nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">int</span> resultat;
<span style="color: blue;">int</span> arguments[NB_CAS_NB_SECS_IN_PERIOD] = {ARG_INT_EMPTY, <span style="color: #38761d;">5</span>, <span style="color: #38761d;">240</span>, -<span style="color: #38761d;">2</span>, <span style="color: #38761d;">0</span>};
<span style="color: blue;">string</span> parametresCas[NB_CAS_NB_SECS_IN_PERIOD] = {<span style="color: #45818e;">" sans paramètres => "</span>,
<span style="color: #45818e;">" 5 => "</span>,
<span style="color: #45818e;">" 240 => "</span>,
<span style="color: #45818e;">" -2 => "</span>,
<span style="color: #45818e;">" 0 => "</span>};
<span style="color: blue;">int</span> resultatsAttendus[NB_CAS_NB_SECS_IN_PERIOD];
resultatsAttendus[<span style="color: #38761d;">0</span>] = <span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>();
resultatsAttendus[<span style="color: #38761d;">1</span>] = <span style="color: #38761d;">300</span>;
resultatsAttendus[<span style="color: #38761d;">2</span>] = <span style="color: #38761d;">14400</span>;
resultatsAttendus[<span style="color: #38761d;">3</span>] = ERREUR_INT_POSITIF;
resultatsAttendus[<span style="color: #38761d;">4</span>] = <span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>();
<span style="color: blue;">for</span>(noCas=<span style="color: #38761d;">0</span> ; noCas<NB_CAS_NB_SECS_IN_PERIOD ; noCas++) {
resultat = execObtenirNbSecsDsPeriode(arguments[noCas]);
nbErreurs += analyserResultatIntDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNbSecsDsPeriode,
parametresCas[noCas]);
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: blue;">int</span> execObtenirNoSecDsPeriode(<span style="color: blue;">datetime</span> argumentHorodatage, <span style="color: blue;">int</span> argumentNbSecsDsPeriode) {
<span style="color: blue;">int</span> resultat;
<span style="color: blue;">if</span>(argumentNbSecsDsPeriode == ARG_INT_EMPTY) {
resultat = obtenirNoSecDsPeriode(argumentHorodatage); }
<span style="color: blue;">else</span> { resultat = obtenirNoSecDsPeriode(argumentHorodatage, argumentNbSecsDsPeriode); }
<span style="color: blue;">return</span>(resultat);
}
<span style="color: blue;">int</span> testObtenirNoSecDsPeriode() {
<span style="color: blue;">int</span> noCas, nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">int</span> resultat;
<span style="color: blue;">datetime</span> argumentsHorodatages[NB_CAS_NO_SEC_IN_PERIOD] = {<span style="color: #38761d;">127</span>,
<span style="color: #38761d;">123456789</span>,
<span style="color: #38761d;">123456789</span>,
<span style="color: #38761d;">123456789</span>,
<span style="color: #38761d;">127</span>,
<span style="color: #38761d;">127</span>,
<span style="color: #38761d;">127</span>};
<span style="color: blue;">int</span> argumentsNbSecsDsPeriode[NB_CAS_NO_SEC_IN_PERIOD] = {ARG_INT_EMPTY,
ARG_INT_EMPTY,
<span style="color: #38761d;">240</span>,
<span style="color: #38761d;">900</span>,
<span style="color: #38761d;">60</span>,
<span style="color: #38761d;">0</span>,
-<span style="color: #38761d;">4</span>};
<span style="color: blue;">string</span> parametresCas[NB_CAS_NO_SEC_IN_PERIOD] = {<span style="color: #45818e;">" 127, EMPTY => "</span>,
<span style="color: #45818e;">" 123456789, EMPTY => "</span>,
<span style="color: #45818e;">" 123456789, 240 => "</span>,
<span style="color: #45818e;">" 123456789, 900 => "</span>,
<span style="color: #45818e;">" 127, 60 => "</span>,
<span style="color: #45818e;">" 127, 0 => "</span>,
<span style="color: #45818e;">" 127, -4 => "</span>};
<span style="color: blue;">int</span> resultatsAttendus[NB_CAS_NO_SEC_IN_PERIOD];
resultatsAttendus[<span style="color: #38761d;">0</span>] = <span style="color: #38761d;">127</span> % (<span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>());
resultatsAttendus[<span style="color: #38761d;">1</span>] = <span style="color: #38761d;">123456789</span> % (<span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>());
resultatsAttendus[<span style="color: #38761d;">2</span>] = <span style="color: #38761d;">69</span>;
resultatsAttendus[<span style="color: #38761d;">3</span>] = <span style="color: #38761d;">189</span>;
resultatsAttendus[<span style="color: #38761d;">4</span>] = <span style="color: #38761d;">7</span>;
resultatsAttendus[<span style="color: #38761d;">5</span>] = <span style="color: #38761d;">127</span> % (<span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>());
resultatsAttendus[<span style="color: #38761d;">6</span>] = ERREUR_INT_POSITIF;
<span style="color: blue;">for</span>(noCas=<span style="color: #38761d;">0</span> ; noCas<NO_CAS_NB_SEC_IN_PERIOD ; noCas++) {
resultat = execObtenirNoSecsDsPeriode(argumentsHorodatages[noCas],
argumentsNbSecsDsPeriode[noCas]);
nbErreurs += analyserResultatIntDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNoSecDsPeriode,
parametresCas[noCas]);
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> init()
{
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
nbErreurs += testObtenirNoDerniereSecConnue();
nbErreurs += testObtenirNbSecsDsPeriode();
nbErreurs += testObtenirNoSecDsPeriode();
<span style="color: #674ea7;">Print</span>(<span style="color: #45818e;">"-------------------------------------------------------------------"</span>);
<span style="color: #674ea7;">Print</span>(<span style="color: #45818e;">"TESTS DE ArithmetiqueTemporelle.mqh TERMINES AVEC "</span>, nbErreurs, <span style="color: #45818e;">" ERREUR(S)."</span>);
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> deinit()
{
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> start()
{
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span>
</code>
</pre>
<br /></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-23354228829773003602014-01-31T12:30:00.000+01:002014-02-23T12:39:00.152+01:00Code de tests des fonctions de nombre et numéro de secondes dans les périodes<div style="text-align: justify; text-indent: 3em;">
Je l'avais dit: «il faut tester impérativement le code des fonctions des bibliothèques avant de les utiliser dans des projets.» et nous le faisons dès à présent.
</div>
<br />
<h3 style="text-decoration: underline;">
Factorisation des messages par défaut avec deux directives #define:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
La première fonction que nous avons réalisé pour le type datetime contient des messages par défaut, il faut les mutualiser pour ne pas les répéter dans le code. Mais nous ne pouvons pas employer de constantes, car le compilateur les refuse pour une déclaration d'argument de fonction. Nous allons alors utiliser deux directives préprocesseur <span style="color: blue;">#define</span>. Nous ajoutons donc ces deux lignes dans la section define du fichier UtilitairesTests.mqh:
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">#define</span> MESSAGE_ERREUR <span style="color: #45818e;">" a produit une erreur de résultat avec le cas "</span>
<span style="color: blue;">#define</span> MESSAGE_SUCCES <span style="color: #45818e;">" a passé le test sans erreurs "</span>
</code>
</pre>
Il faut ensuite mettre ces étiquettes aux endroits où il faut que ces chaines de caractères se trouvent. Donc dans la liste des arguments de la fonction analyserResultatDatetimeDuTest() du même fichier nous remplaçons les chaines de caractères et leurs guillemets par les étiquettes MESSAGE_ERREUR et MESSAGE_SUCCES. Il faut bien comprendre que cela ne change rien pour le compilateur qui lui verra le code comme si on n'avait fait aucune modification. En effet le préprocesseur passe avant le compilateur et remplace l'étiquette par les caractères qu'on a mis après l'étiquette sur la ligne du <span style="color: blue;">#define</span>. Donc le compilateur verra à la place des étiquettes dans le code les chaines que nous avons voulu mutualiser. Et les lignes de directives <span style="color: blue;">#define</span> ne seront plus là. Voici le code de la fonction:
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">int</span> analyserResultatDatetimeDuTest(
<span style="color: blue;">datetime</span> resultatTest,
<span style="color: blue;">datetime</span> resultatAttendu,
<span style="color: blue;">string</span> nomFonction,
<span style="color: blue;">string</span> parametresCas,
<span style="color: blue;">string</span> msgErreur=MESSAGE_ERREUR,
<span style="color: blue;">string</span> msgSucces=MESSAGE_SUCCES) {
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">if</span>(resultatTest == resultatAttendu) {
<span style="color: #674ea7;">Print</span>(nomFonction, msgSucces, resultatTest);
} <span style="color: blue;">else</span> {
<span style="color: #674ea7;">Print</span>(nomFonction, msgErreur, parametresCas, resultatTest);
nbErreurs++;
}
<span style="color: blue;">return</span>(nbErreurs);
}
</code>
</pre>
</div>
<br />
<h3 style="text-decoration: underline;">
Une fonction d'analyse de résultat de test pour le type int:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Maintenant occupons-nous de l'analyse du résultat de test, s'il est du type entier (<span style="color: blue;">int</span>). En effet, nous avons une fonction qui analyse le résultat d'un test seulement si c'est un horodatage (<span style="color: blue;">datetime</span>) et ne peut en analyser de types différents car on doit passer ce résultat en argument de la fonction, et que cet argument doit avoir un type bien précis. On va donc créer la même fonction mais pour le type entier où <span style="color: blue;">datetime</span> est remplacé par <span style="color: blue;">int</span> y compris dans le nom et avec une majuscule pour la lisibilité (sinon il y aurait deux fonctions du même nom ce que le compilateur refuse et on ne pourrait pas les distinguer). Voici le code de cette fonction:
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">int</span> analyserResultatIntDuTest(
<span style="color: blue;">int</span> resultatTest,
<span style="color: blue;">int</span> resultatAttendu,
<span style="color: blue;">string</span> nomFonction,
<span style="color: blue;">string</span> parametresCas,
<span style="color: blue;">string</span> msgErreur=MESSAGE_ERREUR,
<span style="color: blue;">string</span> msgSucces=MESSAGE_SUCCES) {
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">if</span>(resultatTest == resultatAttendu) {
<span style="color: #674ea7;">Print</span>(nomFonction, msgSucces, resultatTest);
} <span style="color: blue;">else</span> {
<span style="color: #674ea7;">Print</span>(nomFonction, msgErreur, parametresCas, resultatTest);
nbErreurs++;
}
<span style="color: blue;">return</span>(nbErreurs);
}
</code>
</pre>
Et pourquoi attendre ? Dans la foulée, on écrit (ou plutôt copie et colle, avec trois modifications pour chacune) les mêmes fonctions pour les types <span style="color: blue;">bool</span>, <span style="color: blue;">double</span>, <span style="color: blue;">string</span> et <span style="color: blue;">color</span>. Je vous donne le code complet du fichier à la fin du post. (Ces codes complets sont juste là pour vous donner une référence, un moyen de contrôle sur vos écritures, il faudrait pour bien apprendre que vous fassiez l'effort d'écrire vous même le code.)</div>
<br />
<h3 style="text-decoration: underline;">
Le test de ObtenirNbSecsDsPeriode():
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
On peut donc maintenant écrire du code pour tester notre deuxième fonction du fichier include, celle qui donne le nombre de secondes dans une période. Il y a peu de cas à tester, ce sera assez rapide, car cette fonction prend un entier positif qu'on lui fournit et le multiplie par 60. Si on ne lui donne pas, elle le récupère sur la période courante. On va donc tester deux cas positifs, un cas négatif, un cas nul et un cas sans argument. Ce sera largement suffisant. Normalement, aucun nombre négatif n'est sensé être passé à cette fonction, mais ça ne l'empêchera pas de donner un résultat. Nous n'avons pas fait de code pour lever une erreur si l'argument venait à être négatif, ou bien fournir une valeur par défaut si l'argument n'est pas bon. C'est à réfléchir. Nous verrons ça plus après. Il n'y a qu'un seul argument à la fonction à tester, donc un code d'exécution binaire simple: avec ou sans l'argument. On va donc coder nos deux fonctions: une pour l'exécution avec ou sans argument et l'autre pour faire tous les cas de test et faire analyser les résultat. On n'oublie pas non plus d'ajouter un <span style="color: blue;">#define</span> pour le nombre de cas de test et la constante qui contient le nom de la fonction. On change évidemment les types des résultats et des arguments. Et on ajoute une ligne exécutant la fonction de test dans la fonction init(), sinon, pas de test ! Et bien sûr, on change les valeurs des arguments et résultats pour les différents cas. Voici les cas traités:<br />
<ol style="text-indent: 0;">
<li>Sans argument, le résultat attendu est le nombre de secondes de la période courante, soit <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>() </code>.</li>
<li>Argument 5 (timeframe M5), le résultat attendu est 5*60=300.</li>
<li>Argument 240 (timeframe H4), le résultat attendu est 240*60=14 400.</li>
<li>Argument -2 (ne doit normalement pas arriver, sauf bug), résultat attendu -2*60=-120.</li>
<li>Argument 0 (no doit normalement pas arriver, sauf bug), résultat attendu 0*60=0. </li>
</ol>
Voici les lignes de codes à ajouter à l'expert de test de l'include (testArithmetiqueTemporelle.mq4):
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">#define</span> NB_CAS_NB_SECS_IN_PERIOD <span style="color: #38761d;">5</span>
<span style="color: blue;">string</span> nomObtenirNbSecsDsPeriode = <span style="color: #45818e;">"obtenirNbSecsDsPeriode()"</span>
<span style="color: blue;">int</span> execObtenirNbSecsDsPeriode(<span style="color: blue;">int</span> argument) {
<span style="color: blue;">int</span> resultat;
<span style="color: blue;">if</span>(argument == ARG_INT_EMPTY) { resultat = obtenirNbSecsDsPeriode(); }
<span style="color: blue;">else</span> { resultat = obtenirNbSecsDsPeriode(argument); }
<span style="color: blue;">return</span>(resultat);
}
<span style="color: blue;">int</span> testObtenirNbSecsDsPeriode() {
<span style="color: blue;">int</span> noCas, nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">int</span> resultat;
<span style="color: blue;">int</span> arguments[NB_CAS_NB_SECS_IN_PERIOD] = {ARG_INT_EMPTY, <span style="color: #38761d;">5</span>, <span style="color: #38761d;">240</span>, -<span style="color: #38761d;">2</span>, <span style="color: #38761d;">0</span>};
<span style="color: blue;">string</span> parametresCas[NB_CAS_NB_SECS_IN_PERIOD] = {<span style="color: #45818e;">" sans paramètres => "</span>,
<span style="color: #45818e;">" 5 => "</span>,
<span style="color: #45818e;">" 240 => "</span>,
<span style="color: #45818e;">" -2 => "</span>,
<span style="color: #45818e;">" 0 => "</span>};
<span style="color: blue;">int</span> resultatsAttendus[NB_CAS_NB_SECS_IN_PERIOD];
resultatsAttendus[<span style="color: #38761d;">0</span>] = <span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>();
resultatsAttendus[<span style="color: #38761d;">1</span>] = <span style="color: #38761d;">300</span>;
resultatsAttendus[<span style="color: #38761d;">2</span>] = <span style="color: #38761d;">14400</span>;
resultatsAttendus[<span style="color: #38761d;">3</span>] = -<span style="color: #38761d;">120</span>;
resultatsAttendus[<span style="color: #38761d;">4</span>] = <span style="color: #38761d;">0</span>;
<span style="color: blue;">for</span>(noCas=<span style="color: #38761d;">0</span> ; noCas<NB_CAS_NB_SECS_IN_PERIOD ; noCas++) {
resultat = execObtenirNbSecsDsPeriode(arguments[noCas]);
nbErreurs += analyserResultatIntDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNbSecsDsPeriode,
parametresCas[noCas]);
}
<span style="color: blue;">return</span>(nbErreurs);
}
</code>
</pre>
Et ne pas oublier la ligne à ajouter dans la fonction init():
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
nbErreurs += testObtenirNbSecsDsPeriode();
</code>
</pre>
</div>
<br />
<h3 style="text-decoration: underline;">
Le test de obtenirNoSecDsPeriode():
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Même chose pour la fonction qui calcule le numéro de seconde à l'intérieur d'une période. La différence est qu'elle reçoit deux arguments au lieu d'un seul, et que l'un des deux est optionnel. Nous prévoyons donc cinq cas de tests aussi, deux sans l'argument optionnel et trois avec le deuxième argument:<br />
<ol style="text-align: left; text-indent: 0;">
<li>Sans l'argument optionnel, et avec un petit horodatage: 127.<br />Résultat attendu: <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #38761d;">127</span> % (<span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>())</code>.</li>
<li>Sans l'argument optionnel, et avec un horodatage plus conséquent: 123456789.<br />Résultat attendu: <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #38761d;">123456789</span> % (<span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>())</code>.</li>
<li>Avec un nombre de secondes par période de 240 et un horodatage de 123456789.<br />Résultat attendu:<code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #38761d;">69</span></code>.</li>
<li>Avec un nombre de secondes par période de 900 et un horodatage de 123456789.<br />Résultat attendu:<code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #38761d;">189</span></code>.</li>
<li>Avec un nombre de secondes par période de 60 et un horodatage de 127.<br />Résultat attendu:<code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #38761d;">7</span></code>.</li>
</ol>
</div>
<br />
Pour le code, on ajoute la directive <span style="color: blue;">#define</span> pour déclarer le nombre de cas de test, la constante <span style="color: blue;">string</span> pour définir le nom de la fonction pour les affichages, on écrit la fonction qui exécute la fonction à tester selon le cas avec ou sans argument optionnel. On écrit aussi la fonction de test qui définit les valeurs des cas et fait les tests dans une boucle. Pour les valeurs des cas de test, il faut ajouter un autre tableau d'arguments puisqu'elle en demande deux. Et on n'oublie pas d'ajouter la ligne d'exécution du test de cette fonction dans la fonction init(). Voici le code à ajouter à l'expert advisor:
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">#define</span> NB_CAS_NO_SEC_IN_PERIOD <span style="color: #38761d;">5</span>
<span style="color: blue;">string</span> nomObtenirNoSecDsPeriode = <span style="color: #45818e;">"obtenirNoSecDsPeriode()"</span>
<span style="color: blue;">int</span> execObtenirNoSecDsPeriode(<span style="color: blue;">datetime</span> argumentHorodatage, <span style="color: blue;">int</span> argumentNbSecsDsPeriode) {
<span style="color: blue;">int</span> resultat;
<span style="color: blue;">if</span>(argumentNbSecsDsPeriode == ARG_INT_EMPTY) {
resultat = obtenirNoSecDsPeriode(argumentHorodatage); }
<span style="color: blue;">else</span> { resultat = obtenirNoSecDsPeriode(argumentHorodatage, argumentNbSecsDsPeriode); }
<span style="color: blue;">return</span>(resultat);
}
<span style="color: blue;">int</span> testObtenirNoSecDsPeriode() {
<span style="color: blue;">int</span> noCas, nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">int</span> resultat;
<span style="color: blue;">datetime</span> argumentsHorodatages[NB_CAS_NO_SEC_IN_PERIOD] = {<span style="color: #38761d;">127</span>,
<span style="color: #38761d;">123456789</span>,
<span style="color: #38761d;">123456789</span>,
<span style="color: #38761d;">123456789</span>,
<span style="color: #38761d;">127</span>};
<span style="color: blue;">int</span> argumentsNbSecsDsPeriode[NB_CAS_NO_SEC_IN_PERIOD] = {ARG_INT_EMPTY,
ARG_INT_EMPTY,
<span style="color: #38761d;">240</span>,
<span style="color: #38761d;">900</span>,
<span style="color: #38761d;">60</span>};
<span style="color: blue;">string</span> parametresCas[NB_CAS_NO_SEC_IN_PERIOD] = {<span style="color: #45818e;">" 127, EMPTY => "</span>,
<span style="color: #45818e;">" 123456789, EMPTY => "</span>,
<span style="color: #45818e;">" 123456789, 240 => "</span>,
<span style="color: #45818e;">" 123456789, 900 => "</span>,
<span style="color: #45818e;">" 127, 60 => "</span>};
<span style="color: blue;">int</span> resultatsAttendus[NB_CAS_NO_SEC_IN_PERIOD];
resultatsAttendus[<span style="color: #38761d;">0</span>] = <span style="color: #38761d;">127</span> % (<span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>());
resultatsAttendus[<span style="color: #38761d;">1</span>] = <span style="color: #38761d;">123456789</span> % (<span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>());
resultatsAttendus[<span style="color: #38761d;">2</span>] = <span style="color: #38761d;">69</span>;
resultatsAttendus[<span style="color: #38761d;">3</span>] = <span style="color: #38761d;">189</span>;
resultatsAttendus[<span style="color: #38761d;">4</span>] = <span style="color: #38761d;">7</span>;
<span style="color: blue;">for</span>(noCas=<span style="color: #38761d;">0</span> ; noCas<NO_CAS_NB_SEC_IN_PERIOD ; noCas++) {
resultat = execObtenirNbSecsDsPeriode(argumentsHorodatages[noCas],
argumentsNbSecsDsPeriode[noCas]);
nbErreurs += analyserResultatIntDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNoSecDsPeriode,
parametresCas[noCas]);
}
<span style="color: blue;">return</span>(nbErreurs);
}
</code>
</pre>
Le code est un peu décousu car des lignes sont tronquées. Visionnez la vidéo et vous aurez une meilleure présentation. Et dans la fonction init():
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
nbErreurs += testObtenirNoSecDsPeriode();
</code>
</pre>
<br />
<h3 style="text-decoration: underline;">
Le tutoriel vidéo et les deux codes complets:
</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='640' height='480' src='https://www.youtube.com/embed/d3flmkrLUI4?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| UtilitairesTests.mqh |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2014, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#define</span> ARG_STRING_EMPTY <span style="color: #45818e;">"-#-EMPTY-#-"</span>
<span style="color: blue;">#define</span> ARG_INT_EMPTY <span style="color: #38761d;">2147483647</span>
<span style="color: blue;">#define</span> ARG_BOOL_EMPTY -<span style="color: #38761d;">1</span>
<span style="color: blue;">#define</span> ARG_DOUBLE_EMPTY <span style="color: #38761d;">123456789</span>.<span style="color: #38761d;">123456789</span>
<span style="color: blue;">#define</span> ARG_DATETIME_EMPTY <span style="color: #38761d;">4294967295</span>
<span style="color: blue;">#define</span> ARG_COLOR_EMPTY <span style="color: #38761d;">4294967295</span>
<span style="color: blue;">#define</span> MESSAGE_ERREUR <span style="color: #45818e;">" a produit une erreur de résultat avec le cas "</span>
<span style="color: blue;">#define</span> MESSAGE_SUCCES <span style="color: #45818e;">" a passé le test sans erreurs "</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| constantes de tests |
//+------------------------------------------------------------------+</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| fonctions |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> analyserResultatDatetimeDuTest(
<span style="color: blue;">datetime</span> resultatTest, <span style="color: blue;">datetime</span> resultatAttendu,
<span style="color: blue;">string</span> nomFonction, <span style="color: blue;">string</span> parametresCas,
<span style="color: blue;">string</span> msgErreur = MESSAGE_ERREUR, <span style="color: blue;">string</span> msgSucces = MESSAGE_SUCCES) {
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">if</span>(resultatTest == resultatAttendu) {
<span style="color: #674ea7;">Print</span>(nomFonction, msgSucces, resultatTest);
} <span style="color: blue;">else</span> {
<span style="color: #674ea7;">Print</span>(nomFonction, msgErreur, parametresCas, resultatTest);
nbErreurs++;
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: blue;">int</span> analyserResultatIntDuTest(
<span style="color: blue;">int</span> resultatTest, <span style="color: blue;">int</span> resultatAttendu,
<span style="color: blue;">string</span> nomFonction, <span style="color: blue;">string</span> parametresCas,
<span style="color: blue;">string</span> msgErreur = MESSAGE_ERREUR, <span style="color: blue;">string</span> msgSucces = MESSAGE_SUCCES) {
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">if</span>(resultatTest == resultatAttendu) {
<span style="color: #674ea7;">Print</span>(nomFonction, msgSucces, resultatTest);
} <span style="color: blue;">else</span> {
<span style="color: #674ea7;">Print</span>(nomFonction, msgErreur, parametresCas, resultatTest);
nbErreurs++;
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: blue;">int</span> analyserResultatBoolDuTest(
<span style="color: blue;">bool</span> resultatTest, <span style="color: blue;">bool</span> resultatAttendu,
<span style="color: blue;">string</span> nomFonction, <span style="color: blue;">string</span> parametresCas,
<span style="color: blue;">string</span> msgErreur = MESSAGE_ERREUR, <span style="color: blue;">string</span> msgSucces = MESSAGE_SUCCES) {
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">if</span>(resultatTest == resultatAttendu) {
<span style="color: #674ea7;">Print</span>(nomFonction, msgSucces, resultatTest);
} <span style="color: blue;">else</span> {
<span style="color: #674ea7;">Print</span>(nomFonction, msgErreur, parametresCas, resultatTest);
nbErreurs++;
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: blue;">int</span> analyserResultatDoubleDuTest(
<span style="color: blue;">double</span> resultatTest, <span style="color: blue;">double</span> resultatAttendu,
<span style="color: blue;">string</span> nomFonction, <span style="color: blue;">string</span> parametresCas,
<span style="color: blue;">string</span> msgErreur = MESSAGE_ERREUR, <span style="color: blue;">string</span> msgSucces = MESSAGE_SUCCES) {
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">if</span>(resultatTest == resultatAttendu) {
<span style="color: #674ea7;">Print</span>(nomFonction, msgSucces, resultatTest);
} <span style="color: blue;">else</span> {
<span style="color: #674ea7;">Print</span>(nomFonction, msgErreur, parametresCas, resultatTest);
nbErreurs++;
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: blue;">int</span> analyserResultatStringDuTest(
<span style="color: blue;">string</span> resultatTest, <span style="color: blue;">string</span> resultatAttendu,
<span style="color: blue;">string</span> nomFonction, <span style="color: blue;">string</span> parametresCas,
<span style="color: blue;">string</span> msgErreur = MESSAGE_ERREUR, <span style="color: blue;">string</span> msgSucces = MESSAGE_SUCCES) {
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">if</span>(resultatTest == resultatAttendu) {
<span style="color: #674ea7;">Print</span>(nomFonction, msgSucces, resultatTest);
} <span style="color: blue;">else</span> {
<span style="color: #674ea7;">Print</span>(nomFonction, msgErreur, parametresCas, resultatTest);
nbErreurs++;
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: blue;">int</span> analyserResultatColorDuTest(
<span style="color: blue;">color</span> resultatTest, <span style="color: blue;">color</span> resultatAttendu,
<span style="color: blue;">string</span> nomFonction, <span style="color: blue;">string</span> parametresCas,
<span style="color: blue;">string</span> msgErreur = MESSAGE_ERREUR, <span style="color: blue;">string</span> msgSucces = MESSAGE_SUCCES) {
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">if</span>(resultatTest == resultatAttendu) {
<span style="color: #674ea7;">Print</span>(nomFonction, msgSucces, resultatTest);
} <span style="color: blue;">else</span> {
<span style="color: #674ea7;">Print</span>(nomFonction, msgErreur, parametresCas, resultatTest);
nbErreurs++;
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span>
</code>
</pre>
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| testsArithmetiqueTemporelle.mqh |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2014, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: blue;">#include <UtilitairesTests.mqh></span>
<span style="color: blue;">#include <ArithmetiqueTemporelle.mqh></span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#define</span> NB_CAS_LAST_KNOWN_SEC_NO <span style="color: #38761d;">5</span>
<span style="color: blue;">#define</span> NB_CAS_NB_SECS_IN_PERIOD <span style="color: #38761d;">5</span>
<span style="color: blue;">#define</span> NB_CAS_NO_SEC_IN_PERIOD <span style="color: #38761d;">5</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| constantes de tests |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">string</span> nomObtenirNoDerniereSecConnue = <span style="color: #45818e;">"obtenirNoDerniereSecConnue()"</span>;
<span style="color: blue;">string</span> nomObtenirNbSecsDsPeriode = <span style="color: #45818e;">"obtenirNbSecsDsPeriode()"</span>
<span style="color: blue;">string</span> nomObtenirNoSecDsPeriode = <span style="color: #45818e;">"obtenirNoSecDsPeriode()"</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| fonctions de tests |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">datetime</span> execObtenirNoDerniereSecConnue(<span style="color: blue;">string</span> argument) {
<span style="color: blue;">datetime</span> resultat;
<span style="color: blue;">if</span>(argument == ARG_STRING_EMPTY) { resultat = obtenirNoDerniereSecConnue(); }
<span style="color: blue;">else</span> { resultat = obtenirNoDerniereSecConnue(argument); }
<span style="color: blue;">return</span>(resultat);
}
<span style="color: blue;">int</span> testObtenirNoDerniereSecConnue() {
<span style="color: blue;">int</span> noCas, nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">datetime</span> resultat;
<span style="color: blue;">string</span> arguments[NB_CAS_LAST_KNOWN_SEC_NO] = {ARG_STRING_EMPTY,
<span style="color: #45818e;">"EURUSD"</span>,
<span style="color: #45818e;">"GBPJPY"</span>,
<span style="color: #45818e;">"EUR"</span>,
<span style="color: #45818e;">""</span>};
<span style="color: blue;">string</span> parametresCas[NB_CAS_LAST_KNOWN_SEC_NO] = {<span style="color: #45818e;">" sans paramètre => "</span>,
<span style="color: #45818e;">" \"EURUSD\" => "</span>,
<span style="color: #45818e;">" \"GBPJPY\" => "</span>,
<span style="color: #45818e;">" \"EUR\" => "</span>,
<span style="color: #45818e;">" \"\" => "</span>};
<span style="color: blue;">datetime</span> resultatsAttendus[NB_CAS_LAST_KNOWN_SEC_NO];
resultatsAttendus[<span style="color: #38761d;">0</span>] = <span style="color: #674ea7;">TimeCurrent</span>();
resultatsAttendus[<span style="color: #38761d;">1</span>] = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #45818e;">"EURUSD"</span>, <span style="color: #0b5394;">MODE_TIME</span>);
resultatsAttendus[<span style="color: #38761d;">2</span>] = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #45818e;">"GBPJPY"</span>, <span style="color: #0b5394;">MODE_TIME</span>);
resultatsAttendus[<span style="color: #38761d;">3</span>] = <span style="color: #38761d;">0</span>;
resultatsAttendus[<span style="color: #38761d;">4</span>] = <span style="color: #38761d;">0</span>;
<span style="color: blue;">for</span>(noCas=<span style="color: #38761d;">0</span> ; noCas<NB_CAS_LAST_KNOWN_SEC_NO ; noCas++) {
resultat = execObtenirNoDerniereSecConnue(arguments[noCas]);
nbErreurs += analyserResultatDatetimeDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNoDerniereSecConnue,
parametresCas[noCas]);
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: blue;">int</span> execObtenirNbSecsDsPeriode(<span style="color: blue;">int</span> argument) {
<span style="color: blue;">int</span> resultat;
<span style="color: blue;">if</span>(argument == ARG_INT_EMPTY) { resultat = obtenirNbSecsDsPeriode(); }
<span style="color: blue;">else</span> { resultat = obtenirNbSecsDsPeriode(argument); }
<span style="color: blue;">return</span>(resultat);
}
<span style="color: blue;">int</span> testObtenirNbSecsDsPeriode() {
<span style="color: blue;">int</span> noCas, nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">int</span> resultat;
<span style="color: blue;">int</span> arguments[NB_CAS_NB_SECS_IN_PERIOD] = {ARG_INT_EMPTY, <span style="color: #38761d;">5</span>, <span style="color: #38761d;">240</span>, -<span style="color: #38761d;">2</span>, <span style="color: #38761d;">0</span>};
<span style="color: blue;">string</span> parametresCas[NB_CAS_NB_SECS_IN_PERIOD] = {<span style="color: #45818e;">" sans paramètres => "</span>,
<span style="color: #45818e;">" 5 => "</span>,
<span style="color: #45818e;">" 240 => "</span>,
<span style="color: #45818e;">" -2 => "</span>,
<span style="color: #45818e;">" 0 => "</span>};
<span style="color: blue;">int</span> resultatsAttendus[NB_CAS_NB_SECS_IN_PERIOD];
resultatsAttendus[<span style="color: #38761d;">0</span>] = <span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>();
resultatsAttendus[<span style="color: #38761d;">1</span>] = <span style="color: #38761d;">300</span>;
resultatsAttendus[<span style="color: #38761d;">2</span>] = <span style="color: #38761d;">14400</span>;
resultatsAttendus[<span style="color: #38761d;">3</span>] = -<span style="color: #38761d;">120</span>;
resultatsAttendus[<span style="color: #38761d;">4</span>] = <span style="color: #38761d;">0</span>;
<span style="color: blue;">for</span>(noCas=<span style="color: #38761d;">0</span> ; noCas<NB_CAS_NB_SECS_IN_PERIOD ; noCas++) {
resultat = execObtenirNbSecsDsPeriode(arguments[noCas]);
nbErreurs += analyserResultatIntDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNbSecsDsPeriode,
parametresCas[noCas]);
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: blue;">int</span> execObtenirNoSecDsPeriode(<span style="color: blue;">datetime</span> argumentHorodatage, <span style="color: blue;">int</span> argumentNbSecsDsPeriode) {
<span style="color: blue;">int</span> resultat;
<span style="color: blue;">if</span>(argumentNbSecsDsPeriode == ARG_INT_EMPTY) {
resultat = obtenirNoSecDsPeriode(argumentHorodatage); }
<span style="color: blue;">else</span> { resultat = obtenirNoSecDsPeriode(argumentHorodatage, argumentNbSecsDsPeriode); }
<span style="color: blue;">return</span>(resultat);
}
<span style="color: blue;">int</span> testObtenirNoSecDsPeriode() {
<span style="color: blue;">int</span> noCas, nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">int</span> resultat;
<span style="color: blue;">datetime</span> argumentsHorodatages[NB_CAS_NO_SEC_IN_PERIOD] = {<span style="color: #38761d;">127</span>,
<span style="color: #38761d;">123456789</span>,
<span style="color: #38761d;">123456789</span>,
<span style="color: #38761d;">123456789</span>,
<span style="color: #38761d;">127</span>};
<span style="color: blue;">int</span> argumentsNbSecsDsPeriode[NB_CAS_NO_SEC_IN_PERIOD] = {ARG_INT_EMPTY,
ARG_INT_EMPTY,
<span style="color: #38761d;">240</span>,
<span style="color: #38761d;">900</span>,
<span style="color: #38761d;">60</span>};
<span style="color: blue;">string</span> parametresCas[NB_CAS_NO_SEC_IN_PERIOD] = {<span style="color: #45818e;">" 127, EMPTY => "</span>,
<span style="color: #45818e;">" 123456789, EMPTY => "</span>,
<span style="color: #45818e;">" 123456789, 240 => "</span>,
<span style="color: #45818e;">" 123456789, 900 => "</span>,
<span style="color: #45818e;">" 127, 60 => "</span>};
<span style="color: blue;">int</span> resultatsAttendus[NB_CAS_NO_SEC_IN_PERIOD];
resultatsAttendus[<span style="color: #38761d;">0</span>] = <span style="color: #38761d;">127</span> % (<span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>());
resultatsAttendus[<span style="color: #38761d;">1</span>] = <span style="color: #38761d;">123456789</span> % (<span style="color: #38761d;">60</span> * <span style="color: #674ea7;">Period</span>());
resultatsAttendus[<span style="color: #38761d;">2</span>] = <span style="color: #38761d;">69</span>;
resultatsAttendus[<span style="color: #38761d;">3</span>] = <span style="color: #38761d;">189</span>;
resultatsAttendus[<span style="color: #38761d;">4</span>] = <span style="color: #38761d;">7</span>;
<span style="color: blue;">for</span>(noCas=<span style="color: #38761d;">0</span> ; noCas<NO_CAS_NB_SEC_IN_PERIOD ; noCas++) {
resultat = execObtenirNoSecsDsPeriode(argumentsHorodatages[noCas],
argumentsNbSecsDsPeriode[noCas]);
nbErreurs += analyserResultatIntDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNoSecDsPeriode,
parametresCas[noCas]);
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> init()
{
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
nbErreurs += testObtenirNoDerniereSecConnue();
nbErreurs += testObtenirNbSecsDsPeriode();
nbErreurs += testObtenirNoSecDsPeriode();
<span style="color: #674ea7;">Print</span>(<span style="color: #45818e;">"TESTS DE ArithmetiqueTemporelle.mqh TERMINES AVEC "</span>, nbErreurs, <span style="color: #45818e;">" ERREUR(S)."</span>);
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> deinit()
{
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> start()
{
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span>
</code>
</pre>
<br />
<div style="text-align: justify; text-indent: 3em;">
Ouf =D Ça commence à en faire du code ! C'est assez répétitif, à cause des limitations de MQL4: on fait ce qu'on peut ! Si quelqu'un voit une amélioration, qu'il la propose je suis preneur. Faites attention aux modifications à apporter à chaque copier coller de fonction. Il ne faut pas en oublier car le compilateur ne vous dira pas forcément qu'il y a un problème. Vous pouvez laissez par exemple un <span style="color: blue;">datetime</span> sans le changer en <span style="color: blue;">int</span>, et ça passe, le compilateur ne vous dit rien, mais vous aurez des bugs potentiels car il y a des valeurs qui changent en faisant les conversions d'un <span style="color: blue;">int</span> à un <span style="color: blue;">datetime</span> et inversement.</div>
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-78973996808800584222014-01-29T19:40:00.001+01:002014-01-30T21:05:08.699+01:00Traitement du cas de test sans argument<div style="text-align: justify; text-indent: 3em;">
A faire des fonctions utilisant la valeur par défaut <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #0b5394;">EMPTY</span> </code> je réfléchissais aux tests des fonctions et du traitement du cas sans argument. Je ne peux pas laisser ce problème de côté, il faut le régler, je fais donc ce post pour améliorer le code de tests de fonctions une seconde fois. Le problème est que lorsque je mets une valeur par défaut, il faudrait tester le cas ou je ne passe pas l'argument avec valeur par défaut pour voir si le code qui doit gérer ce cas dans la fonction testée fonctionne bien. Or en passant la valeur par défaut, je ne teste pas forcément la portion de code qui y est dédiée surtout si j'emploie la valeur <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #0b5394;">EMPTY</span> </code> que je ne peux stocker dans une variable, ni même passer en argument car le compilateur refuse. Nous allons donc régler ce problème: traiter le cas sans argument et pouvoir mettre la constante <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #0b5394;">EMPTY</span> </code>.
</div>
<br />
<h3 style="text-decoration: underline;">
Utilisation de la constante EMPTY dans la fonction à tester:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Attention ! La constante <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #0b5394;">EMPTY</span> </code> est à utiliser avec précautions. Je m'explique: elle possède une valeur entière valide qui est -1. Première conclusion, on ne peut pas l'utiliser avec les types <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">double</span> </code> ou <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: blue;">string</span> </code> (les autres types acceptant les nombres entiers). Deuxième remarque, c'est une valeur et il faut faire attention qu'elle ne soit pas utilisée parce que dans ce cas, quand on utilise la valeur -1 sans vouloir signifier une valeur vide, on se retrouve à traiter le cas de la valeur vide. Donc extrême vigilance. On ne touche donc pas au code de la première fonction obtenirNoDerniereSecConnue() qui a une valeur par défaut à <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #45818e;">"NULL"</span> </code> Cette valeur convient pour le cas, et <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #0b5394;">EMPTY</span> </code> ne serait pas acceptée par le compilateur pour cause d'incompatibilité de type.
</div>
<br />
<h3 style="text-decoration: underline;">
Création de directives #define pour des valeurs vides selon les types:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
C'est bien beau de mettre la valeur vide par défaut, mais il va falloir trouver un moyen de signaler à la fonction de test qu'il n'y a pas d'argument car le compilateur ne va pas accepter une valeur vide dans une variable, ni dans un tableau. En informant la fonction de test qu'il n'y a pas de valeur, donc pas d'argument à mettre, elle peut faire une alternative d'appel de la fonction sans cet argument. Il faut alors trouver le moyen de lui indiquer. Ce moyen va être la définition de directives <span style="color: blue;">#define</span> pour mettre dans les variables ou tableaux des constantes littérales. Ces constantes auront une valeur particulière dont on est certain (ou presque) qu'elles ne seront pas utilisées pour désigner le fait qu'il ne faut pas passer l'argument. Cette valeur est destinée à être stockée dans une variable ou un tableau, elle devra donc avoir le même type que l'argument. Il faut alors créer une directive <span style="color: blue;">#define</span> par argument. Bien obligé d'utiliser une directive préprocesseur au lieu de variables constantes, car le compilateur ne les accepte pas dans les tableaux. Elles devront être utilisées dans tous les tests, ont les définit donc dans l'include UtilitairesTests.mqh. On ajoute le code suivant dans ce fichier:<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#define</span> ARG_STRING_EMPTY <span style="color: #45818e;">"-#-EMPTY-#-"</span>
<span style="color: blue;">#define</span> ARG_INT_EMPTY <span style="color: #38761d;">2147483647</span>
<span style="color: blue;">#define</span> ARG_BOOL_EMPTY -<span style="color: #38761d;">1</span>
<span style="color: blue;">#define</span> ARG_DOUBLE_EMPTY <span style="color: #38761d;">123456789</span>.<span style="color: #38761d;">123456789</span>
<span style="color: blue;">#define</span> ARG_DATETIME_EMPTY <span style="color: #38761d;">4294967295</span>
<span style="color: blue;">#define</span> ARG_COLOR_EMPTY <span style="color: #38761d;">4294967295</span>
</code>
</pre>
Je propose ces valeurs car il y a une chaine de caractères très particulière dont il est très improbable de se servir dans les tests, la valeur positive maximum d'un entier, une valeur entière négative acceptée pour les booléens mais qui ne correspond ni à true (1) ni à false (0), une valeur décimale très grande et très particulière dont il est très improbable de se servir dans un test, une valeur entière pour datetime qui est la valeur maximum et la même valeur pour une couleur qui n'est pas utilisée car elle dépasse trois octets en mémoire (quatre octets tous remplis).
</div>
<br />
<h3 style="text-decoration: underline;">
Prise en compte des cas de test où un argument est absent:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Maintenant que nous avons de quoi informer la fonction de test qu'il y a un argument à laisser vide, nous pouvons ajouter le code pour qu'elle fasse une alternative à l'exécution de la fonction à tester: avec ou sans l'argument. Pour ne pas modifier la boucle de test des différents cas, nous ajoutons juste un préfixe à la fonction appelée pour placer notre code supplémentaire dans une autre fonction. Ce préfixe est «exec» car la nouvelle fonction qu'on crée est là pour exécuter la fonction à tester de différentes manières: avec ou sans les arguments optionnels. Dans cette nouvelle fonction nous testons l'égalité de l'argument avec la constante correspondante précédemment définie pour excéuter comme il faut la fonction à tester: c'est-à-dire que si l'argument est égal à la constante désignant une valeur vide, alors la fonction est exécutée sans cet argument, sinon avec l'argument. Nous changeons aussi la valeur des arguments absents en mettant aussi cette valeur précédemment définie dans le tableau des arguments.
</div>
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">datetime</span> execObtenirNoDerniereSecConnue(<span style="color: blue;">string</span> argument) {
<span style="color: blue;">datetime</span> resultat;
<span style="color: blue;">if</span>(argument == ARG_STRING_EMPTY) { resultat = obtenirNoDerniereSecConnue(); }
<span style="color: blue;">else</span> { resultat = obtenirNoDerniereSecConnue(argument); }
<span style="color: blue;">return</span>(resultat);
}
<span style="color: blue;">int</span> testObtenirNoDerniereSecConnue() {
<span style="color: blue;">int</span> noCas, nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">datetime</span> resultat;
<span style="color: blue;">string</span> arguments[NB_CAS_LAST_KNOWN_SEC_NO] = {ARG_STRING_EMPTY,
<span style="color: #45818e;">"EURUSD"</span>,
<span style="color: #45818e;">"GBPJPY"</span>,
<span style="color: #45818e;">"EUR"</span>,
<span style="color: #45818e;">""</span>};
<span style="color: blue;">string</span> parametresCas[NB_CAS_LAST_KNOWN_SEC_NO] = {<span style="color: #45818e;">" sans paramètre => "</span>,
<span style="color: #45818e;">" \"EURUSD\" => "</span>,
<span style="color: #45818e;">" \"GBPJPY\" => "</span>,
<span style="color: #45818e;">" \"EUR\" => "</span>,
<span style="color: #45818e;">" \"\" => "</span>};
<span style="color: blue;">datetime</span> resultatsAttendus[NB_CAS_LAST_KNOWN_SEC_NO];
resultatsAttendus[<span style="color: #38761d;">0</span>] = <span style="color: #674ea7;">TimeCurrent</span>();
resultatsAttendus[<span style="color: #38761d;">1</span>] = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #45818e;">"EURUSD"</span>, <span style="color: #0b5394;">MODE_TIME</span>);
resultatsAttendus[<span style="color: #38761d;">2</span>] = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #45818e;">"GBPJPY"</span>, <span style="color: #0b5394;">MODE_TIME</span>);
resultatsAttendus[<span style="color: #38761d;">3</span>] = <span style="color: #38761d;">0</span>;
resultatsAttendus[<span style="color: #38761d;">4</span>] = <span style="color: #38761d;">0</span>;
<span style="color: blue;">for</span>(noCas=<span style="color: #38761d;">0</span> ; noCas<NB_CAS_LAST_KNOWN_SEC_NO ; noCas++) {
resultat = execObtenirNoDerniereSecConnue(arguments[noCas]);
nbErreurs += analyserResultatDatetimeDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNoDerniereSecConnue,
parametresCas[noCas]);
}
<span style="color: blue;">return</span>(nbErreurs);
}
</code>
</pre>
<br />
<h3 style="text-decoration: underline;">
Le tutoriel vidéo et les deux fichiers de code complets:
</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='640' height='480' src='https://www.youtube.com/embed/VKKAGJe-Kfo?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| UtilitairesTests.mqh |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2014, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#define</span> ARG_STRING_EMPTY <span style="color: #45818e;">"-#-EMPTY-#-"</span>
<span style="color: blue;">#define</span> ARG_INT_EMPTY <span style="color: #38761d;">2147483647</span>
<span style="color: blue;">#define</span> ARG_BOOL_EMPTY -<span style="color: #38761d;">1</span>
<span style="color: blue;">#define</span> ARG_DOUBLE_EMPTY <span style="color: #38761d;">123456789</span>.<span style="color: #38761d;">123456789</span>
<span style="color: blue;">#define</span> ARG_DATETIME_EMPTY <span style="color: #38761d;">4294967295</span>
<span style="color: blue;">#define</span> ARG_COLOR_EMPTY <span style="color: #38761d;">4294967295</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| constantes de tests |
//+------------------------------------------------------------------+</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| fonctions |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> analyserResultatDatetimeDuTest(
<span style="color: blue;">datetime</span> resultatTest,
<span style="color: blue;">datetime</span> resultatAttendu,
<span style="color: blue;">string</span> nomFonction,
<span style="color: blue;">string</span> parametresCas,
<span style="color: blue;">string</span> msgErreur = <span style="color: #45818e;">" a produit une erreur de résultat avec le cas "</span>,
<span style="color: blue;">string</span> msgSucces = <span style="color: #45818e;">" a passé le test sans erreurs "</span>) {
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">if</span>(resultatTest == resultatAttendu) {
<span style="color: #674ea7;">Print</span>(nomFonction, msgSucces, resultatTest);
} <span style="color: blue;">else</span> {
<span style="color: #674ea7;">Print</span>(nomFonction, msgErreur, parametresCas, resultatTest);
nbErreurs++;
}
<span style="color: blue;">return</span>(nbErreurs);
}
</code>
</pre>
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| testsArithmetiqueTemporelle.mqh |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2014, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: blue;">#include</span> <UtilitairesTests.mqh>
<span style="color: blue;">#include</span> <ArithmetiqueTemporelle.mqh>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#define</span> NB_CAS_LAST_KNOWN_SEC_NO <span style="color: #38761d;">5</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| constantes de tests |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">string</span> nomObtenirNoDerniereSecConnue = <span style="color: #45818e;">"obtenirNoDerniereSecConnue()"</span>;
<span style="color: #999999;">//+------------------------------------------------------------------+
//| fonctions de tests |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">datetime</span> execObtenirNoDerniereSecConnue(<span style="color: blue;">string</span> argument) {
<span style="color: blue;">datetime</span> resultat;
<span style="color: blue;">if</span>(argument == ARG_STRING_EMPTY) { resultat = obtenirNoDerniereSecConnue(); }
<span style="color: blue;">else</span> { resultat = obtenirNoDerniereSecConnue(argument); }
<span style="color: blue;">return</span>(resultat);
}
<span style="color: blue;">int</span> testObtenirNoDerniereSecConnue() {
<span style="color: blue;">int</span> noCas, nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">datetime</span> resultat;
<span style="color: blue;">string</span> arguments[NB_CAS_LAST_KNOWN_SEC_NO] = {ARG_STRING_EMPTY,
<span style="color: #45818e;">"EURUSD"</span>,
<span style="color: #45818e;">"GBPJPY"</span>,
<span style="color: #45818e;">"EUR"</span>,
<span style="color: #45818e;">""</span>};
<span style="color: blue;">string</span> parametresCas[NB_CAS_LAST_KNOWN_SEC_NO] = {<span style="color: #45818e;">" sans paramètre => "</span>,
<span style="color: #45818e;">" \"EURUSD\" => "</span>,
<span style="color: #45818e;">" \"GBPJPY\" => "</span>,
<span style="color: #45818e;">" \"EUR\" => "</span>,
<span style="color: #45818e;">" \"\" => "</span>};
<span style="color: blue;">datetime</span> resultatsAttendus[NB_CAS_LAST_KNOWN_SEC_NO];
resultatsAttendus[<span style="color: #38761d;">0</span>] = <span style="color: #674ea7;">TimeCurrent</span>();
resultatsAttendus[<span style="color: #38761d;">1</span>] = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #45818e;">"EURUSD"</span>, <span style="color: #0b5394;">MODE_TIME</span>);
resultatsAttendus[<span style="color: #38761d;">2</span>] = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #45818e;">"GBPJPY"</span>, <span style="color: #0b5394;">MODE_TIME</span>);
resultatsAttendus[<span style="color: #38761d;">3</span>] = <span style="color: #38761d;">0</span>;
resultatsAttendus[<span style="color: #38761d;">4</span>] = <span style="color: #38761d;">0</span>;
<span style="color: blue;">for</span>(noCas=<span style="color: #38761d;">0</span> ; noCas<NB_CAS_LAST_KNOWN_SEC_NO ; noCas++) {
resultat = execObtenirNoDerniereSecConnue(arguments[noCas]);
nbErreurs += analyserResultatDatetimeDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNoDerniereSecConnue,
parametresCas[noCas]);
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> init()
{
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
nbErreurs += testObtenirNoDerniereSecConnue();
<span style="color: #674ea7;">Print</span>(<span style="color: #45818e;">"TESTS DE ArithmetiqueTemporelle.mqh TERMINES AVEC "</span>, nbErreurs, <span style="color: #45818e;">" ERREUR(S)."</span>);
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> deinit()
{
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> start()
{
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span>
</code>
</pre>
<br />
<div style="text-align: justify; text-indent: 3em;">
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-84530049522962422202014-01-27T11:48:00.000+01:002014-01-27T12:32:04.279+01:00Le nombre et le numéro de secondes dans les périodes (bars) avec MQL4<script type="text/javascript">
function checkExercice(exercice, nb_questions) {
var nb_bonnes_reponses = 0;
for(var i=1; i<=nb_questions; i++) {
var reponse = document.getElementById(exercice+"Q"+i);
if(reponse.value === 'V') {
nb_bonnes_reponses++;
}
}
if(nb_bonnes_reponses > 1) {
alert("il y a "+nb_bonnes_reponses+" bonnes réponses sur "+nb_questions+" !");
} else {
alert("il y a "+nb_bonnes_reponses+" bonne réponse sur "+nb_questions+" !");
}
}
</script>
<br />
<div style="text-align: justify; text-indent: 3em;">
Nous allons utiliser les techniques arithmétiques de code vues dans la première partie de ce sujet pour réaliser des fonctions supplémentaires de calculs temporels, à placer dans le fichier include d'arithmétique temporelle que nous avons créé. Ces fonctions seront très simple pour les premières.</div>
<br />
<h3 style="text-decoration: underline;">
La fonction Period():
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
On commence par utiliser une fonction prédéfinie par Metatrader qui donne une caractéristique de la période courante: le nombre de minutes qu'elle contient. La période courante étant celle sur laquelle on a lancé le programme (expert advisor ou indicateur). Cette fonction est <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">Period</span>() </code>. Si elle nous donne le nombre 5, c'est que nous sommes sur une période de 5 minutes ! c'est aussi simple que cela. Nous allons l'utiliser pour obtenir une information qui en découle comme le nombre de secondes de la période.
</div>
<br />
<h3 style="text-decoration: underline;">
Le nombre de secondes dans la période courante:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Une fonction très simple à faire: calculer le nombre de secondes en ayant le nombre de minutes ! Tout ça pour la période utilisée dans le graphique sur lequel le programme a été lancé. Je suis sûr que vous avez déjà trouvé comment faire. La fonction <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">Period</span>() </code> nous donne les minutes et je vous donne le code de la fonction très minimaliste:
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">int</span> obtenirNbSecsDsPeriodeCourante() {
<span style="color: blue;">return</span>(<span style="color: #38761d;">60</span>*<span style="color: #674ea7;">Period</span>());
}
</code>
</pre>
</div>
<br />
<h3 style="text-decoration: underline;">
Le nombre de secondes dans une période quelconque:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Sur le même modèle, on calcule le nombre de secondes d'une période en recevant en argument le nombre de minutes dans la période. Le code complet et minimaliste également de la fonction:
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">int</span> obtenirNbSecsDsPeriode(<span style="color: blue;">int</span> nbMinsDansPeriode) {
<span style="color: blue;">return</span>(<span style="color: #38761d;">60</span>*nbMinsDansPeriode);
}
</code>
</pre>
Mais plutôt que de faire deux fonctions pour la même chose, on va en faire une synthèse. Je m'explique: on ne va pas créer la première mais modifier celle-ci pour qu'elle prenne en compte le cas particulier de la première. L'argument aura une valeur par défaut: <code style="background-color: white; color: #0b5394; font-weight: bold;"> EMPTY </code> comme ça lorsque dans le corps de la fonction la variable est vide, on lui met alors la valeur utilisée dans la première fonction issue de <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">Period</span>() </code>. Ainsi nous n'avons pas besoin de préciser le nombre de secondes dans une période si on veut la période courante. Voici le code:
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">int</span> obtenirNbSecsDsPeriode(<span style="color: blue;">int</span> nbMinsDansPeriode=<span style="color: #0b5394;">EMPTY</span>) {
<span style="color: blue;">int</span> nbSecsDsPeriode;
<span style="color: blue;">if</span>(nbMinsDansPeriode == <span style="color: #0b5394;">EMPTY</span>) { nbMinsDansPeriode = <span style="color: #674ea7;">Period</span>(); }
nbSecsDsPeriode = <span style="color: #38761d;">60</span> * nbMinsDansPeriode;
<span style="color: blue;">return</span>(nbSecsDsPeriode);
}
</code>
</pre>
</div>
<br />
<h3 style="text-decoration: underline;">
Le numéro d'une seconde dans une période:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
On va maintenant faire un calcul un peu différent, puisqu'on veut non pas un numéro depuis l'epoch (1<sup>er</sup> janvier 1970 à 00:00:00) mais le numéro d'une seconde depuis le début de la période. Par exemple, si les périodes sont des M1, c'est-à-dire de 1 min = 60 sec, et que la seconde porte l'horodatage 132 (je sais c'est très vieux!) alors on en déduit que de 0 à 59, c'est la période n°0, de 60 à 119 c'est la période n°1, et que 132 est dans la période n°2. C'est la seconde n°132-120=n°12 de la période n°2. Il faut donc retirer de l'horodatage toutes les périodes entières qu'il contient et prendre le reste. Cette opération porte un nom en arithmétique: modulo. L'opérateur modulo (souvent représenté avec le signe pourcent: %) indique de faire la division euclidienne (entière) et de prendre le reste. En résumé: 132%60=12 ou encore 12%5=2. Mentalement il faut faire comme on vient de voir, retirer le diviseur autant de fois que possible et voir ce qui reste. 12=10+2=5x2+2, donc 12%5=2. Je vous propose une série d'exercices pour vous exercer si vous en avez besoin:<br />
<br />
<form id="modulo">
<fieldset style="text-align: right;">
<legend style="text-align: left;">Exercices sur l'opérateur modulo</legend>
<br />
Soit l'opération 24%5 (prononcez «vingt-quatre modulo cinq»)<br />
Combien de 5 peut-on retirer de 24:
<select id="moduloQ1">
<option value="F">--choisir--</option>
<option value="F">3</option>
<option value="V">4</option>
<option value="F">5</option>
</select>
<br />
La décomposition de 24 à choisir est:
<select id="moduloQ2">
<option value="F">--choisir--</option>
<option value="F">3x5+9</option>
<option value="V">4x5+4</option>
<option value="F">5x5-1</option>
</select>
<br />
24%5 est égal à:
<select id="moduloQ3">
<option value="F">--choisir--</option>
<option value="F">9</option>
<option value="F">3</option>
<option value="V">4</option>
</select>
<br />
Pour 24%11 la décomposition est:
<select id="moduloQ4">
<option value="F">--choisir--</option>
<option value="V">2x11+2</option>
<option value="F">2x10+4</option>
<option value="F">3x7+3</option>
</select>
<br />
Pour 8%3 la décomposition est:
<select id="moduloQ5">
<option value="F">--choisir--</option>
<option value="F">3x3-1</option>
<option value="F">2x4+0</option>
<option value="V">2x3+2</option>
</select>
<br />
8%3 est égal à:
<select id="moduloQ6">
<option value="F">--choisir--</option>
<option value="F">1</option>
<option value="V">2</option>
<option value="F">3</option>
</select>
<br />
Pour 9%3 la décomposition est:
<select id="moduloQ7">
<option value="F">--choisir--</option>
<option value="V">3x3+0</option>
<option value="F">2x4+1</option>
<option value="F">2x3+3</option>
</select>
<br />
9%3 est égal à:
<select id="moduloQ8">
<option value="F">--choisir--</option>
<option value="F">2</option>
<option value="F">1</option>
<option value="V">0</option>
</select>
<br />
<button onclick="checkExercice('modulo',8);" type="button">Vérifier</button>
</fieldset>
</form>
<br />
Il faut retenir qu'il y a un nombre limité de restes possibles, par exemple: un nombre modulo 5, ne peut avoir que 5 résultats possibles qui sont 0, 1, 2, 3 et 4. On ne peut évidemment pas avoir 5 ou plus car on pourrait y retirer encore le diviseur qui est 5. Quand un nombre augmente, le résultat de son modulo est cyclique:<br />
<ul>
<li>0%3=0</li>
<li>1%3=1</li>
<li>2%3=2</li>
<li>3%3=0</li>
<li>4%3=1</li>
<li>5%3=2</li>
<li>6%3=0</li>
<li>7%3=1</li>
<li>etc. </li>
</ul>
<br />
Nous allons donc utiliser l'opérateur modulo pour extraire le numéro d'une seconde dans la période à laquelle il appartient à partir de son horodatage. Notre fonction va donc recevoir en argument un horodatage et le nombre de secondes dans la période. Nous mettrons ce deuxième argument avec une valeur par défaut <code style="background-color: white; color: #0b5394; font-weight: bold;"> EMPTY </code> comme ça lorsque nous le préciserons pas, il s'agira du nombre de secondes dans la période courante. Et lorsque le deuxième argument sera vide il faudra y mettre la valeur qu'on fera calculer par la fonction que nous avons créée précédemment, sans argument évidemment comme ça nous l'aurons pour la période courante:
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">int</span> obtenirNoSecDsPeriode(<span style="color: blue;">datetime</span> horodatageSec, <span style="color: blue;">int</span> nbSecsDansPeriode=<span style="color: #0b5394;">EMPTY</span>) {
<span style="color: blue;">int</span> noSecDansPeriode;
<span style="color: blue;">if</span>(nbSecsDansPeriode == <span style="color: #0b5394;">EMPTY</span>) { nbSecsDansPeriode = obtenirNbSecsDsPeriode(); }
noSecDansPeriode = horodatageSec % nbSecsDansPeriode;
<span style="color: blue;">return</span>(noSecDansPeriode);
}
</code>
</pre>
</div>
<br />
<h3 style="text-decoration: underline;">
Le tutoriel vidéo et le code du fichier include augmenté:
</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="https://ytimg.googleusercontent.com/vi/_nEKOuP2VDs/0.jpg" height="480" width="640"><param name="movie" value="https://youtube.googleapis.com/v/_nEKOuP2VDs&source=uds" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="640" height="480" src="https://youtube.googleapis.com/v/_nEKOuP2VDs&source=uds" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| ArithmetiqueTemporelle.mqh |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2014, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| DLL imports |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| EX4 imports |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| includes |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| variables globales |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| constantes globales |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| fonctions comptage |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">datetime</span> obtenirNoDerniereSecConnue(<span style="color: blue;">string</span> paire=<span style="color: #45818e;">"NULL"</span>) {
<span style="color: blue;">datetime</span> horodatage;
<span style="color: blue;">if</span>(paire==<span style="color: #45818e;">"NULL"</span>) { horodatage = <span style="color: #674ea7;">TimeCurrent</span>(); }
<span style="color: blue;">else</span> { horodatage = <span style="color: #674ea7;">MarketInfo</span>(paire, <span style="color: #0b5394;">MODE_TIME</span>); }
<span style="color: blue;">return</span>(horodatage);
}
<span style="color: blue;">int</span> obtenirNbSecsDsPeriode(<span style="color: blue;">int</span> nbMinsDansPeriode=<span style="color: #0b5394;">EMPTY</span>) {
<span style="color: blue;">int</span> nbSecsDsPeriode;
<span style="color: blue;">if</span>(nbMinsDansPeriode == <span style="color: #0b5394;">EMPTY</span>) { nbMinsDansPeriode = <span style="color: #674ea7;">Period</span>(); }
nbSecsDsPeriode = <span style="color: #38761d;">60</span> * nbMinsDansPeriode;
<span style="color: blue;">return</span>(nbSecsDsPeriode);
}
<span style="color: blue;">int</span> obtenirNoSecDsPeriode(<span style="color: blue;">datetime</span> horodatageSec, <span style="color: blue;">int</span> nbSecsDansPeriode=<span style="color: #0b5394;">EMPTY</span>) {
<span style="color: blue;">int</span> noSecDansPeriode;
<span style="color: blue;">if</span>(nbSecsDansPeriode == <span style="color: #0b5394;">EMPTY</span>) { nbSecsDansPeriode = obtenirNbSecsDsPeriode(); }
noSecDansPeriode = horodatageSec % nbSecsDansPeriode;
<span style="color: blue;">return</span>(noSecDansPeriode);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span>
</code>
</pre>
<br />
<div style="text-align: justify; text-indent: 3em;">
Dans le prochain post nous ferons sans attendre un code de test pour ces deux fonctions, à ajouter à celui déjà existant. Il est impératif de le faire le plus tôt possible, car nous ne voyons pas le code fonctionner pour l'instant, et il ne s'agit pas de modifier ces fonctions quand nous voudrons les inclure dans un gros projet. Ou même d'avoir un bug dans un gros projet à cause de petites fonctions de base, on perdrait ainsi un temps précieux à chercher l'origine du problème et de la motivation au passage.
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-77889237267867373842014-01-24T12:52:00.000+01:002014-01-30T21:06:18.113+01:00Factorisation du code de test avec un fichier include pour les tests<div style="text-align: justify; text-indent: 3em;">
Le code précédent pour tester notre fonction, est tout à fait du «bad code». Il faut impérativement corriger cela, car il ne sert à rien d'essayer de faire du code utile propre et laisser un code de tests dégueulasse. Cela induirait les mêmes effets que si le code utile était mauvais.
</div>
<br />
<h3 style="text-decoration: underline;">
Factorisation de l'analyse du résultat du cas:</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Je vous propose donc de créer une fonction d'analyse du résultat du test de cas qui sera appelée plusieurs fois pour tester une fonction. Le problème est que nous ne pouvons pas mettre le test de la fonction proprement dit à l'intérieur car avec le langage MQL4 on ne peut pas passer de fonction en paramètre. On est donc obligé de tester le cas puis d'appeler cette fonction d'analyse qui comparera les résultats et fera les affichages et retournera une valeur booléenne pour dire si c'est ok ou bien s'il y a une erreur. Non on va plutôt retourner un entier qui est le nombre d'erreur (0 ou 1) comme ça on pourra l'additionner directement au total des erreurs lors de l'appel de la fonction d'analyse, ça fera un code plus concis. Cette fonction d'analyse du résultat du cas sera placée dans un include, car elle ne sera pas la seule sans doute (pour le moment oui) et qu'elle sera utilisée dans de nombreux experts advisors de tests de code. Cette fonction doit donc recevoir en arguments: le résultat du test, la valeur attendue, le nom de la fonction, le texte représentant les paramètres du cas, le message de succès avec une valeur par défaut et le message d'erreur avec une valeur par défaut. Ça fait beaucoup trop de paramètres, et donc pas «clean code» du tout. Mais hélas, trois fois hélas, avec le MQL4, on est obligé de faire des entorses aux règles du code propre et des compromis. C'est ça ou bien un code très long et très redondant. Autre détail facheux: le type du résultat va varier d'une fonction à tester à l'autre. Or on doit passer ce résultat à la fonction d'analyse, et préciser un type, et il n'y a pas de type général en MQL4 et on ne peut pas se servir du type void pour dire qu'on ne connait pas le type à la compilation et ainsi pouvoir recevoir n'importe quel type de données comme dans le langage C. Ça ne fonctionne pas ! Le compilateur réclame un type précis. Nous allons donc créer une fonction d'analyse par type de valeur de retour, et par «chance» avec MQL4, ça sera en nombre limité. Nous ferons les autres fonctions quand nous en aurons besoin. Je place l'argument du message d'erreur avant celui du succès car le message d'erreur est plus susceptible d'être spécifié que le message de succès, puisqu'il faut placer les valeurs par défaut et non précisées lors de l'appel en dernier. Voici le code complet du fichier include en première version:<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| UtilitairesTests.mqh |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2014, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| constantes de tests |
//+------------------------------------------------------------------+</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| fonctions |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> analyserResultatDatetimeDuTest(
<span style="color: blue;">datetime</span> resultatTest,
<span style="color: blue;">datetime</span> resultatAttendu,
<span style="color: blue;">string</span> nomFonction,
<span style="color: blue;">string</span> parametresCas,
<span style="color: blue;">string</span> msgErreur = <span style="color: #45818e;">" a produit une erreur de résultat avec le cas "</span>,
<span style="color: blue;">string</span> msgSucces = <span style="color: #45818e;">" a passé le test sans erreurs "</span>) {
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">if</span>(resultatTest == resultatAttendu) {
<span style="color: #674ea7;">Print</span>(nomFonction, msgSucces, resultatTest);
} <span style="color: blue;">else</span> {
<span style="color: #674ea7;">Print</span>(nomFonction, msgErreur, parametresCas, resultatTest);
nbErreurs++;
}
<span style="color: blue;">return</span>(nbErreurs);
}
</code>
</pre>
</div>
<br />
<h3 style="text-decoration: underline;">
Factorisation des tests des cas:</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Nous avons donc maintenant deux lignes par test de cas au lieu de 7: un appel de la fonction à tester avec récupération du résultat et un appel de la fonction qu'on vient de créer pour analyser avec une addition au total des erreurs en même temps. Ces deux étapes sont à faire pour chaque cas. Nous aurons encore du code redondant: ces deux lignes à répéter pour chaque cas. On va factoriser tout ça avec une boucle for, mais dans ce cas il va falloir mettre les données des différents cas dans des tableaux, qu'on mettra en constantes locales à la fonction de test. Nous aurons besoin d'une variable entière noCas (int) pour parcourir la boucle, du nombre d'erreurs (int) comme précédemment, d'une variable résultat (datetime), d'un tableau de string des arguments, un autre tableau de string des paramètres des cas et un tableau de datetime des resultats attendus. Nous pouvons remplir ces tableaux de deux manières:<br />
<ol style="text-indent: 0;">
<li>à la déclaration, avec un égal et la liste des valeurs littérales (nombres et textes dans le code) séparées par des virgules, entre accolades.</li>
<li>en affectant une valeur case par case après la déclaration, et nous y serons obligés bien que ce soit moins pratique pour les valeurs issues de fonctions sur le moment de l'affectation.</li>
</ol>
Il faut également factoriser ce nombre de cas qui est répété plusieurs fois: dans la déclaration des tableaux et dans la condition de limite de la boucle. Mais lors de déclaration des tableaux on ne peut pas indiquer la taille avec une variable, ni même une constante (c'est la même chose). Par contre il y a un autre moyen qui est d'utiliser les directives <span style="color: blue;">#define</span> qui nous permettent de définir des constantes pour le préprocesseur. Celui-ci va remplacer toutes les constantes qu'on lui aura définit par leur valeur associée avant la compilation. Le compilateur ne verra dans le code que le nombre 5 que le préprocesseur aura mis. Pour ne pas faire de noms de constantes <span style="color: blue;">#define</span> trop longs je vais donner parfois des noms en anglais quand ils sont plus courts. Voici le tutoriel vidéo et le nouveau code de l'expert advisor de test de l'include ArithmetiqueTemporelle.mqh (certaines lignes entières dans le fichier ont été tronquées pour tenir dans le post, celles qui ont des colonnades de trop nombreux arguments pas «clean code» du tout ! Ahhh ... le MQL4 !):
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='640' height='480' src='https://www.youtube.com/embed/4B6o9m3bm3M?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| testsArithmetiqueTemporelle.mqh |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2014, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: blue;">#include</span> <UtilitairesTests.mqh>
<span style="color: blue;">#include</span> <ArithmetiqueTemporelle.mqh>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#define</span> NB_CAS_LAST_KNOWN_SEC_NO <span style="color: #38761d;">5</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| constantes de tests |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">string</span> nomObtenirNoDerniereSecConnue = <span style="color: #45818e;">"obtenirNoDerniereSecConnue()"</span>;
<span style="color: #999999;">//+------------------------------------------------------------------+
//| fonctions de tests |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> testObtenirNoDerniereSecConnue() {
<span style="color: blue;">int</span> noCas, nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">datetime</span> resultat;
<span style="color: blue;">string</span> arguments[NB_CAS_LAST_KNOWN_SEC_NO] = {<span style="color: #45818e;">"NULL"</span>,
<span style="color: #45818e;">"EURUSD"</span>,
<span style="color: #45818e;">"GBPJPY"</span>,
<span style="color: #45818e;">"EUR"</span>,
<span style="color: #45818e;">""</span>};
<span style="color: blue;">string</span> parametresCas[NB_CAS_LAST_KNOWN_SEC_NO] = {<span style="color: #45818e;">" sans paramètre => "</span>,
<span style="color: #45818e;">" \"EURUSD\" => "</span>,
<span style="color: #45818e;">" \"GBPJPY\" => "</span>,
<span style="color: #45818e;">" \"EUR\" => "</span>,
<span style="color: #45818e;">" \"\" => "</span>};
<span style="color: blue;">datetime</span> resultatsAttendus[NB_CAS_LAST_KNOWN_SEC_NO];
resultatsAttendus[<span style="color: #38761d;">0</span>] = <span style="color: #674ea7;">TimeCurrent</span>();
resultatsAttendus[<span style="color: #38761d;">1</span>] = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #45818e;">"EURUSD"</span>, <span style="color: #0b5394;">MODE_TIME</span>);
resultatsAttendus[<span style="color: #38761d;">2</span>] = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #45818e;">"GBPJPY"</span>, <span style="color: #0b5394;">MODE_TIME</span>);
resultatsAttendus[<span style="color: #38761d;">3</span>] = <span style="color: #38761d;">0</span>;
resultatsAttendus[<span style="color: #38761d;">4</span>] = <span style="color: #38761d;">0</span>;
<span style="color: blue;">for</span>(noCas=<span style="color: #38761d;">0</span> ; noCas<NB_CAS_LAST_KNOWN_SEC_NO ; noCas++) {
resultat = obtenirNoDerniereSecConnue(arguments[noCas]);
nbErreurs += analyserResultatDatetimeDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNoDerniereSecConnue,
parametresCas[noCas]);
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> init()
{
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
nbErreurs += testObtenirNoDerniereSecConnue();
<span style="color: #674ea7;">Print</span>(<span style="color: #45818e;">"TESTS DE ArithmetiqueTemporelle.mqh TERMINES AVEC "</span>, nbErreurs, <span style="color: #45818e;">" ERREUR(S)."</span>);
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> deinit()
{
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> start()
{
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span></code></pre>
<br />
<div style="text-align: justify; text-indent: 3em;">
PS: La fonction testée, a un paramètre optionnel, donc avec une valeur par défaut. J'avais commencé par mettre la constante NULL à cette valeur, comme dans le langage C, mais le compilateur MQL4 ne l'accepte pas et j'ai donc mis la chaine de caractères "NULL". Le MQL4 a une constante pour les paramètres vides, c'est la constante EMPTY, et NULL ne concerne que les variables string vides (différent de chaine vide: ""). Mais j'ai laissé la chaine "NULL" car je peux la mettre dans le tableau des arguments et la passer pour le premier cas bien que ce soit un cas sans argument. Cet argument passé est celui par défaut. Ça n'aurait pas pu être le cas avec EMPTY, puisque que le compilateur ne l'accepte pas en tant que valeur dans le tableau.<br />
Je ne peux pas améliorer encore plus le code, je n'ai pas trouvé comment faire pour l'instant, car dans l'idéal il faudrait sortir les déclarations des valeurs des tests et en plus certaines d'entre elles doivent être affectées au moment de l'exécution de la fonction de test (les appels aux fonctions prédéfinies). Nous sommes un peu limités par le langage MQL4. Le code actuel est tout de même bien meilleur que le précédent, y a pas photo ! =D </div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-28609026694157969232014-01-23T12:10:00.000+01:002014-01-30T21:06:47.363+01:00Un fichier de tests pour l'include d'arithmétique temporelle<div style="text-align: justify; text-indent: 3em;">
<br />
La programmation est très rigoureuse, et nous humains, nous le somme beaucoup moins. Il est difficile de penser à tout, et nous oublions de nombreuses choses. Surtout nous ne pouvons pas tout connaitre et c'est l'expérience qui nous fait apprendre de nouvelles choses. C'est pour cela qu'on ne peut pas espérer coder ne serait-ce qu'un petit programme sans aucun bug voire défaut de conception algorithmique. Dès qu'on fait du code, il faut s'attendre à ce que ça ne fonctionne pas, et qu'il faille tester pour trouver les problèmes de conception et bugs cachés. Depuis les années 90, le monde du développement informatique applique ce qu'on appelle le Test Driven Developpment: le développement conduit par les tests. Nous n'appliquerons pas à la lettre les recommandations qui disent par exemple de commencer à coder le programme de test avant même le code qu'il est sensé tester. Et nous avons tord, mais pour des raisons pédagogiques, je ne commence pas par faire les tests, ni ne fait des tests absolument pour tout. Pour les petits experts advisors ou indicateurs de démonstration le simple fait de les voir fonctionner de suite après nous confirme si la fonction principale est assurée sur le moment (on en sait rien dans le temps, ni des bugs cachés). Donc pour eux, pas de tests rigoureux. En général le test minimal est le test dit unitaire. Il consiste à juste tester que le code fonctionne dans un cas banal. Il n'y a pas de tests étendus, de torture avec un fonctionnement marathon ou avec le test du débile où des données farfelues sont fournies au code pour voir s'il réagit bien. Pas de tests avec tous les différents cas possibles, etc. Dans notre cas nous allons faire un peu plus que le test unitaire sans pour autant tester tous les cas. La stabilité dans le temps pourra être testé avec le testeur de stratégies de metaTrader, mais ça ne concerne que les indicateurs et experts advisors. Une librairie de fonction doit juste donner des résultats de traitement cohérents. Nous testerons donc plusieurs cas, et, plus nous en mettrons des différents, plus nous seront sûr de la qualité du code et de l'algorithme.
</div>
<br />
<h3 style="text-decoration: underline;">
Tester la fonction obtenirNoDerniereSecConnue():
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Nous allons tester cette fonction en l'appelant en lui passant ou non un paramètre, et même différents paramètres. Sans paramètre pour tester si la valeur par défaut est bien gérée, puis avec différents textes pour tester différents cas, et même des cas ou le texte n'est pas valide. Dans ce dernier cas, nous supposons déjà que la fonction va planter et nous verrons comment l'erreur est gérée par Metatrader. Puis nous modifierons la fonction pour qu'elle gère elle-même les erreurs qui peuvent survenir. Il faut le faire car si un bug est caché dans un indicateur ou expert advisor, et qu'il provoque le fait qu'un paramètre non valide est fourni à cette fonction, il faut pouvoir réagir en conséquence et ne pas faire perdre du capital par des erreurs en cascade:<br />
<ul style="text-indent: 0;">
<li>Un cas sans paramètre et on doit obtenir la même chose que ce que fournit TimeCurrent().</li>
<li>Avec <code style="background-color: white; color: #45818e; font-weight: bold;">"EURUSD"</code> et obtenir la même chose que ce que nous fournit <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">MarketInfo</span>() </code>.</li>
<li>Avec <code style="background-color: white; color: #45818e; font-weight: bold;">"GBPJPY"</code> et obtenir la même chose que ce que nous fournit <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #674ea7;">MarketInfo</span>() </code>.</li>
<li>Avec une chaîne vide <code style="background-color: white; color: #45818e; font-weight: bold;">""</code> et voir la gestion de l'erreur par MetaTrader4 pour commencer puis obtenir le résultat par défaut lors d'une erreur que nous aurons décidé.</li>
<li>Avec <code style="background-color: white; color: #45818e; font-weight: bold;">"EUR"</code> et obtenir le résultat par défaut pour une erreur.</li>
</ul>
Comme nous allons faire les tests dans un expert advisor, qui aura pour but de tester toutes les fonctions de ce fichier include, nous allons mettre tous ces cas de test dans une fonction nommée pour l'occasion TestObtenirNoDerniereSecConnue() (ouf ! 30 caractères, ça a faillit dépasser 31 caractères). Et à l'intérieur nous allons y tester les différents cas et comptabiliser les échecs aux tests. En cas d'échec on affiche un message avec les valeurs et en cas de succès aussi. Pour chaque cas on va:<br />
<ul style="text-indent: 0;">
<li>obtenir le résultat du cas</li>
<li>tester si le résultat est égal à la valeur attendue</li>
<li>si oui, afficher que c'est ok et le résultat</li>
<li>si non afficher qu'il y a eu une erreur et le résultat, et augmenter le nombre d'erreurs de 1.</li>
</ul>
le code pour tester chaque cas sera donc:<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
resultat = obtenirNoDerniereSecConnue(<span style="color: #999999;">//paramètre</span>);
<span style="color: blue;">if</span>(resultat == <span style="color: #999999;">//resultat attendu</span>) {
<span style="color: #674ea7;">Print</span>(<span style="color: #999999;">//nom de la fonction</span>, <span style="color: #999999;">//message ok</span>, resultat);
} <span style="color: blue;">else</span> {
nbErreurs++;
<span style="color: #674ea7;">Print</span>(<span style="color: #999999;">//nom de la fonction</span>, <span style="color: #999999;">//message erreur</span>, <span style="color: #999999;">//paramètre fourni</span>, resultat);
}
</code>
</pre>
Et il faut répéter ce code avec les bonnes valeurs pour chaque cas de test, ce qui n'est pas très "clean code". J'ai réfléchi pour factoriser ce code, mais cela rallonge énormément la liste des déclarations de constantes et au final le code est très long. je ferai un post plus tard pour essayer de factoriser ces cas de tests, mais ce n'est pas facile d'obtenir quelque chose de convenable avec un langage comme MQL4. Pour l'instant on se contente de ce code linéaire et redondant qui malgré tout fonctionne.
</div>
<br />
<h3 style="text-decoration: underline;">
Les résultats du test de la fonction obtenirNoDerniereSecConnue():
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
J'ai écrit le code et testé la fonction, et je constate que MetaTrader4 ne m'indique aucune erreur et que les quatre tests sont effectués, dont les deux derniers en erreur signalée. Ce qui signifie une chose: la fonction <code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">MarketInfo</span>()</code> réagit bien aux paramètres erronés. Elle les accepte et retourne quand même un résultat qui est zéro. J'avais l'intention de modifier le code pour qu'il réagisse à une erreur retournée par la fonction <code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">MarketInfo</span>()</code> et de renvoyer la valeur 0 car jamais utilisée en tant qu'horodatage ce qui aurait signifié au code appelant qu'il y a eu une erreur, mais <code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">MarketInfo</span>()</code> retourne déjà zéro ! C'est parfait ! On a donc déjà zéro dans la variable horodatage et c'est donc la valeur qui sera retournée. Nous n'avons pas besoin de modifier le code. Nous modifions juste les valeurs de résultat attendu qui doivent être zéro dans les cas où le paramètre fourni est mauvais.
</div>
<br />
<h3 style="text-decoration: underline;">
Le tutoriel vidéo et le code complet:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Le code sera donc placé dans un expert advisor, on doit évidemment inclure le fichier ArithmétiqueTemporelle avec la directive préprocesseur #include suivie du nom du fichier entre deux chevrons ouvrant et fermant: <code style="background-color: white; color: black; font-weight: bold;"><span style="color: blue;">#include</span> <ArithmetiqueTemporelle.mqh></code> au début du fichier après le copyright. Nous créons alors une fonction testObtenirNoDerniereSecConnue() qui contient les tests de tous les cas et qui retourne le nombre d'erreur. Puis dans la fonction init(), on fait exécuter toutes les fonctions de tests (pour l'instant une seule) en récupérant le nombre d'erreurs à chaque fois et en les accumulant. A la fin de la fonction init() on affiche le bilan du test de l'include entier.<br />
<br />
Voici le tutoriel vidéo:
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='640' height='480' src='https://www.youtube.com/embed/c4dJ-AMlTTM?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<div style="text-align: justify; text-indent: 3em;">
Et le code complet:<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| testsArithmetiqueTemporelle.mq4 |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2014, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: blue;">#include</span> <ArithmetiqueTemporelle.mqh>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| constantes de tests |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">string</span> msgTestOk = <span style="color: #45818e;">" a passé le test sans erreurs. Valeur retournée: "</span>;
<span style="color: blue;">string</span> msgErreurTest = <span style="color: #45818e;">" a produit une erreur de résultat avec le cas "</span>;
<span style="color: blue;">string</span> nomObtenirNoDerniereSecConnue = <span style="color: #45818e;">"obtenirNoDerniereSecConnue()"</span>;
<span style="color: #999999;">//+------------------------------------------------------------------+
//| fonctions de tests |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> testObtenirNoDerniereSecConnue() {
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
<span style="color: blue;">datetime</span> resultat;
resultat = obtenirNoDerniereSecConnue();
<span style="color: blue;">if</span>(resultat == <span style="color: #674ea7;">TimeCurrent</span>()) {
<span style="color: #674ea7;">Print</span>(nomObtenirNoDerniereSecConnue, msgTestOk, resultat);
} <span style="color: blue;">else</span> {
nbErreurs++;
<span style="color: #674ea7;">Print</span>(nomObtenirNoDerniereSecConnue, msgTestOk, <span style="color: #45818e;">" sans paramètre => "</span>, resultat);
}
resultat = obtenirNoDerniereSecConnue(<span style="color: #45818e;">"EURUSD"</span>);
<span style="color: blue;">if</span>(resultat == <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #45818e;">"EURUSD"</span>, <span style="color: #0b5394;">MODE_TIME</span>)) {
<span style="color: #674ea7;">Print</span>(nomObtenirNoDerniereSecConnue, msgTestOk, resultat);
} <span style="color: blue;">else</span> {
nbErreurs++;
<span style="color: #674ea7;">Print</span>(nomObtenirNoDerniereSecConnue, msgTestOk, <span style="color: #45818e;">"\"EURUSD\" => "</span>, resultat);
}
resultat = obtenirNoDerniereSecConnue(<span style="color: #45818e;">"GBPJPY"</span>);
<span style="color: blue;">if</span>(resultat == <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #45818e;">"GBPJPY"</span>, <span style="color: #0b5394;">MODE_TIME</span>)) {
<span style="color: #674ea7;">Print</span>(nomObtenirNoDerniereSecConnue, msgTestOk, resultat);
} <span style="color: blue;">else</span> {
nbErreurs++;
<span style="color: #674ea7;">Print</span>(nomObtenirNoDerniereSecConnue, msgTestOk, <span style="color: #45818e;">"\"GBPJPY\" => "</span>, resultat);
}
resultat = obtenirNoDerniereSecConnue(<span style="color: #45818e;">"EUR"</span>);
<span style="color: blue;">if</span>(resultat == <span style="color: #38761d;">0</span>) {
<span style="color: #674ea7;">Print</span>(nomObtenirNoDerniereSecConnue, msgTestOk, resultat);
} <span style="color: blue;">else</span> {
nbErreurs++;
<span style="color: #674ea7;">Print</span>(nomObtenirNoDerniereSecConnue, msgTestOk, <span style="color: #45818e;">"\"EUR\" => "</span>, resultat);
}
resultat = obtenirNoDerniereSecConnue(<span style="color: #45818e;">""</span>);
<span style="color: blue;">if</span>(resultat == <span style="color: #38761d;">0</span>) {
<span style="color: #674ea7;">Print</span>(nomObtenirNoDerniereSecConnue, msgTestOk, resultat);
} <span style="color: blue;">else</span> {
nbErreurs++;
<span style="color: #674ea7;">Print</span>(nomObtenirNoDerniereSecConnue, msgTestOk, <span style="color: #45818e;">"\"\" => "</span>, resultat);
}
<span style="color: blue;">return</span>(nbErreurs);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> init()
{
<span style="color: blue;">int</span> nbErreurs = <span style="color: #38761d;">0</span>;
nbErreurs += testObtenirNoDerniereSecConnue();
<span style="color: #674ea7;">Print</span>(<span style="color: #45818e;">"TESTS DE ArithmetiqueTemporelle.mqh TERMINES AVEC "</span>, nbErreurs, <span style="color: #45818e;">" ERREUR(S)."</span>);
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> deinit()
{
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> start()
{
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span></code></pre>
<br />
Je ne peux définitivement pas laisser un tel code, redondant à ce point ! On est loin du «clean code», c'est même du «bad code». Surtout qu'on va ajouter d'autres fonctions dans l'include d'arithmétique temporelle, et donc multiplier ce code de test. Il est important, très important de maintenir un code de test clean, tout comme le code utile. Je m'y attèle dès le prochain post, nous factoriserons ce code. Pour l'instant l'objectif est rempli: notre première fonction de l'include est testée et on sait qu'on peut avoir confiance en elle. Nous n'avons pas pourtant de garantie à 100%, on va dire que nous sommes à 99%. Mais sans ces tests, c'était du 1%. (la première version de la fonction avait échouée non pas aux tests, mais carrément à la compilation ! =D)</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-4105192961305423612014-01-21T11:44:00.000+01:002014-01-24T08:28:46.969+01:00un fichier include d'arithmétique temporelle et horodatages<div style="text-align: justify; text-indent: 3em;">
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 <span style="color: blue;">datetime</span>.
</div>
<br />
<h3 style="text-decoration: underline;">
Les fichiers include .mqh:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
On les nomme ainsi car on fait appel à la directive du préprocesseur <span style="color: blue;">#include</span> 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 <span style="color: blue;">#import</span> 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 <span style="color: blue;">#import</span> 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 "<a href="http://www.amazon.fr/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882">clean code</a>", 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.
</div>
<br />
<h3 style="text-decoration: underline;">
Le préprocesseur:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
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: <code style="font-weight: bold;"><span style="color: blue;">#include</span> <fichier-a-inclure.mqh></code> 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.
</div>
<br />
<h3 style="text-decoration: underline;">
horodatage et MarketInfo():
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
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 1<sup>er</sup> 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
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code><span style="color: #674ea7;">MarketInfo</span>(<span style="color: #674ea7;">Symbol</span>(), <span style="color: #0b5394;">MODE_TIME</span>);
</code></pre>
<br />
Le premier paramètre pourrait tout aussi bien être remplacé par <code style="background-color: white; color: #45818e; font-weight: bold;">"EURUSD"</code> ou <code style="background-color: white; color: #45818e; font-weight: bold;">"GBPJPY"</code> par exemple car <code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">Symbol</span>()</code> 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.
</div>
<br />
<h3 style="text-decoration: underline;">
La fonction TimeCurrent():
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
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 <code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">TimeCurrent</span>()</code>. 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 <code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">Symbol</span>()</code> à 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 <code style="background-color: white; color: #45818e; font-weight: bold;">"NULL"</code> par défaut et si c'est la valeur du paramètre alors on utilise <code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">TimeCurrent</span>()</code> sinon on utilise <code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">MarketInfo</span>()</code> 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 <code style="background-color: white; color: #0b5394; font-weight: bold;">NULL</code> 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 <span style="color: blue;">int</span> et <span style="color: blue;">datetime</span> 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:<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">datetime</span> obtenirNoDerniereSecConnue(<span style="color: blue;">string</span> paire=<span style="color: #45818e;">"NULL"</span>) {
<span style="color: blue;">datetime</span> horodatage;
<span style="color: blue;">if</span>(paire==<span style="color: #45818e;">"NULL"</span>) { horodatage = <span style="color: #674ea7;">TimeCurrent</span>(); }
<span style="color: blue;">else</span> { horodatage = <span style="color: #674ea7;">MarketInfo</span>(paire, <span style="color: #0b5394;">MODE_TIME</span>); }
<span style="color: blue;">return</span>(horodatage);
}
</code>
</pre>
</div>
<h3 style="text-decoration: underline;">
Le tutoriel vidéo et le code du fichier include:
</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='640' height='480' src='https://www.youtube.com/embed/5HbMOzSkt5Q?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: justify; text-indent: 3em;">
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| ArithmetiqueTemporelle.mqh |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2014, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| DLL imports |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| EX4 imports |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| includes |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| variables globales |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| constantes globales |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| fonctions comptage |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">datetime</span> obtenirNoDerniereSecConnue(<span style="color: blue;">string</span> paire=<span style="color: #45818e;">"NULL"</span>) {
<span style="color: blue;">datetime</span> horodatage;
<span style="color: blue;">if</span>(paire==<span style="color: #45818e;">"NULL"</span>) { horodatage = <span style="color: #674ea7;">TimeCurrent</span>(); }
<span style="color: blue;">else</span> { horodatage = <span style="color: #674ea7;">MarketInfo</span>(paire, <span style="color: #0b5394;">MODE_TIME</span>); }
<span style="color: blue;">return</span>(horodatage);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span>
</code>
</pre>
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.<br />
<br />
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. </div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-61552167342071373042014-01-20T13:20:00.000+01:002014-01-20T13:20:01.049+01:00Le type Datetime de MQL4<div style="text-align: justify; text-indent: 3em;">
Chaque langage de programmation a ses types de données, mais rares sont ceux qui ont le temps en type de données. ici le temps est très important, on le manipule tout le temps car nos données sont des valeurs de cours qui ont toutes une position dans le temps. Le type associé à ces positions est le type Datetime.
</div>
<br />
<h3 style="text-decoration: underline;">
Le type Datetime
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
il s'agit en réalité d'un nombre entier codé sur 4 octets, soit environ 4 milliards de valeurs différentes possibles. Ce nombre entier représente le nombre de secondes écoulées depuis le 1<sup>er</sup> janvier 1970. C'est un horodatage du type EPOCH des systèmes d'exploitations UNIX (prononcez "épok", il s'agit de la transcription phonétique anglaise du mot français "époque"). Et actuellement en 2014, nous en sommes à environ 1,3 milliards de secondes écoulées, presque 1,4 milliards. Facile à estimer: 60 sec / min, soit 60 x 60 = 3 600 sec / h, soit 24 x 3 600 = 86 400 sec / jour, soit 86 400 x 365 = 31 536 000 sec / an, soit finalement pour 44 ans du 1<sup>er</sup> janvier 1970 au 1<sup>er</sup> janvier 2014: 31 536 000 x 44 = 1 387 584 000 secondes. On le déclare en MQL4 avec le mot-clé <b><span style="color: blue;">datetime</span>.</b></div>
<br />
<h3 style="text-decoration: underline;">
Les constantes littérales Datetime
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Mais ! C'est pas du tout pratique à manipuler, surtout si on veut créer une date précise ! Rassurez-vous, vous n'avez aucune conversion à faire, donc rien à calculer dans ce genre-là, et pour deux raisons:<br />
<ol style="text-indent: 0;">
<li>La plupart du temps vous n'avez pas de date à créer, vous utilisez les dates fournies par MetaTrader déjà sous forme de nombre entier à environ 1,4 milliard.</li>
<li>Au cas où vous avez besoin de créer une date précise, vous utiliser une forme littérale dans laquelle vous exprimez la date sous forme courante et MetaTrader fait lui-même les conversions. C'est ce qu'on va voir de suite.</li>
</ol>
</div>
<div style="text-align: justify; text-indent: 3em;">
Pour écrire une date que vous décidez, il faut écrire du texte entre guillemets simples (obligatoirement, pas de doubles !) avec un D majuscule accolé devant. Et cette date est simplement écrite de façon lisible comme l'afficherait une horloge digitale. Attention les dates sont écrite dans l'ordre du poids le plus fort d'abord (année, mois puis jour). Si la fin de l'heure ou toute l'heure est omise, la fin ou toute l'heure est considérée comme égale à zéro, et si la date est omise, elle est considérée comme celle du jour de compilation (quand vous cliquez sur le bouton Compiler). Exemples:<br />
<ul style="text-indent: 0;">
<li> D'2014.01.17 13:29:47' pour le 17 janvier 2014 à 13h29min47sec.</li>
<li>D'1980.05.14 03:54' pour le 14 mai 1980 à 3h du matin 54 min et 0 seconde.</li>
<li>D'2000.02.01 08' pour le 1<sup>er</sup> février 2000 à 8 heures 0 min et 0 secondes.</li>
<li>D'2010.07.14' pour le 14 juillet 2010 à minuit pile.</li>
<li>D'18:40:34' pour la date du jour de compilation du programme à 18h40min34sec.</li>
<li>D'' pour la date du jour de compilation du programme à minuit. </li>
</ul>
</div>
<br />
<h3 style="text-decoration: underline;">
Metatrader fournit les horodatages: Time[] et MarketInfo()
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Comme je l'ai précisé, la plupart du temps (voire quasiment tout le temps), on ne créé pas d'horodatage, on prend ceux fournis par MetaTrader par deux moyens:<br />
<ul style="text-indent: 0;">
<li><code style="background-color: white; color: black; font-weight: bold;"><span style="color: blue;">Time</span>[]</code> Ce tableau d'historique prédéfini par MetaTrader nous donne les horodatages des ouvertures de chaque période. Il suffit de mettre entre les crochets le numéro de la période désirée. 0 étant celle en cours, 1 celle qui vient de finir et 2 celle d'avant, etc. Je précise de suite qu'on a tendance à penser que ces horodatages sont ceux du début de chaque période, eh zou ! raté ! Ils correspondent aux horodatages des premiers ticks de chaque période, qui eux n'arrivent pas forcément à la première seconde de chaque période ! :D</li>
<li><code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">MarketInfo</span>()</code> est une fonction qui peut donner plusieurs informations sur le marché. (d'où son nom). Il faut lui préciser en premier paramètre la paire voulue avec quelque chose comme <code style="background-color: white; color: #45818e; font-weight: bold;">"EURUSD"</code>
ou bien <code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">Symbol</span>()</code> qui donnera pareil sur l'euro-dollar, et le type d'information en deuxième paramètre. Le type d'information est une constante qui commence par <code style="background-color: white; color: #0b5394; font-weight: bold;">MODE_</code>. Vous commencez à la saisir et l'éditeur vous suggère avec l'auto-complétion les possibilités. Dans notre cas on termine de taper <code style="background-color: white; color: #0b5394; font-weight: bold;">TIME</code> pour écrire la constante <code style="background-color: white; color: #0b5394; font-weight: bold;">MODE_TIME</code>. Et là, la fonction nous donne le dernier temps connu du serveur. Celui que le serveur a donné dans le dernier tick reçu. </li>
</ul>
</div>
<br />
<h3 style="text-decoration: underline;">
Du code exemple pour Time[] et MarketInfo()
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Nous allons utiliser le tableau prédéfini <code style="background-color: white; color: black; font-weight: bold;"><span style="color: blue;">Time</span>[]</code> pour lire dans l'historique le temps de début de la période en cours, et la fonction <code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">MarketInfo</span>()</code> pour obtenir l'horodatage du dernier tick reçu et étudier un peu les résultats obtenus. Nous allons placer ce code juste dans la fonction Init(), où nous déclarons deux variables du type <b><span style="color: blue;">datetime</span></b> pour contenir les deux nombres.
</div>
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code><span style="color: blue;">int</span> init()
{
<span style="color: blue;">datetime</span> horodatageDebutPeriode = <span style="color: blue;">Time</span>[<span style="color: #38761d;">0</span>];
<span style="color: blue;">datetime</span> horodatageTickActuel = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #674ea7;">Symbol</span>(),<span style="color: #0b5394;">MODE_TIME</span>);
<span style="color: blue;">datetime</span> ecartEnSecondes = horodatageTickActuel - horodatageDebutPeriode;
<span style="color: #674ea7;">Print</span>(<span style="color: #45818e;">"horodatage début période: "</span>, horodatageDebutPeriode);
<span style="color: #674ea7;">Print</span>(<span style="color: #45818e;">"horodatage tick actuel: "</span>, horodatageTickActuel);
<span style="color: #674ea7;">Print</span>(<span style="color: #45818e;">"écart en secondes: "</span>, ecartEnSecondes);
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}</code></pre>
<br />
<div style="text-align: justify; text-indent: 3em;">
Et le tutoriel en vidéo !
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='4800' height='360' src='https://www.youtube.com/embed/v76rgWkc20U?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<div style="text-align: justify; text-indent: 3em;">
En application de cette initiation au type datetime, nous ferons des calculs arithmétiques sur le temps dans le prochain post, tout en commençant à faire des bibliothèques de fonctions utilisables dans les experts advisors et les indicateurs.
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-2805050944140659612014-01-18T12:12:00.000+01:002014-01-24T08:29:41.274+01:00IndicatorCounted() et le remplissage de l'historique de l'indicateur 3 / 3.<div style="text-align: justify; text-indent: 3em;">
Et voici finalement un exemple simple d'indicateur stable dans le temps, sans artefacts. Cet indicateur reprend ce qui est expliqué dans les deux posts précédents et donnera une valeur moyenne approchée du cours à chaque période. Nous ne pouvons pas réaliser une moyenne exacte du cours pour les périodes avant l'exécution de l'indicateur, car l'historique ne garde pas en mémoire tous les ticks: il n'y a que les high, low, open et close, soit quatre valeurs seulement du cours à chaque période. Et ces valeurs sont celles du bid, le ask n'est pas du tout sauvegardé dans l'historique. On ne peut avoir le ask qu'au moment où on reçoit le tick car MetaTrader ne l'enregistre pas. Six valeurs par période quatre du bid plus le temps et le volume, c'est mieux que rien et nous permet d'avoir une moyenne qui devrait être relativement proche de la moyenne réelle du cours sur la période. D'autant plus qu'on a la plus haute et la plus basse dont on va se servir. Il faut bien comprendre qu'avoir ces deux valeurs ne nous permet pas de savoir ce qu'a fait le cours durant la période. Nous savons seulement qu'il est resté entre les deux. Nous allons juste utiliser ces deux valeurs et faire ce qu'en trading on appelle la valeur médiane. Une moyenne des quatre bid (high, low open et close) sera faite ultérieurement dans un autre post, et elle sera plus proche de la vraie moyenne que la valeur médiane.
</div>
<br />
<h3 style="text-decoration: underline;">
La valeur médiane:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Il s'agit de faire un simple calcul de moyenne entre deux valeurs, mais nous n'allons pas le laisser comme ça nu dans le code de l'indicateur: on va l'habiller dans une fonction ce qui nous permettra de le réutiliser dans d'autres indicateurs, voire experts advisors. Nous la placerons même dans un fichier header qui contiendra de nombreuses fonctions de calculs sur les cours, mais ce fichier c'est pour plus tard. Pour l'instant voici comment faire la fonction:<br />
<ul>
<li>il faut savoir sur quelle période de l'historique on doit la faire. Il nous faut donc un paramètre qui est le numéro de période dans l'historique. C'est un nombre entier (int)</li>
<li>on fait le calcul (high + low) / 2 qu'on stocke dans une variable nommée coursMedian déclarée en même temps comme une valeur à virgule (double). Pour être sûr d'obtenir un nombre à virgule, on fait la division par un nombre à virgule sûr et certain: 2.0.</li>
<li>on retourne cette valeur au code appelant la fonction.</li>
</ul>
Voici donc le code de la fonction:
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">double</span> obtenirCoursMedian(<span style="color: blue;">int</span> noPeriode) {
<span style="color: blue;">double</span> coursMedian = (<span style="color: magenta;">High</span>[noPeriode] + <span style="color: magenta;">Low</span>[noPeriode]) / <span style="color: #38761d;">2.0</span>;
<span style="color: blue;">return</span>(coursMedian);
}
</code></pre>
</div>
<h3 style="text-decoration: underline;">
L'initialisation de l'indicateur:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Nous reprenons le code du tout premier indicateur que je vous ai proposé, en version améliorée: celui de l'initialisation de l'indicateur dans une fonction: <a href="http://argent-facile-avec-robots-forex.blogspot.fr/2013/08/factorisation-code-indicateur-prix-moyen.html" target="_blank">factorisation du code d'initialisation de l'indicateur</a>. Il y a deux choses dans cette fonction:<br />
<ol>
<li>On fixe le nombre de décimales de précision des valeurs données par l'indicateur avec la fonction <code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">IndicatorDigits</span>()</code>. On doit lui fournir un paramètre qui est un nombre entier indiquant le nombre de décimale, normalement 4 ou 5. On va prendre le nombre de décimales de la paire sur laquelle a été lancé l'indicateur. C'est la fonction <code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">MarketInfo</span>()</code> qui nous donnera ça, à condition de lui indiquer deux choses:
<ol>
<li>La paire sur laquelle nous travaillons, qui est donnée par la fonction <code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">Symbol</span>()</code>.</li>
<li>et ce qu'on lui demande sur cette paire de devises: le nombre de chiffres décimaux. Ce qui est indiqué par la constante MQL4 : <code style="background-color: white; color: black; font-weight: bold;"> <span style="color: #0b5394;">MODE_DIGITS</span></code>. Cette constante nommée cache un nombre entier défini par MetaTrader, mais peut importe, ce nombre aura pour la fonction la signification de vouloir le nombre de décimales.
</li>
</ol>
</li>
<li>
et notre fonction fixe le nom court de l'indicateur avec la fonction <code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">IndicatorShortName</span>()</code>. Cette fonction prend évidemment un paramètre qui est le nom qu'on donne à l'indicateur sous forme de chaine de caractères (string). Il faut que ce nom soit passé en paramètre à notre fonction, sinon elle ne saura pas quoi mettre. Ou bien elle peut définir un nom elle même et le donner à l'indicateur, mais ce serait toujours le même, et ça n'aurait pas d'intérêt. MetaTrader a besoin de ce nom pour pouvoir l'afficher sur les graphiques et indiquer que l'indicateur est présent.
</li>
</ol>
Voici le code complet de notre fonction déjà faite précédemment. J'ai changé le nom du paramètre, car avec un nom en français, c'est plus lisible et on fait bien la différence entre un nom que nous avons donné et un nom fixé par MetaTrader. (eh oui ! il faut toujours améliorer un code dès qu'on voit une amélioration possible ! Ne jamais cesser de le faire.)
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">void</span> initIndicateur(<span style="color: blue;">string</span> nomCourt) {
<span style="color: #674ea7;">IndicatorDigits</span>(<span style="color: #674ea7;">MarketInfo</span>(<span style="color: #674ea7;">Symbol</span>(), <span style="color: #0b5394;">MODE_DIGITS</span>));
<span style="color: #674ea7;">IndicatorShortName</span>(nomCourt);
}
</code></pre>
</div>
<br />
<h3 style="text-decoration: underline;">
L'initialisation d'un index:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Nous reprenons aussi le code du tout premier indicateur que je vous ai proposé en version améliorée pour initialiser un index d'indicateur: <a href="http://argent-facile-avec-robots-forex.blogspot.fr/2013/08/factorisation-code-indicateur-prix-moyen.html" target="_blank">factorisation du code d'initialisation de l'indicateur</a>. C'est la fonction InitIndex qui fait pour l'instant quatre choses:<br />
<ol>
<li>initialiser le style de traçage de l'index avec ce style passé en paramètre de notre fonction. Ce style possède une valeur par défaut car le plus souvent ce sera une ligne. Comme ça, le plus souvent, nous n'auront pas besoin de le préciser.</li>
<li>initialiser le buffer de l'index avec le tableau qu'on aura déclaré au début du code de l'indicateur. Ce tableau se passe en paramètre de notre fonction par référence, et non par copie (voir le post consacré à ce sujet: <a href="http://argent-facile-avec-robots-forex.blogspot.fr/2013/08/initiation-mql4-passage-par-reference.html" target="_blank">passer une valeur par référence</a>.</li>
<li>initialiser le décalage de l'index (shift) qui est un décalage du traçage de cet index seulement. Nombre entier positif ou négatif. J'ajoute une valeur par défaut par rapport à la première version car c'est très souvent 0.</li>
<li>initialiser le début de traçage: c'est un nombre qui indique le nombre de périodes à ne pas tracer en partant de la période la plus ancienne. Utile lorsque les premières valeurs anciennes dans l'historique sont entachées de grosses erreurs car les périodes concernées n'ont pas suffisamment de périodes précédentes pour donner une valeur correcte. J'ajoute ici une valeur par défaut, car le plus souvent ce sera zéro. </li>
</ol>
Pour toutes ces taches il faut évidemment préciser le numéro de l'index concerné (entre 0 et 7) qu'on aura reçu en paramètre. Voici le code complet de la fonction (la première ligne a été coupée car trop longue pour rentrer entière dans la largeur du post):
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">void</span> initIndex(<span style="color: blue;">int</span> noIndex, <span style="color: blue;">double</span> &buffer[], <span style="color: blue;">int</span> shift=<span style="color: #38761d;">0</span>,
<span style="color: blue;">int</span> begin=<span style="color: #38761d;">0</span>, <span style="color: blue;">int</span> style=<span style="color: #0b5394;">DRAW_LINE</span>) {
<span style="color: #674ea7;">SetIndexStyle</span>(noIndex,style);
<span style="color: #674ea7;">SetIndexBuffer</span>(noIndex,buffer);
<span style="color: #674ea7;">SetIndexShift</span>(noIndex, shift);
<span style="color: #674ea7;">SetIndexDrawBegin</span>(noIndex, begin);
}
</code></pre>
</div>
<h3 style="text-decoration: underline;">
Tutoriel vidéo pour le code complet de l'indicateur:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Nous reprenons la boucle principale étudiée dans le post précédent sur le <a href="http://argent-facile-avec-robots-forex.blogspot.com/2014/01/historique-bars-indicatorCounted.html">remplissage de l'historique</a>. Nous déclarons également sous forme de constante au début du code le nom court de l'indicateur, ainsi que le numéro d'index que nous utiliserons (le 0). Nous plaçons les deux fonctions d'initialisation dans la fonction init() et rien dans la fonction deinit(). Dans la fonction start() on déclare un numéro de période qui va parcourir toutes les périodes de l'historique et un nombre décimal double qui va contenir le résultat du calcul de chaque période avant de le stocker dans le buffer de l'index. En résumé, à chaque passage de la boucle de remplissage de l'historique, on demande le calcul de la valeur médiane à la fonction créée pour ça et on le stocke dans notre variable coursMedian. Puis cette valeur, on la copie dans le buffer à la bonne case, celle numérotée par la valeur de noPeriode. La variable de boucle noPeriode prendra toutes les valeurs de numéro des périodes de l'historique, la première fois, puis seulement les valeurs à récentes à recalculer les fois suivantes. Stocker les valeurs dans le buffer de l'index c'est tout ce qu'il y a faire pour qu'elles soient disponibles pour tout expert advisor qui la demande et qu'elle soit tracées automatiquement sur les graphiques par MetaTrader. (J'aurais pu mettre directement le résultat du calcul dans le tampon, plutôt que de passer par une variable intermédiaire. Mais je préfère comme ça pour bien vous montrer l'extraction de la valeur du calcul puis l'affectation dans le tampon en deux étapes séparées, c'est plus visible pour les débutants) Voici le tutoriel vidéo:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='4800' height='360' src='https://www.youtube.com/embed/Hpx3paH7urI?feature=player_embedded' frameborder='0'></iframe></div>
<span id="goog_70703695"></span><span id="goog_70703696"></span><br />
Et le code complet:<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| CoursMedian.mq4 |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2014, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;"> "http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: blue;">#property indicator_chart_window
#property indicator_buffers</span> <span style="color: #38761d;">1</span>
<span style="color: blue;">#property indicator_color1</span> <span style="color: #0b5394;">Aqua</span>
<span style="color: #999999;">//--- input parameters</span>
<span style="color: blue;">extern int</span> decalage = <span style="color: #38761d;">0</span>;
<span style="color: #999999;">//--- buffers</span>
<span style="color: blue;">double</span> tamponCoursMedian[];
<span style="color: #999999;">//--- constantes</span>
<span style="color: blue;">string</span> NOM_COURT_INDICATEUR = <span style="color: #45818e;">"Cours Median"</span>;
<span style="color: blue;">int</span> NO_INDEX = <span style="color: #38761d;">0</span>;
<span style="color: #999999;">//--- fonctions</span>
<span style="color: blue;">double</span> obtenirCoursMedian(<span style="color: blue;">int</span> noPeriode) {
<span style="color: blue;">double</span> coursMedian = (<span style="color: magenta;">High</span>[noPeriode] + <span style="color: magenta;">Low</span>[noPeriode]) / <span style="color: #38761d;">2.0</span>;
<span style="color: blue;">return</span>(coursMedian);
}
<span style="color: blue;">void</span> initIndicateur(<span style="color: blue;">string</span> nomCourt) {
<span style="color: #674ea7;">IndicatorDigits</span>(<span style="color: #674ea7;">MarketInfo</span>(<span style="color: #674ea7;">Symbol</span>(), <span style="color: #0b5394;">MODE_DIGITS</span>));
<span style="color: #674ea7;">IndicatorShortName</span>(nomCourt);
}
<span style="color: blue;">void</span> initIndex(<span style="color: blue;">int</span> noIndex, <span style="color: blue;">double</span> &buffer[], <span style="color: blue;">int</span> shift=<span style="color: #38761d;">0</span>,
<span style="color: blue;">int</span> begin=<span style="color: #38761d;">0</span>, <span style="color: blue;">int</span> style=<span style="color: #0b5394;">DRAW_LINE</span>) {
<span style="color: #674ea7;">SetIndexStyle</span>(noIndex,style);
<span style="color: #674ea7;">SetIndexBuffer</span>(noIndex,buffer);
<span style="color: #674ea7;">SetIndexShift</span>(noIndex, shift);
<span style="color: #674ea7;">SetIndexDrawBegin</span>(noIndex, begin);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> init()
{
initIndicateur(NOM_COURT_INDICATEUR);
initIndex(NO_INDEX, tamponCoursMedian, decalage);
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> deinit()
{
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> start()
{
<span style="color: blue;">double</span> coursMedian;
<span style="color: blue;">int</span> noPeriode;
<span style="color: blue;">int</span> nbPeriodesATraiter = <span style="color: magenta;">Bars</span> - <span style="color: #674ea7;">IndicatorCounted</span>();
<span style="color: blue;">for</span>(noPeriode=nbPeriodesATraiter-<span style="color: #38761d;">1</span> ; noPeriode>=<span style="color: #38761d;">0</span> ; noPeriode--) {
coursMedian = obtenirCoursMedian(noPeriode);
tamponCoursMedian[noPeriode] = coursMedian;
}
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span></code></pre>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-81300397962829921562014-01-17T12:02:00.000+01:002014-01-17T12:02:01.242+01:00IndicatorCounted() et le remplissage de l'historique de l'indicateur 2 / 3.<div style="text-align: justify; text-indent: 3em;">
Suite de la gestion de l'historique d'un indicateur. Nous allons maintenant voir comment gérer ça. Dans le post où je vous fais faire un premier indicateur, la gestion est mauvaise et il se produit des artéfacts dans le traçage de la courbe de l'indicateur de temps en temps. Cela signifie qu'il y a un problème dans la continuité des valeurs calculées. Premièrement nous devons remplir l'historique de l'indicateur simplement parce que notre indicateur doit être valide pour toutes les périodes dans l'historique géré par MetaTrader. Il faut que notre indicateur propose une valeur pour chaque période, comme ça, il y a continuité temporelle pour pouvoir analyser le passé et tenter d'anticiper le futur des cours. Un problème supplémentaire vient se mêler à tout ça: la mémoire de l'ordinateur est limitée. Or Metatrader, doit gérer l'historique des cours en remontant loin dans le passé, en général plus de 50 000 périodes du passé chargées en mémoire. Et cela pour cinq valeurs enregistrées par période pour une seule paire de devises: time, volume, high, low, open et close. Cela fait 5 valeurs de 8 octets chacune plus le temps sur 4 octets: 5*8+4=44 octets par période, à multiplier par un nombre de périodes entre 50 000 et 100 000, nous obtenons une mémoire nécessaire entre 2 200 000 et 4 400 00 octets pour une seule paire de devises. Et c'est sans compter les éventuels indicateurs à ajouter sur la paire. Chaque signal (ou index) d'indicateur doit enregistrer pour ce même nombre de périodes des nombres sur 8 octets, soit entre 400 000 et 800 000 octets par index d'indicateur (un indicateur pouvant aller jusqu'à huit index, on comprend pourquoi c'est limité). MetaTrader a donc besoin pour une paire de devises avec un indicateur mono-index de 2 600 000 octets à 5 200 000 octets, soit entre 2,5 et 5Mo. Si le logiciel MetaTrader fonctionne jour, et nuit sans discontinuer (et il est sensé le faire, il est la pour ça, parce qu'un trader manuel doit quand même dormir un peu !) le nombre de périodes de l'historique va gonfler et faire monter la note en coût d'utilisation mémoire. Alors MetaTrader fait des recyclages de mémoire tampon, et des réallocations des tampons, bref, il fait sa tambouille pour gérer la mémoire dont il dispose. Nous avons donc des recyclages de mémoire, et de temps en temps, et, si nous ne remplissons pas automatiquement l'historique, nous voyons apparaitre des vielles valeurs du passé dans le présent. Sur le graphique nous avons de grands sauts brutaux de la courbe. Ce sont les artéfacts qui apparaissent avec le premier indicateur que je vous ai proposé.</div>
<br />
<h3 style="text-decoration: underline;">
La variable prédéfinie Bars:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
La taille de l'historique en nombre de périodes est donnée par la variable <span style="color: magenta; font-weight: bold;">Bars</span>. Il faut donc parcourir tout l'historique du cours, faire les calculs et mettre un résultat dans le buffer de l'indicateur pour chaque période. Le buffer a une taille gérée par MetaTrader et donc il a la même que celle des tableaux de l'historique du cours. Donc <span style="color: magenta; font-weight: bold;">Bars</span> nous donne sa taille. Alors la dernière case du tableau possède le numéro Bars-1 (la numérotation commence à zéro), et doit contenir la toute première valeur de l'historique à calculer par notre indicateur évidemment. C'est la valeur la plus ancienne que l'indicateur calculera et donnera.
</div>
<br />
<h3 style="text-decoration: underline;">
L'historique du cours:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Je l'ai déjà précisé: l'historique du cours de la paire de devise est stocké dans des tableaux gérés par MetaTrader. Ces tableaux sont mis à notre disposition pour pouvoir lire dedans et obtenir les cours pour la paire de devise sur laquelle nous avons lancé l'indicateur (ou l'expert). Nous disposons grâce à MetaTrader, des plus-hauts des périodes (tableau <span style="color: magenta; font-weight: bold;">High</span>[]), des plus-bas (tableau <span style="color: magenta; font-weight: bold;">Low</span>[]), des cours d'ouverture des périodes (tableau <span style="color: magenta; font-weight: bold;">Open</span>[]), des cours de fermeture des périodes (tableau <span style="color: magenta; font-weight: bold;">Close</span>[]), des horodatages d'ouvertures des périodes (tableau <span style="color: magenta; font-weight: bold;">Time</span>[]) et des volumes d'échanges des périodes (tableau <span style="color: magenta; font-weight: bold;">Volume</span>[]). On lit donc les valeurs de la période en cours avec l'indice 0, celle qui vient de se terminer avec l'indice 1 et celle d'avant avec l'indice 2. Etc, jusqu'à l'indice <span style="color: magenta; font-weight: bold;">Bars</span>-1. A chaque changement de période, il y a une nouvelle période en cours n°0, celle qui était en cours (donc ex n°0) devient la n°1 , l'ex n°1 devient la n°2 etc, de manière automatique et géré par MetaTrader.
</div>
<br />
<h3 style="text-decoration: underline;">
La fonction IndicatorCounted():
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Puisque qu'il faut remplir l'historique, MetaTrader nous indique à chaque fois que la fonction start() de l'indicateur est exécutée, le nombre de périodes qui n'ont pas changées depuis la dernière exécution. Cette fonction nous donne le nombre de périodes déjà calculées, qui sont restées inchangées, et donc qui n'ont pas besoin d'être recalculées. C'est-à-dire que la première fois que l'indicateur est exécuté, <code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">IndicatorCounted</span>()</code> donne un nombre de périodes déjà calculées de zéro: il faut tout calculer, tout l'historique. La taille de l'historique en nombre de périodes est donnée par la variable <span style="color: magenta; font-weight: bold;">Bars</span>. Il faut donc parcourir tout l'historique du cours, faire les calculs et mettre un résultat dans le buffer de l'indicateur pour chaque période.
</div>
<br />
<h3 style="text-decoration: underline;">
Respecter la demande de calcul de MetaTrader:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Par l'intermédiaire de la fonction <code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">IndicatorCounted</span>()</code> MetaTrader nous demande de calculer certaines périodes. La première fois, la fonction nous donne la valeur de 0, ce qui signifie qu'il y a 0 valeurs déjà calculées. On devra alors parcourir tout l'historique du cours et effectuer les calculs et écritures des résultats dans le buffer de l'indicateur pour toutes les périodes de la plus ancienne n°Bars-1 à la plus récente n°1, ou même n°0 si notre calcul nous permet d'utiliser une période qui n'est pas finie. La fois suivante, si la période en cours n'est pas une nouvelle, <code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">IndicatorCounted</span>()</code> nous donnera la valeur de <span style="color: magenta; font-weight: bold;">Bars</span>, c'est-à-dire <span style="color: magenta; font-weight: bold;">Bars</span> valeurs qui n'ont pas besoin d'être recalculées, car toutes les valeurs auront été calculées et n'auront pas changé, sauf la période n°0, celle en cours, car on vient de recevoir un tick, qui fait partie de cette période, et donc les high, low, open, close et volume de cette période sont susceptibles de changer et il faut alors la recalculer. Il vient un moment ou la période en cours est nouvelle et du coup <code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">IndicatorCounted</span>()</code> donne la valeur <span style="color: magenta; font-weight: bold;">Bars</span>-1 car pour éviter des problèmes de transition d'une période à l'autre, MetaTrader demande de recalculer une période de plus en remontant dans l'historique: celle qui vient de finir.<br />
De temps en temps MetaTrader opère des recyclages et réallocations de mémoire tampon, et demande alors de recalculer des valeurs en remontant plus dans l'historique car suite au recyclage, un certain nombre de périodes ne sont plus bonnes (toujours les plus récentes). La fonction <code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">IndicatorCounted</span>()</code> donnera la valeur nécessaire. C'est à nous de parcourir l'historique en conséquence et de faire les calculs demandés.</div>
<br />
<h3 style="text-decoration: underline;">
L'algorithme nécessaire pour chaque indicateur programmé:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Le logiciel MetaTrader nous indique donc le nombre de périodes dans l'historique avec la variable prédéfinie <span style="color: magenta; font-weight: bold;">Bars</span>, et le nombre de périodes les plus anciennes à ne pas recalculer avec la fonction <code style="background-color: white; color: black; font-weight: bold;"><span style="color: #674ea7;">IndicatorCounted</span>()</code>. l'algorithme de base de chaque indicateur devra donc être une boucle de parcours de l'historique de la période à calculer la plus ancienne à la période la plus récente. Des deux valeurs précédentes fournies par MetaTrader on peut en déduire une nouvelle qui est le nombre de période à traiter par le calcul suivant (différence entre le nombre total de périodes et celles qu'on ne doit pas recalculer):<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>nbPeriodesATraiter = <span style="color: magenta; font-weight: bold;">Bars</span> - <span style="color: #674ea7;">IndicatorCounted</span>();</code></pre>
Les numéros des cases des tableaux étant inférieurs d'une unité on parcourra les tableaux d'historique de nbPeriodesATraiter-1 jusqu'à 1 ou 0 selon l'indicateur avec une boucle for ou une boucle while:
<br />
<pre style="background-color: white; color: black; padding: 1em;"><code style="font-weight: bold;">
<span style="color: blue;">int</span> noPeriode;
<span style="color: blue;">for</span>(noPeriode=nbPeriodesATraiter-<span style="color: #38761d;">1</span> ; noPeriode><span style="color: #38761d;">0</span> ; noPeriode--) {</code>
instructions de lecture de l'historique,
de calculs et d'écriture dans le buffer de l'indicateur
<code style="font-weight: bold;">}
</code></pre>
Dans cette boucle for: le numéro de période commence comme prévu à nbPeriodesATraiter-1, est décrémenté de 1 à chaque passage de boucle par noPeriode-- et la boucle continue tant que noPeriode>0.
Ou bien utiliser la boucle while sans oublier qu'il faut gérer manuellement les changements de numéro de période:
<br />
<pre style="background-color: white; color: black; padding: 1em;"><code style="font-weight: bold;">
<span style="color: blue;">int</span> noPeriode = nbPeriodesATraiter -<span style="color: #38761d;"> 1</span> ;
<span style="color: blue;">while</span>(noPeriode><span style="color: #38761d;">0</span>) {</code>
instructions de lecture de l'historique,
de calculs et d'écriture dans le buffer de l'indicateur
<code style="font-weight: bold;"> noPeriode--;
}
</code></pre>
Voilà pour l'algorithme principal d'un indicateur. Un exemple au prochain post, histoire de vous laissez digérer un peu ce qu'on vient de voir.
</div>
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-57862159168032188622014-01-16T11:09:00.000+01:002014-01-16T20:43:36.813+01:00IndicatorCounted() et le remplissage de l'historique de l'indicateur 1 / 3.<div style="text-align: justify; text-indent: 3em;">
Concernant les indicateurs nous allons nous pencher sur un détail important qui pose des problèmes lorsqu'on débute et qu'il faut régler tout de suite: celui du remplissage de l'historique de l'index. Je vais donc vous détailler les notions avant d'expliquer ce qu'il faut faire pour chaque indicateur qu'on créé.</div>
<br />
<h3 style="text-decoration: underline;">
Historique:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Pour nous permettre de faire des anticipations de l'évolution du cours, MetaTrader conserve en mémoire les valeurs du cours pour constituer un historique du cours. On peut alors lire ces valeurs et faire des calculs avec pour prévoir, selon nos méthodes, ce que va faire le cours. Cet historique est entièrement géré par MetaTrader qui nous met à disposition un tableau de ces valeurs. Lorsqu'on fait un indicateur, le but est de faire une série de valeurs calculées pour indiquer quelque chose sur le cours. Il faut donc remplir aussi l'historique de l'indicateur, ce que nous allons voir ici.
</div>
<br />
<h3 style="text-decoration: underline;">
Indicateur:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Un indicateur est un programme tout comme les experts advisors, qui va étudier le signal, mais dont le but n'est pas de passer les ordres mais de calculer une ou des valeurs caractéristiques d'une information sur ce cours. Grâce à cette information, les experts advisors vont pouvoir déterminer s'il faut acheter, vendre ou ne rien faire en temps réel. Donc un indicateur va être utilisé par les experts advisors, ou même simplement par un trader manuel qui recevra ainsi en temps réel et de manière automatique le résultat d'un calcul pour l'aider dans ses prises de décisions.
</div>
<br />
<h3 style="text-decoration: underline;">
Index:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Il faut bien comprendre le concept d'index lorsqu'on créé un indicateur dans MetaTrader. Un index est un signal, c'est à dire une suite de valeurs calculées (une par période temporelle) qui vont tracer une courbe. On peut en faire huit par indicateur, chacune possédant sa série de valeurs. Une valeur pour chaque période temporelle de l'historique entier de la paire de devises. C'est-à-dire qu'on remonte tout l'historique, il va falloir toutes les calculer. Et à chaque nouvelle période qui rentre dans l'historique il faut en calculer une.
</div>
<br />
<h3 style="text-decoration: underline;">
Buffer:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Pour tracer l'évolution de l'indicateur au cours du temps, il faut stocker toutes ses valeurs pour pouvoir les lire, faire encore des calculs avec ou tout simplement les afficher sur un graphique. On va stocker ces valeurs dans un tableau, qu'en programmation on nomme un buffer, "tampon" en français. C'est-à-dire une zone suffisamment vaste en mémoire qui sert de tampon de stockage. Tampon parce que vu sa taille, elle ne débordera pas. Et si elle venait à être pleine, MetaTrader gère le problème et demande au système une zone supplémentaire. De notre côté, nous avons juste à écrire et lire des valeurs dans ce tableau et rien d'autre. MetaTrader tracera tout seul le graphique avec, sans que nous nous en occupions. Il faut juste le remplir avec des valeurs ! MetaTrader ne les invente pas pour nous, puisque ce sont celles de notre indicateur, issues de nos calculs. MetaTrader s'occupe déjà de maintenir l'historique du cours, de gérer la taille de nos tampons d'indicateurs et de tracer nos courbes.
</div>
<br />
<h3 style="text-decoration: underline;">
Timeserie:
</h3>
<br />
<div style="text-align: justify; text-indent: 3em;">
Comme on l'a vu précédemment, on accède aux valeurs d'un tableau par le nom du tableau et accolé au nom, une paire de crochets encadrant le numéro de la case du tableau voulue. Chaque case du tableau correspondant à une place en mémoire numérotée. Le processeur y accède par un numéro qui est appelée adresse mémoire. Lorsqu'on créé dans un programme un tableau, le compilateur réserve une place de 4 octets en mémoire pour contenir l'adresse où le tableau sera réellement placé. Ce sera l'adresse du début du tableau. Toutes les cases du tableau seront les unes à côté des autres dans la mémoire, à l'endroit désigné par l'adresse contenue dans la variable dans le programme (nom donné au tableau).
Par exemple si je créé un tableau appelé "moyenne" de 500 cases, je tape les instructions:<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code><span style="color: blue;">double</span> <span style="color: black;">moyenne[</span><span style="color: #38761d;">500</span><span style="color: black;">];</span></code></pre>
Avec cette ligne de code, nous créons deux places en mémoire: celle de la variable moyenne, de quatre octets qui contient uniquement l'adresse de la véritable place du tableau, par exemple 0xA53BC970 (notation hexadécimale pour être moins grosse, si si c'est un nombre, malgré les lettres !). Et une deuxième place de 500x8=4000 octets pour contenir 500 nombres décimaux (de type <span style="color: blue;">double</span>) de 8 octets chacun, commençant à l'adresse 0xA53BC970. Un petit schéma vaut mieux qu'un grand discours:<br />
<table border="1" style="margin: 2em; text-align: center;"><tbody>
<tr><td style="background-color: grey; width: 10em;">contenu de moyenne</td><td>0xA5...3B...C9...70</td></tr>
<tr><td style="background-color: grey; width: 10em;">adresse:<br />
n° octet en mémoire</td><td>octets n°0xA53BA000 à 0xA53BA003</td></tr>
</tbody></table>
Et un peu plus loin dans la mémoire:<br />
<table border="1" style="margin: 2em; text-align: center;"><tbody>
<tr><td style="background-color: grey; width: 10em;">case n°</td><td>0</td><td>1</td><td>2</td><td style="border-style: none; width: 5em;">...</td><td>499</td></tr>
<tr><td style="background-color: grey; width: 10em;">adresse:<br />
n° octet en mémoire</td><td>0xA53BC970</td><td>0xA53BC978</td><td>0xA53BC980</td><td style="border-style: none; width: 5em;">...</td><td>0xA53CB58</td></tr>
</tbody></table>
Le premier emplacement sert uniquement à retrouver où se situe le deuxième emplacement: le tableau. Et lorsqu'on veut y accéder pour lire la valeur de la case n°2 avec par exemple l'instruction:
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code><span style="color: #674ea7;">Print</span><span style="color: black;">(moyenne[</span><span style="color: #38761d;">2</span><span style="color: black;">]);</span></code></pre>
Le compilateur va déterminer l'adresse exacte de la valeur cherchée en prenant l'adresse de base du tableau dans le premier emplacement (la variable), et en ajoutant deux fois la taille en mémoire d'une valeur de type <span style="color: blue;">double</span>, c'est-à-dire 2x8 octets, on obtient donc 0xA53BC970 + 2x8 = 0xA53BC970 + 16 = 0xA53BC970 + 0x10 (en hexadécimal) = 0xA53BC980. Ce qui est l'adresse de la deuxième case mémoire du tableau. Le compilateur ne vérifiera pas si on dépasse le tableau, et si on demande la case n°500, c'est la 501<sup>ème</sup>, le calcul fera tomber en dehors du tableau dans un emplacement qui ne nous est pas attribué et le système fera arrêter le programme d'un coup car il aura tenté d'accéder à une place qui ne lui était pas réservée.<br />
Vous constatez que la numérotation des cases du tableau suit la progression des adresses mémoire. C'est l'ordre naturel en programmation. Mais pour des considérations temporelles, l'éditeur MetaQuotes a décidé que MetaTrader devait gérer la numérotation dans l'ordre contraire: les timeseries. Il faut imaginer qu'on remonte dans l'historique, et donc quand on veut la période temporelle n°0, c'est la période en cours. La n°1, c'est celle qui vient de se terminer, et la n°2, c'est celle d'avant, etc. Or le compilateur quand il écrit ou lit dans un tableau c'est toujours dans l'ordre naturel de la programmation: la numérotation des cases augmente avec les adresses mémoire. Et là, il faut que la dernière case qui ait été remplie soit la plus récente, donc avec le numéro 0. Je vous montre avec un schéma. Les cases colorées sont celles qui ont été remplies:<br />
<table border="1" style="margin: 2em; text-align: center;"><tbody>
<tr><td style="background-color: grey; width: 10em;">n° timeserie</td><td style="background-color: yellow; color: black;">2</td><td style="background-color: yellow; color: black;">1</td><td style="background-color: yellow; color: black;">0</td><td>inutilisée</td><td style="border-style: none; width: 5em;">...</td></tr>
<tr><td style="background-color: grey; width: 10em;">adresse:<br />
n° octet en mémoire</td><td style="background-color: yellow; color: black;">0xA53BC970</td><td style="background-color: yellow; color: black;">0xA53BC978</td><td style="background-color: yellow; color: black;">0xA53BC980</td><td>0xA53BC988</td><td style="border-style: none; width: 5em;">...</td></tr>
</tbody></table>
Dès qu'il y a une nouvelle période (celle en cours vient de finir), la numérotation est alors décalée, et elle se décale toutes les minutes si la période est M1, ou toutes les quatre heures si la période est H4, etc. La première case inutilisée devenant la n°0. Vous devez juste retenir qu'à tout moment la période en cours, c'est la n°0, celle qui vient de finir la n°1, celle d'avant c'est la n°2, etc. Rassurez-vous, c'est MetaTrader qui gère cette différence. Vous avez juste à savoir qu'il faut remonter dans le temps en augmentant le numéro des cases. Puisque MetaTrader gère tout, y compris la taille des tableaux en mémoire, vous ne devez même pas indiquer de taille lors de la création de votre buffer pour votre courbe d'indicateur:<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code><span style="color: blue;">double</span> <span style="color: black;">moyenne[];</span></code></pre>
Par contre, il faut indiquer à MetaTrader que ce tableau créé, est un buffer de signal qu'il devra gérer, et qu'on remplira avec nos valeurs. On choisit pour ce buffer, le numéro 0, et on peut aller jusqu'au numéro 7 (huit index):<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code><span style="color: #674ea7;">SetIndexBuffer</span><span style="color: black;">(<span style="color: #38761d;">0</span>, moyenne);</span></code></pre>
</div>
<br />
<div style="text-align: justify; text-indent: 3em;">
Ça suffira pour aujourd'hui. Il y a suffisamment d'informations à digérer et je tenais à faire ces précisions pour mieux comprendre les indicateurs avant de voir une partie technique indispensable pour tous les indicateurs: remplir l'historique, même celui déjà présent avant l'exécution de l'indicateur ! Nous verrons ça au post suivant.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-83391702243449877132013-08-16T22:52:00.000+02:002014-01-24T08:30:11.259+01:00Factorisation du code de l'indicateur Taux Moyen<div style="text-align: justify; text-indent: 3em;">
Nous reprenons immédiatement l'indicateur réalisé juste avant pour restructurer un peu le code. Restructurer le code par des fonctions pour le rendre réutilisable s'appelle factoriser, comme en mathématiques quand vous factorisez une expression. Cela a le même sens. Nous allons nous focaliser uniquement sur l'initialisation de l'indicateur car il contient de nombreuses lignes qui sont des appels à des fonctions d'initialisation. Il y a deux types de fonctions d'initialisation: celles qui concernent l'indicateur au niveau global et celles qui concernent un index dans l'indicateur. Un index étant un signal à calculer et à tracer. Il peut y en avoir huit maximum par indicateur. Nous n'en utilisons qu'un seul pour l'instant, mais à l'avenir sur cet indicateur on en utilisera trois. (selon ce que je projette de faire pour le moment) Nous allons donc faire deux fonctions, une pour initialiser l'indicateur au niveau global et une autre pour initialiser un index. Et cette dernière pourra être utilisée jusqu'à huit fois dans l'indicateur pour initialiser les huit signaux possibles.</div>
<br />
<h3>
L'initialisation de l'indicateur:
</h3>
<div style="text-align: justify; text-indent: 3em;">
Dans l'état actuel des choses, l'indicateur est initialisé seulement avec deux fonctions: une pour préciser le nombre de décimales à utiliser et l'autre pour préciser le nom court de l'indicateur. Ce nom sera passé en paramètre de la fonction qui ne retourne aucune valeur, donc déclarée en void.</div>
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">void</span> initIndicateur(<span style="color: blue;">string</span> shortName) {
<span style="color: #674ea7;">IndicatorDigits</span>(<span style="color: #674ea7;">MarketInfo</span>(<span style="color: #674ea7;">Symbol</span>(), <span style="color: #0b5394;">MODE_DIGITS</span>));
<span style="color: #674ea7;">IndicatorShortName</span>(shortName);
}
</code>
</pre>
<br />
<h3>
L'initialisation d'un index:
</h3>
<div style="text-align: justify; text-indent: 3em;">
Un index ou signal, s'initialise avec quatre fonctions pour l'instant. Chacune de ces fonctions prend en premier paramètre le numéro de l'index. On passera donc ce numéro en premier paramètre de notre fonction. Puis nous aurons besoin de passer le tableau qui sert de buffer. Il faudra alors le passer par référence, avec un esperluette devant son nom (&) et bien mettre la paire de crochets pour préciser que c'est un tableau, et le déclarer en tableau de nombres décimaux (double). Ensuite il faut passer le décalage à appliquer sur le signal (un nombre entier), puis l'indice de commencement de traçage (shift). Pour finir il faut le style de traçage qu'on met par défaut à DRAW_LINE. Les noms des variables buffer et shift utilisées dans cette fonction sont les mêmes que les variables globales utilisées dans l'indicateur. Il faut impérativement changer les noms des variables globales pour éviter toute collision de noms. Nous mettrons 'tampon' et 'decalage'.</div>
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">void</span> initIndex(<span style="color: blue;">int</span> noIndex, <span style="color: blue;">double</span> &buffer[], <span style="color: blue;">int</span> shift, <span style="color: blue;">int</span> begin, <span style="color: blue;">int</span> style=<span style="color: #0b5394;">DRAW_LINE</span>) {
<span style="color: #674ea7;">SetIndexStyle</span>(noIndex,style);
<span style="color: #674ea7;">SetIndexBuffer</span>(noIndex,buffer);
<span style="color: #674ea7;">SetIndexShift</span>(noIndex, shift);
<span style="color: #674ea7;">SetIndexDrawBegin</span>(noIndex, begin);
}
</code>
</pre>
<br />
<div style="text-align: justify; text-indent: 3em;">
Je vous fais faire tout ça en vidéo, puis vous avez le code complet juste après.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='480' height='360' src='https://www.youtube.com/embed/EjWk59telpE?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| tauxMoyen.mq4 |
//| Copyright 2013, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2013, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;"> "http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: blue;">#property indicator_chart_window
#property indicator_buffers</span> <span style="color: #38761d;">1</span>
<span style="color: blue;">#property indicator_color1</span> <span style="color: #0b5394;">Aqua</span>
<span style="color: #999999;">//--- input parameters</span>
<span style="color: blue;">extern int</span> decalage = <span style="color: #38761d;">0</span>;
<span style="color: #999999;">//--- buffers</span>
<span style="color: blue;">double</span> tampon[];
<span style="color: blue;">int</span> ancienCompteBars, nbTicksDansBar;
<span style="color: blue;">double</span> sommeCours;
<span style="color: blue;">double</span> obtenirCoursActuel() {
<span style="color: blue;">double</span> cours = (<span style="color: magenta;">Bid</span> + <span style="color: magenta;">Ask</span>) / <span style="color: #38761d;">2.0</span>;
<span style="color: blue;">return</span>(cours);
}
<span style="color: blue;">void</span> initIndicateur(<span style="color: blue;">string</span> shortName) {
<span style="color: #674ea7;">IndicatorDigits</span>(<span style="color: #674ea7;">MarketInfo</span>(<span style="color: #674ea7;">Symbol</span>(), <span style="color: #0b5394;">MODE_DIGITS</span>));
<span style="color: #674ea7;">IndicatorShortName</span>(shortName);
}
<span style="color: blue;">void</span> initIndex(<span style="color: blue;">int</span> noIndex, <span style="color: blue;">double</span> &buffer[], <span style="color: blue;">int</span> shift, <span style="color: blue;">int</span> begin, <span style="color: blue;">int</span> style=<span style="color: #0b5394;">DRAW_LINE</span>) {
<span style="color: #674ea7;">SetIndexStyle</span>(noIndex,style);
<span style="color: #674ea7;">SetIndexBuffer</span>(noIndex,buffer);
<span style="color: #674ea7;">SetIndexShift</span>(noIndex, shift);
<span style="color: #674ea7;">SetIndexDrawBegin</span>(noIndex, begin);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> init()
{
ancienCompteBars = <span style="color: #674ea7;">IndicatorCounted</span>();
initIndicateur(<span style="color: #45818e;">"TM"</span>);
initIndex(<span style="color: #38761d;">0</span>, tampon, decalage, <span style="color: #38761d;">0</span>);
sommeCours = <span style="color: #38761d;">0.0</span>;
nbTicksDansBar = <span style="color: #38761d;">0</span>;
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> deinit()
{
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> start()
{
<span style="color: blue;">double</span> coursActuel = obtenirCoursActuel();
<span style="color: blue;">double</span> moyenneCours = coursActuel;
<span style="color: blue;">int</span> nbBarsActuel = <span style="color: #674ea7;">IndicatorCounted</span>();
<span style="color: blue;">if</span>(nbBarsActuel > ancienCompteBars) {
<span style="color: blue;">if</span>(nbTicksDansBar > <span style="color: #38761d;">0</span>) { moyenneCours = sommeCours / nbTicksDansBar; }
tampon[<span style="color: #38761d;">1</span>] = moyenneCours;
sommeCours = <span style="color: #38761d;">0.0</span>;
nbTicksDansBar = <span style="color: #38761d;">0</span>;
ancienCompteBars = nbBarsActuel;
}
sommeCours += coursActuel;
nbTicksDansBar++;
tampon[<span style="color: #38761d;">0</span>] = sommeCours / nbTicksDansBar;
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span>
</code>
</pre>
<br />
<div style="text-align: justify; text-indent: 3em;">
Nous continuerons dans les posts suivants à améliorer et faire évoluer cet indicateur.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-64003417397657651842013-08-15T23:46:00.000+02:002014-01-24T08:30:42.606+01:00Création d'un premier indicateur pour MetaTrader 4<div style="text-align: justify; text-indent: 3em;">
Toujours avec le même algorithme, nous allons maintenant faire un indicateur. Un indicateur, à la différence d'un expert advisor, ne peut pas passer d'ordres au broker. Il est là pour donner la valeur d'un calcul sur les cours qui nous sert pour trader. En général, on l'affiche dans un graphique. On s'en sert aussi dans les experts advisors car la (ou les) valeur(s) qu'ils donne sert à la décision pour ouvrir ou clôturer une position. L'indicateur que nous allons faire, va nous donner simplement la moyenne du cours pour chaque chandelier. Toutes les minutes pour un timeframe M1, ou toutes les quatre heures pour un timeframe H4, etc. Cette moyenne sera affichée sous forme de courbe et non pas comme valeur brute dans un label sur le graphique. Vous commencez à connaître l'algorithme qu'on va utiliser sur le bout des doigts. On va utiliser le même que le précédent mais adapté à un traçage de courbe d'indicateur.</div>
<br />
<h3>
Le traçage de courbes avec MetaTrader 4:
</h3>
<div style="text-align: justify; text-indent: 3em;">
Je vais vous décevoir, mais il n'existe pas de fonction toute prête pour tracer une ligne entre deux points ! On peut tracer pleins d'objets graphiques avec les fonctions appropriées, mais pas de ligne toute simple ! Cela pour une raison principale: MetaTrader gère lui même en interne le traçage de courbes avec des lignes pour gérer les performances et la mémoire et avoir un contrôle complet sur ce processus, car si on le fait nous même c'est plus lent, et on risque de consommer bien trop de mémoire. Les concepteurs de MetaTrader ont préféré que le logiciel garde tout le contrôle à ce niveau. Et donc nous n'avons rien à tracer ! INCROYABLE ! Pour tracer une courbe, nous ne traçons rien du tout !! Il suffit juste de donner à MetaTrader les valeurs et il s'en charge. Ces valeurs sont stockées dans ce que les programmeurs appellent un buffer, ou tampon en français. Il s'agit d'une zone mémoire qui contient les données les unes à la suite des autres. Et si vous avez bien suivi, c'est typiquement un tableau ! Nous n'avons même pas à gérer la taille du tableau ! C'est pas beau ça ! :) Nous mettons simplement la valeur la plus récente au début du tableau, et toutes les valeurs se décaleront au fur et à mesure. Il faut donc déclarer un tableau au niveau global du fichier <b>sans la taille</b>, et le remplir, en général, que la ou les premières cases. Il faudra aussi préciser à l'initialisation de l'indicateur que ce tableau déclaré dans le programme est le buffer (mémoire tampon) des valeurs de la courbe grâce à la fonction <code><b>SetIndexBuffer()</b></code>. Cette fonction prend deux paramètres: l'index de la ligne à tracer (elles sont numérotées de 0 à 7 car il ne peut y en avoir que huit maximum) et le tableau créé pour servir de tampon. Les deux choses à faire sont: déclarer un tableau sans indication de taille qui sera le tampon et indiquer avec la fonction SetIndexBuffer() que ce tableau est le tampon pour la courbe numéro 0.</div>
<br />
<pre style="background-color: white; color: black; font-weight: bold;"><code>
<span style="color: blue;">double</span> buffer[];
<span style="color: #674ea7;">SetIndexBuffer</span>(<span style="color: #38761d;">0</span>, buffer);
</code>
</pre>
<br />
<h3>
Les paramètres des indicateurs:
</h3>
<div style="text-align: justify; text-indent: 3em;">
Indiquer juste le tampon des données à MetaTrader 4 n'est pas suffisant, il lui faut d'autres renseignements. Par exemple le nombre de signaux à tracer (courbes), et comment les tracer (courbe de ligne brisée ou histogramme, ou section, ou zigzag etc.). Il faut aussi indiquer le décalage par rapport au temps réel (on peut tracer en décalé temporellement), où on commence le traçage, le nom court de l'indicateur, et la précision du calcul en nombre de décimales. Il en existe d'autres, mais on va s'arrêter sur celles-là. Je vous donne le tout en code MQL4 car les noms des fonctions qui réalisent cela sont explicites sachant que "shift", c'est le décalage et "digits" ce sont les chiffres significatifs de la précision. </div>
<pre style="background-color: white; color: black; font-weight: bold;"><code>
<span style="color: #674ea7;">SetIndexStyle</span>(<span style="color: #38761d;">0</span>,<span style="color: #0b5394;">DRAW_LINE</span>);
<span style="color: #674ea7;">SetIndexShift</span>(<span style="color: #38761d;">0</span>,shift);
<span style="color: #674ea7;">IndicatorDigits</span>(<span style="color: #674ea7;">MarketInfo</span>(<span style="color: #674ea7;">Symbol</span>(),MODE_DIGITS));
<span style="color: #674ea7;">IndicatorShortName</span>(<span style="color: #134f5c;">"TM"</span>);
<span style="color: #674ea7;">SetIndexDrawBegin</span>(<span style="color: #38761d;">0</span>,<span style="color: #38761d;">0</span>);
</code>
</pre>
<div style="text-align: justify; text-indent: 3em;">
Dans ce code: "TM" sont les initiales de "Taux Moyen", c'est le nom court que je donne à l'indicateur. 'shift' est une variable qui contient le décalage sous forme de nombre entier (0 par défaut). Cette variable est déclarée comme externe avec le mot-clef <b style="color: blue;"><code>extern</code></b>, ce qui signifie qu'elle devient un paramètre ajustable du programme lorsqu'on va le démarrer en le glissant sur le graphique d'un cours. Ce paramètre s'ajustera dans un onglet de la fenêtre qui s'ouvre lors du lancement de l'expert ou indicateur.</div>
<pre style="background-color: white; color: black; font-weight: bold;"><code>
<span style="color: blue;">extern</span> shift = <span style="color: #38761d;">0</span>;
</code>
</pre>
<div style="text-align: justify; text-indent: 3em;">
Ensuite, dans ce même code, pour obtenir le nombre de décimales servant à la précision des calculs, on fait appel à la fonction MarketInfo() qui donne le nombre de décimales fournies par le broker (MODE_DIGITS) pour la paire sur laquelle l'indicateur a été lancé (Symbol()). Au final on indique que le dessin du signal numéro 0 commence à l'indice 0 du tableau tampon. Les tableaux étant inversé: plus l'indice grandit et plus on remonte dans l'historique. L'indice zéro étant celui du chandelier en cours. L'indice du chandelier complètement terminé et le plus récent est le 1. C'est bien joli tout ça, mais il y a des informations supplémentaires à indiquer et une aurte fonction à connaître. Ces informations sont: où dessiner la ou les courbes (dans la fenêtre principale ou une autre), combien de buffers sont à réserver (un par signal, autrement appelé courbe, et huit maximum) et quelles sont les couleurs des courbes.</div>
<pre style="background-color: white; color: black; font-weight: bold;"><code>
<span style="color: blue;">#property indicator_chart_window</span>
<span style="color: blue;">#property indicator_buffers</span> <span style="color: #38761d;">1</span>
<span style="color: blue;">#property indicator_color1</span> <span style="color: #0b5394;">Aqua</span>
</code>
</pre>
<div style="text-align: justify; text-indent: 3em;">
Ces lignes ne sont pas du code, mais des instructions pour le préprocesseur car elles commencent par le signe dièse. Et c'est pour ça qu'il n'y a pas de point-virgule à la fin de chaque ligne. MetaTrader saura ce que ces lignes veulent dire. La dernière fonction à voir est celle-ci: <b style="background-color: #fff2cc;"><code><span style="color: #674ea7;">IndicatorCounted</span><span style="color: black;">()</span></code></b>. Cette fonction nous donne le nombre de chandeliers qui n'ont pas changé depuis la dernière fois que l'indicateur a été lancé. Il faut l'utiliser pour éviter à MetaTrader de faire trop de calculs inutiles. Les tampons contiennent toujours les valeurs, et il est inutile de tout recalculer si ça n'a pas changé. On récupère donc ce nombre pour savoir le nombre de chandeliers qu'il ne faut pas refaire. Et ce nombre est sûrement différent du nombre fourni par la variable prédéfinie <b><span style="color: magenta;"><code>Bars</code></span></b> qui est le nombre de chandeliers ou barres (bars) dans l'historique du graphique, modifiés ou non. Ça suffit largement, le compte est bon pour aujourd'hui, ça fait pas mal d'informations à digérer. Je vous le fais faire en tutoriel vidéo, puis je vous donne le code complet.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://img.youtube.com/vi/umGv_yTr2_o/1.jpg" height="360" width="480"><param name="movie" value="http://youtube.googleapis.com/v/umGv_yTr2_o&source=uds" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="480" height="360" src="http://youtube.googleapis.com/v/umGv_yTr2_o&source=uds" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| testsIndicateur.mq4 |
//| Copyright 2013, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2013, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;"> "http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: blue;">#property indicator_chart_window</span>
<span style="color: blue;">#property indicator_buffers</span> <span style="color: #38761d;">1</span>
<span style="color: blue;">#property indicator_color1</span> <span style="color: #0b5394;">Aqua</span>
<span style="color: blue;">extern int</span> shift = <span style="color: #38761d;">0</span>;
<span style="color: blue;">double</span> buffer[];
<span style="color: blue;">int</span> ancienCompteBars, nbTicksDansBar;
<span style="color: blue;">double</span> sommeCours;
<span style="color: blue;">double</span> obtenirCoursActuel() {
<span style="color: blue;">double</span> cours = (<span style="color: magenta;">Bid</span> + <span style="color: magenta;">Ask</span>) / <span style="color: #38761d;">2.0</span>;
<span style="color: blue;">return</span>(cours);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> init()
{
ancienCompteBars = <span style="color: #674ea7;">IndicatorCounted</span>();
<span style="color: #674ea7;">IndicatorDigits</span>(<span style="color: #674ea7;">MarketInfo</span>(<span style="color: #674ea7;">Symbol</span>(),<span style="color: #0b5394;">MODE_DIGITS</span>));
<span style="color: #674ea7;">IndicatorShortName</span>(<span style="color: #45818e;">"TM"</span>);
<span style="color: #674ea7;">SetIndexStyle</span>(<span style="color: #38761d;">0</span>,<span style="color: #0b5394;">DRAW_LINE</span>);
<span style="color: #674ea7;">SetIndexBuffer</span>(<span style="color: #38761d;">0</span>,buffer);
<span style="color: #674ea7;">SetIndexShift</span>(<span style="color: #38761d;">0</span>,shift);
<span style="color: #674ea7;">SetIndexDrawBegin</span>(<span style="color: #38761d;">0</span>,<span style="color: #38761d;">0</span>);
sommeCours = <span style="color: #38761d;">0.0</span>;
nbTicksDansBar = <span style="color: #38761d;">0</span>;
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> deinit()
{
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> start()
{
<span style="color: blue;">double</span> coursActuel = obtenirCoursActuel();
<span style="color: blue;">double</span> moyenneCours = coursActuel;
<span style="color: blue;">int</span> nbBarsActuel = <span style="color: #674ea7;">IndicatorCounted</span>();
<span style="color: blue;">if</span>(nbBarsActuel < ancienCompteBars) {
<span style="color: blue;">if</span>(nbTicksDansBar > <span style="color: #38761d;">0</span>) { moyenneCours = sommeCours / nbTicksDansBar; }
buffer[<span style="color: #38761d;">1</span>] = moyenneCours;
sommeCours = <span style="color: #38761d;">0.0</span>;
nbTicksDansBar = <span style="color: #38761d;">0</span>;
ancienCompteBars = nbBarsActuel;
}
sommeCours += coursActuel;
nbTicksDansBar++;
buffer[<span style="color: #38761d;">0</span>] = sommeCours / nbTicksDansBar;
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+ </span>
<!--0--><!--0--><!--0--></code>
</pre>
<div style="text-align: justify; text-indent: 3em;">
Nous allons améliorer cet indicateur dès le prochain post. J'espère que celui-ci vous a été profitable, à la prochaine ;)</div>
Unknownnoreply@blogger.com4tag:blogger.com,1999:blog-5819740724101841193.post-61975054788922163862013-08-13T13:29:00.000+02:002014-01-24T08:32:37.752+01:00Débuggage et reformulation d'algorithme<div style="text-align: justify; text-indent: 3em;">
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 !</div>
<br />
<h3>
Le problème du choix de la taille du tableau:
</h3>
<div style="text-align: justify; text-indent: 3em;">
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.</div>
<br />
<h3>
Traitements inutiles:
</h3>
<div style="text-align: justify; text-indent: 3em;">
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.</div>
<br />
<h3>
Améliorations:
</h3>
<div style="text-align: justify; text-indent: 3em;">
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.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='480' height='360' src='https://www.youtube.com/embed/TgcjvI4F7TA?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: gold; padding: 1em;"><code>
<span style="color: #999999;">//+------------------------------------------------------------------+
//| moyenneParSeconde2.mq4 |
//| Copyright 2013, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2013, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;"> "http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: blue;">datetime</span> tempsEnCoursTraitement, tempsTickActuel;
<span style="color: blue;">double</span> sommeCours;
<span style="color: blue;">int</span> nbTicksDansSeconde;
<span style="color: blue;">string</span> NOM_LABEL = <span style="color: #45818e;">"moyenne"</span>;
<span style="color: blue;">int</span> TAILLE_TEXTE = <span style="color: #38761d;">10</span>;
<span style="color: blue;">string</span> FONTE = <span style="color: #45818e;">"Arial"</span>;
<span style="color: blue;">double</span> obtenirCoursActuel() {
<span style="color: blue;">double</span> cours = (<span style="color: magenta;">Bid</span> + <span style="color: magenta;">Ask</span>) / <span style="color: #38761d;">2.0</span>;
<span style="color: blue;">return</span>(cours);
}
<span style="color: blue;">void</span> creerLabel(<span style="color: blue;">string</span> nom, <span style="color: blue;">int</span> x, <span style="color: blue;">int</span> y) {
<span style="color: blue;">bool</span> aReussi = <span style="color: #674ea7;">ObjectCreate</span>(nom, <span style="color: #0b5394;">OBJ_LABEL</span>, <span style="color: #38761d;">0</span>, x, y);
<span style="color: blue;">if</span>(aReussi) { <span style="color: #674ea7;">ObjectSetText</span>(nom, <span style="color: #45818e;">"###"</span>, TAILLE_TEXTE, FONTE, <span style="color: #0b5394;">White</span>); }
<span style="color: blue;">else</span> { <span style="color: #674ea7;">Print</span>(<span style="color: #45818e;">"Erreur à la création du texte: "</span>, <span style="color: #674ea7;">GetLastError</span>()); }
}
<span style="color: blue;">void</span> effacerObjetsGraphiques() {
<span style="color: blue;">int</span> nbObjetsEffaces = <span style="color: #674ea7;">ObjectsDeleteAll</span>();
<span style="color: #674ea7;">Print</span>(nbObjetsEffaces, <span style="color: #45818e;">" objets graphiques effacés !"</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> init()
{
tempsEnCoursTraitement = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #674ea7;">Symbol</span>(), <span style="color: #0b5394;">MODE_TIME</span>);
sommeCours = <span style="color: #38761d;">0.0</span>;
nbTicksDansSeconde = <span style="color: #38761d;">0</span>;
creerLabel(NOM_LABEL, <span style="color: #38761d;">1</span>,<span style="color: #38761d;">1</span>);
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| expert deinitialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> deinit()
{
effacerObjetsGraphiques();
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> start()
{
<span style="color: blue;">double</span> moyenneCours = <span style="color: #38761d;">0.0</span>;
tempsTickActuel = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #674ea7;">Symbol</span>(), <span style="color: #0b5394;">MODE_TIME</span>);
<span style="color: blue;">if</span>(tempsTickActuel > tempsEnCoursTraitement) {
<span style="color: blue;">if</span>(nbTicksDansSeconde > <span style="color: #38761d;">0</span>) { moyenneCours = sommeCours / nbTicksDansSeconde; }
<span style="color: #674ea7;">ObjectSetText</span>(NOM_LABEL, <span style="color: #674ea7;">DoubleToStr</span>(moyenneCours, <span style="color: #38761d;">5</span>), TAILLE_TEXTE, FONTE, <span style="color: #0b5394;">White</span>);
sommeCours = <span style="color: #38761d;">0.0</span>;
nbTicksDansSeconde = <span style="color: #38761d;">0</span>;
tempsEnCoursTraitement = tempsTickActuel;
}
sommeCours += obtenirCoursActuel();
nbTicksDansSeconde++;
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span>
</code>
</pre>
<div style="text-align: justify; text-indent: 3em;">
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.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-72565345095275892482013-08-09T13:59:00.001+02:002014-01-24T08:33:16.863+01:00Passage de valeur par référence en MQL4: initiation à la programmation d'experts advisors<div style="text-align: justify; text-indent: 3em;">
Enfin ! Le dernier post sur l'initiation au langage MQL4. Nous allons poursuivre l'amélioration de l'expert advisor qui calcule la moyenne du cours à chaque seconde. Pour cela nous allons continuer à le restructurer avec des fonctions. On va faire deux fonctions ici. Lors de la déinitialisation nous avons trois lignes de code qui ne servent qu'à une seule chose: effacer les objets graphiques. Une seule tâche en fait ! Comme il n'y a qu'une tâche que réalisent ensemble ces instructions, c'est typiquement ce que nous devrions mettre dans une fonction. Il y a aussi la fonction start() qui est surchargée, et au milieu un groupe d'instructions a pour but de calculer la moyenne. Ça doit aussi aller dans une fonction, et en plus c'est un calcul qui se fait en plusieurs étapes. Donc à isoler dans une fonction spécialisée.</div>
<br />
<h3>
La suppression des objets graphiques:
</h3>
<div style="text-align: justify; text-indent: 3em;">
Pour supprimer les objets graphiques, il y a une fonction MQL4 spécialisée: ObjectsDeleteAll(). Mais il faut faire quelques étapes supplémentaires: récupérer le nombre d'éléments effacés que la fonction nous renvoie et afficher ce nombre avec un message pour constater ce qui a été fait. C'est ce que font les trois lignes de code dans la fonction deinit() pour l'instant. On va isoler ces trois lignes dans une fonction, comme ça dans la fonction deinit() on dit clairement qu'on efface les objets graphiques en un appel de fonction. Il y a un avantage supplémentaire: on peut réutiliser cette fonction ailleurs, dans un autre programme. Aucun paramètre n'est nécessaire, donc la paire de parenthèses restera vide, et la fonction ne retourne aucune valeur, on la déclare alors de type 'void'. On va en plus réduire la quantité de code en condensant la première ligne (déclaration de la variable) avec la seconde (exécution de la fonction d'effacement et récupération de la valeur de retour) en une seule ligne. Le code de la nouvelle fonction est alors le suivant:
</div>
<pre style="background-color: white; color: black; font-weight: bold;"><code>
<span style="color: blue;">void</span> effacerObjetsGraphiques() {
<span style="color: blue;">int</span> nbObjetsEffaces = <span style="color: #674ea7;">ObjectsDeleteAll</span>();
<span style="color: #674ea7;">Print</span>(nbObjetsEffaces, <span style="color: #45818e;">" objets graphiques effacés !"</span>);
}
</code></pre>
<br />
<div style="text-align: justify; text-indent: 3em;">
Et le code dans la fonction deinit() pour appeler cette fonction sera simplement: <code style="background-color: white; color: black; font-weight: bold;">effacerObjetsGraphiques();</code> c'est tout !
</div>
<br />
<h3>
Le calcul de la moyenne des valeurs d'un tableau:
</h3>
<div style="text-align: justify; text-indent: 3em;">
Et maintenant la dernière fonction à faire, la plus attendue et la plus nécessaire: faire le calcul de la moyenne des cours à part dans sa propre fonction pour éclaircir ce code confus. Mais il y a un problème: il faut passer le tableau qui contient les valeurs en paramètre de la fonction. Il y a une chose à savoir quand on programme: c'est comment sont passés les paramètres d'une fonction. En général avec une copie de la valeur originale. Oui, une copie parce que les paramètres qu'on passe à une fonction doivent être stockés temporairement dans la pile d'appel des fonctions. Le mécanisme interne est le suivant: on exécute du code, et à un moment donné il faut aller dans une fonction et son code est ailleurs en mémoire. Il faut donc mémoriser où on en est dans le code, on place donc l'adresse mémoire où on doit revenir après la fonction dans une zone spécialisée: la pile des appels. On dit qu'on empile l'adresse de retour. Mais une fois qu'on passe au code de la fonction, elle ne sait pas où aller prendre les valeurs dont elle a besoin, car on peut venir de n'importe où. Alors on copie les paramètres de la fonction dans la pile aussi, et la fonction sait combien elle doit en prendre puisque ça la concerne. On copie donc les valeurs des paramètres dans la pile, on les empile aussi. (comme une pile d'assiettes) Et la fonction les dépile pour les utiliser. Elle dépilera à la fin l'adresse de retour qui s'était retrouvée en dessous pour pouvoir revenir là où on en était avant de passer à la fonction. Avec ce mécanisme on peur imbriquer les sauts à des fonctions: les adresses de retour et paramètres vont s'empiler les uns sur les autres, il suffira de dépiler dans l'ordre pour revenir. Mais la pile a une taille finie, on ne peut pas faire ça indéfiniment. Et avec les tableaux ça pose problème: ils sont en général très grands et peuvent facilement saturer la pile d'appel. Normal, ils sont prévus pour stocker de grandes quantités de données ! Ça pose d'autant plus problème qu'il faut en plus copier toutes les valeurs et ça prend du temps. Avec le MQL4, les tableaux seront la plupart du temps très grands: ils contiennent toutes les valeurs de l'historique des cours, des indicateurs etc. Il y a donc une autre manière de passer des paramètres à une fonction, et qui en plus peut s'avérer pratique même si le paramètre n'est pas un tableau: le passer par référence. C'est-à-dire qu'on passe non pas la valeur, mais l'adresse de l'endroit où est stocké le paramètre. On empile donc un nombre entier de 4 octets (pour nos ordinateurs actuels. Si la mémoire venait à augmenter très fortement en taille, il faudrait augmenter ça). La fonction sait que c'est une adresse qu'elle reçoit car on lui a indiqué, elle ira donc chercher la valeur au bon endroit. Comme cela pas de soucis de saturation de la pile des appels et pas de perte de temps à tout recopier inutilement. Il y a un effet intéressant en plus: comme normalement on passe un paramètre par copie, si on fait des changements dessus, ce sera sur la copie interne à la fonction et les changements ne se verront pas à l'extérieur sur la variable originale une fois que la fonction aura fini. Si le paramètre est passé par référence, la fonction va travailler sur l'original et les changements seront fait sur l'orignal qui reste une fois que la fonction a fini. Cet effet est intéressant pour tout type de paramètre. Voilà pour les explications. On indique à la fonction qu'on lui passe un paramètre par référence en mettant un esperluette (&) devant le nom. Par exemple: <code style="background-color: white; color: black; font-weight: bold;"><span style="color: blue;">void</span> nomFonction(<span style="color: blue;">int</span> &parametre) { bloc de la fonction }</code> Pour notre cas à nous, le tableau n'est pas très grand, même petit car il a seulement dix éléments à 8 octets chacun (double) et ça fait déjà 10x8 = 80 octets à empiler pour l'appel de la fonction, sans compter les autres paramètres. On va alors le passer par référence (il n'y aura que les 4 octets de l'adresse à empiler). On doit également passer un nombre qui est la quantité d'éléments à prendre dans le tableau à partir du début car on n'utilise pas toutes les cases.
</div>
<pre style="background-color: white; color: black; font-weight: bold;"><code>
<span style="color: blue;">double</span> calculerMoyenne(<span style="color: blue;">double</span> &valeurs[], <span style="color: blue;">int</span> effectif) {
<span style="color: blue;">int</span> noElement;
<span style="color: blue;">double</span> somme = <span style="color: #38761d;">0</span>, moyenne = <span style="color: #38761d;">0</span>;
<span style="color: blue;">for</span>(noElement=<span style="color: #38761d;">0</span> ; noElement<effectif ; noElement++) {
somme += valeurs[noElement];
}
<span style="color: blue;">if</span>(noElement != <span style="color: #38761d;">0</span>) { moyenne = somme / effectif; }
<span style="color: blue;">return</span>(moyenne);
}
</code></pre>
<br />
<div style="text-align: justify; text-indent: 3em;">
Et le code dans la fonction start() pour appeler cette fonction sera simplement:
</div>
<br />
<code style="background-color: white; color: black; font-weight: bold;">moyenneCours = calculerMoyenne(ticksDeLaSeconde, nbTickDansSeconde);</code>
<br />
<br />
<div style="text-align: justify; text-indent: 3em;">
Voilà pour cette restructuration du code. On va y voir bien plus clair. Vous allez le faire en vidéo avec moi: je vous montre et vous faites pareil. Le code complet en exemple après la vidéo.
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='480' height='360' src='https://www.youtube.com/embed/CzBspufeM4w?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold; padding: 1em;"><code><span style="color: #999999;">
//+------------------------------------------------------------------+
//| moyenneParSeconde.mq4 |
//| Copyright 2013, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2013, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: blue;">double</span> ticksDeLaSeconde[<span style="color: #38761d;">10</span>];
<span style="color: blue;">int</span> nbTickDansSeconde;
<span style="color: blue;">datetime</span> tempsEnCoursTraitement, tempsTickActuel;
<span style="color: blue;">double</span> obtenirCoursActuel() {
<span style="color: blue;">double</span> cours = (<span style="color: magenta;">Bid</span> + <span style="color: magenta;">Ask</span>) / <span style="color: #38761d;">2.0</span>;
<span style="color: blue;">return</span>(cours);
}
<span style="color: blue;">void</span> creerLabel(<span style="color: blue;">string</span> nom, <span style="color: blue;">int</span> x, <span style="color: blue;">int</span> y) {
<span style="color: blue;">bool</span> aReussi = <span style="color: #674ea7;">ObjectCreate</span>(nom, <span style="color: #0b5394;">OBJ_LABEL</span>, <span style="color: #38761d;">0</span>, x, y);
<span style="color: blue;">if</span>(aReussi) { <span style="color: #674ea7;">ObjectSetText</span>(nom, <span style="color: #45818e;">"###"</span>, <span style="color: #38761d;">10</span>); }
<span style="color: blue;">else</span> { <span style="color: #674ea7;">Print</span>(<span style="color: #45818e;">"Erreur à la création du texte: "</span>, <span style="color: #674ea7;">GetLastError</span>()); }
}
<span style="color: blue;">void</span> effacerObjetsGraphiques() {
<span style="color: blue;">int</span> nbObjetsEffaces = <span style="color: #674ea7;">ObjectsDeleteAll</span>();
<span style="color: #674ea7;">Print</span>(nbObjetsEffaces, <span style="color: #45818e;">" objets graphiques effacés !"</span>);
}
<span style="color: blue;">double</span> calculerMoyenne(<span style="color: blue;">double</span> &valeurs[], <span style="color: blue;">int</span> effectif) {
<span style="color: blue;">int</span> noElement;
<span style="color: blue;">double</span> somme = <span style="color: #38761d;">0</span>, moyenne = <span style="color: #38761d;">0</span>;
<span style="color: blue;">for</span>(noElement=<span style="color: #38761d;">0</span> ; noElement<effectif ; noElement++) {
somme += valeurs[noElement];
}
<span style="color: blue;">if</span>(noElement != <span style="color: #38761d;">0</span>) { moyenne = somme / effectif; }
<span style="color: blue;">return</span>(moyenne);
}
<span style="color: #999999;">
//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> init()
{
nbTickDansSeconde = <span style="color: #38761d;">0</span>;
tempsEnCoursTraitement = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #674ea7;">Symbol</span>(), <span style="color: #073763;">MODE_TIME</span>);
creerLabel(<span style="color: #45818e;">"moyenne"</span>, <span style="color: #38761d;">2</span>, <span style="color: #38761d;">5</span>);
<span style="color: #999999;">//+------------------------------------------------------------------+
//| expert deinitialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> deinit()
{
effacerObjetsGraphiques();
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> start()
{
tempsTickActuel = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #674ea7;">Symbol</span>(), <span style="color: #073763;">MODE_TIME</span>);
<span style="color: blue;">if</span>(tempsTickActuel > tempsEnCoursTraitement) {
<span style="color: blue;">double</span> moyenneCours = calculerMoyenne(ticksDeLaSeconde, nbTickDansSeconde);
<span style="color: #674ea7;">ObjectSetText</span>(<span style="color: #45818e;">"moyenne"</span>, <span style="color: #674ea7;">DoubleToStr</span>(moyenneCours, <span style="color: #38761d;">5</span>), <span style="color: #38761d;">10</span>);
tempsEnCoursTraitement = tempsTickActuel;
nbTickDansSeconde = <span style="color: #38761d;">0</span>;
}
ticksDeLaSeconde[nbTickDansSeconde] = obtenirCoursActuel();
nbTickDansSeconde++;
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span>
</code></pre>
<div style="text-align: justify; text-indent: 3em;">
La fonction start() est désormais bien plus claire à lire et comprendre. Il faudrait pour parfaire ce code déplacer et classer les fonctions créées dans d'autres fichiers, du type librairie pour pouvoir être utilisées partout. Ce que nous ferons plus tard, quand nous maîtriserons mieux les bases du langage MQL4. Il faut pour l'instant pratiquer, c'est important. Nous allons donc dans les prochains posts créer des petits experts et des indicateurs pour obtenir des outils interressants avant de faire un robot complet. Cette façon de faire nous permettra premièrement de maîtriser le langage et deuxièmement de faire un peu de recherches de pistes pour l'analyse des cours et de trouver de nouvelles façons de faire. Il faut innover un peu et dépoussierer le domaine ! Je rappelle l'objectif: être rentier par le forex, ce ne sont pas des mots en l'air, jettés pour attirer du monde mais bel et bien l'objectif accessible à toute personne qui se donnera la peine d'apprendre tout ceci. Il y aura les codes de robots fonctionnels et qui rapportent de manière exponentielle fournis grauitement dans les vidéos et les posts. Mais il faudra comprendre et maîtriser le sujet pour être sûr de les faire fonctionner dans la durée et pouvoir réagir en cas de problème. Regardez bien sur web: dans les forums ceux qui achètent des robots sans réellement comprendre ce que les robots font et comment ils le font, n'arrivent pas en général à les faire fonctionner. Par contre les développeurs qui savent en programmer, en achètent aussi et arrivent à les faire fonctionner. (dans les blogs ou sites spécialisés) C'est pour cela que je vous fais apprendre tout ça: que vous soyez capable de faire fonctionner les robots que nous allons faire ici et de réagir face aux problèmes. En plus ces robots achetés ne donnent pas de miracles mais ils rapportent déjà beaucoup plus que l'intérêt miséreux annuel que vous donne votre banquier. Qui vous ment par ailleurs, il se fout de votre gueule en disant qu'il ne peut pas vous donner plus parce que c'est la crise, et que tout s'agite en bourse. Si vous avez bien compris comment ça fonctionne vous savez alors que plus ça bouge et plus ça rapporte: les gains se font avec les variations, et plus elles sont nombreuses et fortes et plus ça tombe dans la poche !</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-11919339013040782982013-08-08T22:42:00.000+02:002014-01-24T08:33:52.907+01:00Les fonctions en MQL4: initiation à la programmation d'experts advisors<div style="text-align: justify; text-indent: 3em;">
Et voilà la dernière notion à connaître pour compléter l'initiation à la programmation en MQL4: les fonctions. Vous les avez déjà vu en écrivant le code dans les fonctions init(), deinit() et start(). Vous écrivez le code de ces fonctions mais, vous ne les utilisez pas ! C'est MetaTrader 4 qui le fait au moment voulu. Vous en avez utilisé d'autres toutes prêtes qui se coloraient en violet quand vous écriviez leur nom. Elles vous font un travail, un calcul sans que vous ayez le besoin d'écrire tout le code qui fait ce travail ou calcul. Désormais vous allez écrire vos propres fonctions pour que votre code soit structuré et mieux organisé. Pour que vous puissiez réutiliser un bout de code dans d'autres programmes. Si vous deviez tout mettre dans un seul bloc d'instructions, ce serait illisible et incompréhensible tellement il y aurait des instructions à la chaine. Le principe est de fractionner les instructions, de les regrouper en fonctions de leur objectif. Une série d'instructions qui servent à un but unique, à réaliser une chose ou un calcul doit se mettre dans une fonction pour éclaircir le code et le rendre réutilisable.</div>
<br />
<div style="text-align: justify; text-indent: 3em;">
Une fonction doit se déclarer, s'écrire (toutes les instructions qu'elle contient) et s'utiliser. D'abord on les utilise en écrivant leur nom avec une paire de parenthèses qui encadrent zéro, un ou plusieurs paramètres qu'elle peut recevoir pour faire son travail. Elle peut retourner une valeur, surtout si elle fait un calcul car il nous faut le résultat. Et donc le nom de la fonction avec sa paire de parenthèses et ses paramètres deviennent alors la valeur qu'elle retourne, une fois le travail ou calcul fait. Cette valeur il faut donc la récupérer dans une variable ou la placer dans un calcul. <code style="background-color: white; color: black; font-weight: bold;">resultat = nomFonction(parametres);</code> Dans cet exemple '<i>nomFonction(parametres)</i>' est devenu la valeur de retour, et on l'affecte donc à la variable resultat.</div>
<br />
<div style="text-align: justify; text-indent: 3em;">
Comme je le disais précédemment, une fonction se déclare et s'écrit. Puisque la fonction, quand on l'utilise, devient la valeur de retour, il faut la déclarer comme une variable. C'est-à-dire avec un type devant, celui de la valeur de retour. Si elle ne retourne aucune valeur, il faut mettre le type 'void', qu'on pourrait considérer comme le type 'vide'. Il faut aussi déclarer les paramètres qu'elle reçoit, si elle doit en recevoir. Ces paramètres sont des variables valables uniquement à l'intérieur de la fonction, et se déclarent comme des variables normales entre les parenthèses. On peut même leur mettre une valeur par défaut avec un égal et la valeur. Il n'y a pas obligation de passer un paramètre lors de l'appel de la fonction s'il a une valeur par défaut. <code style="background-color: white; color: black; font-weight: bold;">resultat = nomFonction(<span style="color: blue;">int</span> parametre1, <span style="color: blue;">string</span> parametre2, <span style="color: blue;">bool</span> parametre3=<span style="color: blue;">false</span>);</code> Dans cet exemple il sera obligatoire de fournir les deux premiers paramètres mais pas le troisième. Les paramètres ayant une valeur par défaut doivent être à la fin de la liste des paramètres. Les noms parametre1, parametre2 et parametre3 seront des variables utilisables avec les instructions de la fonction à l'intérieur de celle-ci uniquement. Et il vaut mieux les utiliser si on veut récupérer ces paramètres. En Programmation les paramètres s'appellent les arguments de la fonction.</div>
<br />
<div style="text-align: justify; text-indent: 3em;">
Et une fonction s'écrit. Il faut évidemment écrire les instructions qui composent la fonction, puisqu'elle à un travail à faire, et il faut lui dire comment le faire. Après la parenthèse fermante des arguments on place une accolade ouvrante pour commencer le bloc des instructions. On peut déclarer toutes les variables dont on aura besoin, et elles seront utilisables uniquement dans la fonction, dans ce bloc. On doit aussi utiliser les arguments qui sont des variables comme les autres, s'il y en a et si on veut accéder aux paramètres qu'on a fourni à la fonction pour s'exécuter. On place évidemment les instructions qui vont faire le travail ou calcul. Puis là où on veut, en général à la fin, on place une instruction 'return' pour retourner la valeur calculée. Ce n'est pas obligatoire si la fonction est du type void. Le return signifie d'arrêter l'exécution de la fonction et de renvoyer la valeur qu'on place entre les parenthèses du return. Et à la fin on ferme l'accolade pour terminer le bloc de la fonction.
<br />
<pre style="background-color: white; color: black;"> <code style="font-weight: bold;">
<span style="color: blue;">int</span> nomFonction(<span style="color: blue;">int</span> parametre1, <span style="color: blue;">string</span> parametre2, <span style="color: blue;">bool</span> parametre3=<span style="color: blue;">false</span>) {
déclarations variables si besoin;
instruction 1;
instruction 2;
...
instruction n;
<span style="color: blue;">return</span>(valeur calculée); <span style="color: #999999;">//(optionnel)</span>
}
</code></pre>
</div>
<br />
<div style="text-align: justify; text-indent: 3em;">
Nous allons de suite voir deux exemples sur l'expert advisor créé précédemment et qui calcule la moyenne du cours à chaque seconde. Il y a au moins quatre fonctions à faire. Nous allons en faire deux pour ce post, les deux autres seront pour le post suivant. Première chose: le calcul du cours actuel qui est la moyenne du bid et du ask, est un calcul que nous avons fait à plusieurs reprises. Nous allons le mettre dans une fonction, comme ça nous n'aurons plus qu'à appeler cette fonction, et comme son nom sera explicite, ça nous dira clairement ce qu'on fait dans le code. Il y a aussi lors de l'initialisation trois lignes de codes qui ont le même objectif ensemble: créer un label sur le graphique. Nous allons aussi en faire une fonction, et comme ça dans le code nous aurons une seule ligne pour appeler la fonction ce qui nous dira clairement ce qu'on fait. Et en plus cette création de label sur le graphique sera réutilisable dans d'autres programmes.</div>
<br />
<h3>
Le calcul du cours réel actuel par la moyenne du bid et du ask:</h3>
<div style="text-align: justify; text-indent: 3em;">
Cette fonction est très simple: elle ne prend pas de paramètres puisqu'elle n'utilise que Bid et Ask, les variables prédéfinies partout. Elle renvoie évidemment une valeur, le réusltat qu'on attend. On va donc la déclarer comme une valeur de type décimal: double et créer à l'intérieur une variable cours qui contient le résultat. On y affecte le résultat du calcul et on renvoie cette variable cours dans le return. La fonction est très courte:</div>
<pre style="background-color: white; color: black;"> <code style="font-weight: bold;">
<span style="color: blue;">double</span> obtenirCoursActuel() {
<span style="color: blue;">double</span> cours = (<span style="color: magenta;">Bid</span> + <span style="color: magenta;">Ask</span>) / <span style="color: #38761d;">2.0</span>;
<span style="color: blue;">return</span>(cours);
}
</code></pre>
<div style="text-align: justify; text-indent: 3em;">
Le résultat du calcul de la moyenne du bid et du ask est affecté à la variable cours (déclarée en même temps sur la ligne). Puis on renvoie cette valeur avec le return. C'est tout. Et la ligne qui avait ce calcul avant:</div>
<code style="background-color: white; color: black; font-weight: bold;">ticksDeLaSeconde[nbTickDansSeconde] = (<span style="color: magenta;">Bid</span> + <span style="color: magenta;">Ask</span>) / <span style="color: #38761d;">2</span>;</code>
<br />
devient:
<br />
<code style="background-color: white; color: black; font-weight: bold;">ticksDeLaSeconde[nbTickDansSeconde] = obtenirCoursActuel();</code>
<br />
<br />
<h3>
La création d'un label sur un graphique:</h3>
<div style="text-align: justify; text-indent: 3em;">
Cette fonction utilise les trois lignes de codes où on crée le label avec une fonction spéciale qui nous renvoie un vrai ou faux pour dire si ça a réussi. On récupère cette valeur booléenne dans une variable déclarée en même temps. Le tout sur la même ligne. Puis on teste si c'est vrai, on met alors un texte par défaut, et si c'est faux on met un message d'erreur. Mais cette fonction doit pouvoir être utilisable dans d'autres programmes, alors le nom du label "moyenne" ne peut pas être utilisé, ce sera donc un paramètre de la fonction, tout comme les coordonnées x et y. La valeur du texte par défaut doit changer aussi, car "0.00000" est très spécifique à notre cas et ce ne sera pas forcément un nombre qu'on voudra afficher. Il faut donc mettre quelque chose de neutre comme "###" pour montrer que le label est bien là. (on aurait pu faire aussi un paramètre, mais trop de paramètres tue la lisibilité de l'appel à la fonction. On peut se passer de celui-là).</div>
<pre style="background-color: white; color: black;"> <code style="font-weight: bold;">
<span style="color: blue;">void</span> creerLabel(<span style="color: blue;">string</span> nom, <span style="color: blue;">int</span> x, <span style="color: blue;">int</span> y) {
<span style="color: blue;">bool</span> aReussi = <span style="color: #674ea7;">ObjectCreate</span>(nom, <span style="color: #0b5394;">OBJ_LABEL</span>, <span style="color: #38761d;">0</span>, x, y);
<span style="color: blue;">if</span>(aReussi) { <span style="color: #674ea7;">ObjectSetText</span>(nom, <span style="color: #45818e;">"###"</span>, <span style="color: #38761d;">10</span>); }
<span style="color: blue;">else</span> { <span style="color: #674ea7;">Print</span>(<span style="color: #45818e;">"Erreur à la création du texte: "</span>, <span style="color: #674ea7;">GetLastError</span>()); }
}
</code></pre>
<div style="text-align: justify; text-indent: 3em;">
La fonction ObjectCreate réalise le travail principal pour nous en utilisant la variable 'nom' qui contient le nom de l'objet qu'on veut créer passé en paramètre. On lui passe aussi les coordonnées x et y passées en paramètres. Nous récupérons juste la valeur vrai ou faux pour réagir en fonction du résultat. On crée donc la variable booléenne aReussi sur la même ligne et on lui affecte directement la valeur en sortie de fonction. On teste ensuite avec le if si ça a réussi, si oui on met le texte par défaut, les trois dièses sur l'objet graphique qui porte évidemment le nom contenu dans la variable 'nom'. Et la dernière ligne qui est le cas contraire où on pet le message d'erreur. Rien n'a changé dans cette ligne. Pour utiliser la fonction on l'appelle simplement sans récupérer aucune valeur car elle n'en retourne pas :</div>
<code style="background-color: white; color: black; font-weight: bold;">creerLabel(<span style="color: #45818e;">"moyenne"</span>, <span style="color: #38761d;">2</span>, <span style="color: #38761d;">5</span>);</code>
<br />
<br />
<div style="text-align: justify; text-indent: 3em;">
Je vous montre ces modifications en vidéo, vous les faites avec moi. Ensuite le code complet.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='480' height='360' src='https://www.youtube.com/embed/rnRCngJADe8?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code><span style="color: #999999;">
//+------------------------------------------------------------------+
//| moyenneParSeconde.mq4 |
//| Copyright 2013, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2013, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: blue;">double</span> ticksDeLaSeconde[<span style="color: #38761d;">10</span>];
<span style="color: blue;">int</span> nbTickDansSeconde;
<span style="color: blue;">datetime</span> tempsEnCoursTraitement, tempsTickActuel;
<span style="color: blue;">double</span> obtenirCoursActuel() {
<span style="color: blue;">double</span> cours = (<span style="color: magenta;">Bid</span> + <span style="color: magenta;">Ask</span>) / <span style="color: #38761d;">2.0</span>;
<span style="color: blue;">return</span>(cours);
}
<span style="color: blue;">void</span> creerLabel(<span style="color: blue;">string</span> nom, <span style="color: blue;">int</span> x, <span style="color: blue;">int</span> y) {
<span style="color: blue;">bool</span> aReussi = <span style="color: #674ea7;">ObjectCreate</span>(nom, <span style="color: #0b5394;">OBJ_LABEL</span>, <span style="color: #38761d;">0</span>, x, y);
<span style="color: blue;">if</span>(aReussi) { <span style="color: #674ea7;">ObjectSetText</span>(nom, <span style="color: #45818e;">"###"</span>, <span style="color: #38761d;">10</span>); }
<span style="color: blue;">else</span> { <span style="color: #674ea7;">Print</span>(<span style="color: #45818e;">"Erreur à la création du texte: "</span>, <span style="color: #674ea7;">GetLastError</span>()); }
}
<span style="color: #999999;">
//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> init()
{
nbTickDansSeconde = <span style="color: #38761d;">0</span>;
tempsEnCoursTraitement = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #674ea7;">Symbol</span>(), <span style="color: #073763;">MODE_TIME</span>);
creerLabel(<span style="color: #45818e;">"moyenne"</span>, <span style="color: #38761d;">2</span>, <span style="color: #38761d;">5</span>);
<span style="color: #999999;">//+------------------------------------------------------------------+
//| expert deinitialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> deinit()
{
<span style="color: blue;">int</span> nbObjetsEffaces;
nbObjetsEffaces = <span style="color: #674ea7;">ObjectsDeleteAll</span>();
<span style="color: #674ea7;">Print</span>(nbObjetsEffaces, <span style="color: #45818e;">" objets graphiques effaces !"</span>);
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> start()
{
tempsTickActuel = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #674ea7;">Symbol</span>(), <span style="color: #073763;">MODE_TIME</span>);
<span style="color: blue;">if</span>(tempsTickActuel > tempsEnCoursTraitement) {
<span style="color: blue;">int</span> noTick;
<span style="color: blue;">double</span> sommeCours = <span style="color: #38761d;">0</span>, moyenneCours = <span style="color: #38761d;">0</span>;
<span style="color: blue;">for</span>(noTick=<span style="color: #38761d;">0</span> ; noTick<nbTickDansSeconde ; noTick++) {
sommeCours += ticksDeLaSeconde[noTick];
}
<span style="color: blue;">if</span>(noTick != <span style="color: #38761d;">0</span>) { moyenneCours = sommeCours / noTick; }
<span style="color: #674ea7;">ObjectSetText</span>(<span style="color: #45818e;">"moyenne"</span>, <span style="color: #674ea7;">DoubleToStr</span>(moyenneCours, <span style="color: #38761d;">5</span>), <span style="color: #38761d;">10</span>);
tempsEnCoursTraitement = tempsTickActuel;
nbTickDansSeconde = <span style="color: #38761d;">0</span>;
}
ticksDeLaSeconde[nbTickDansSeconde] = obtenirCoursActuel();
nbTickDansSeconde++;
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span>
</code></pre>
<div style="text-align: justify; text-indent: 3em;">
La fonction init() s'est bien allégée, elle est bien plus claire à lire et comprendre. On lit les intentions dans les noms des fonctions qu'on appelle. C'est pour cela que le nommage est très, très important. On continuera pour la fonction deinit() qui se simplifiera à l'extrême et la fonction start() qui en a bien besoin. Nous mettrons le calcul de la moyenne dans une fonction évidemment, ça allègera beaucoup. Nous verrons à l'occasion un point délicat à comprendre et à connaitre: comment passer un tableau en paramètre à une fonction, et plus généralement les deux manières de passer un paramètre à une fonction.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-64019375801997658842013-08-07T13:06:00.001+02:002013-08-09T14:55:34.210+02:00Les boucles for en MQL4: initiation à la programmation d'experts advisors<div style="text-align: justify; text-indent: 3em;">
Enfin la dernière instruction du langage à voir ! Ce post sera plus court, et la vidéo bien plus courte aussi. Nous allons utiliser cette instruction: la boucle for pour modifier l'expert précédemment fait et qui est bien compliqué. La boucle for remplacera la boucle while dans cet expert parce qu'elle est adaptée au parcours de tableaux. Elle sert aussi s'il ny a pas de tableau, et sert surtout si on a besoin d'un compteur ou indice quelconque qui doit évoluer à chaque répétition.</div>
<br />
<h3>
L'instruction for:
</h3>
<div style="text-align: justify; text-indent: 3em;">
L'instruction for est donc une boucle pour répéter un bloc d'instruction, avec un détail particulier: il y a dans l'histoire un indice ou un compteur qui doit évoluer à chaque répétition. Dans notre cas de l'expert précédent c'est le numéro de l'élément du tableau. Cette boucle for est pratique dans ces cas-là parce qu'elle prend en charge le compteur. Nous n'avons pas besoin de le faire évoluer par une instruction spécifique dans la boucle. On indique dans l'instruction for trois choses:</div>
<br />
<ol>
<li>l'initialisation du compteur: on donne sa valeur de départ.</li>
<li>la condition sur ce compteur pour répéter la boucle: elle doit être vraie pour exécuter le bloc d'instructions. Dès qu'elle est fausse, le bloc n'est pas exécuté et le programme suit son court après le bloc de l'instruction for.</li>
<li>la manière de faire évoluer ce compteur: une expression de calcul pour changer la valeur du compteur à chaque fois que le bloc d'instruction de la boucle est fini. </li>
</ol>
<br />
<div style="text-align: justify; text-indent: 3em;">
Voici directement un exemple: <code style="background-color: white; color: black; font-weight: bold;"><span style="color: blue;">for</span>(i=<span style="color: #38761d;">0</span> ; i<<span style="color: #38761d;">10</span> ; i=i+<span style="color: #38761d;">1</span>) { bloc d'instructions }</code>. Dans cet exemple on veut répéter le bloc d'instruction en commençant avec la variable i qui doit être d'abord égale à 0 et tant que cette variable i est inférieure à 10, et on fait varier i selon le calcul i = i + 1. C'est-à-dire qu'on prend i, on lui ajoute 1 et on remet le résultat dans i. En clair on augmente i de 1 à chaque fois. On peut si on veut, enlever 1 ou même ajouter 2 ou 7.3 ou faire ce qu'on veut pour le changer. Mais attention, il faut écrire quelque chose qui finira par rendre la condition fausse pour pouvoir s'arrêter ! Dans cet exemple, si on met le calcul de changement: i = i - 1, on atteindra jamais le 10 en partant de 0, puisque i ne fera que diminuer. Il vaudra -1, -2, -3 etc . La condition d'infériorité à 10 sera toujours vraie et donc on exécutera la boucle sans jamais s'arrêter.</div>
<br />
<div style="text-align: justify; text-indent: 3em;">
La boucle for s'utilise donc dès qu'il faut faire une boucle avec une variable qui va évoluer avec les répétitions de la boucle. Dans ce cas, on donne trois règle à l'instruction for: la valeur de départ, la condition pour répéter et comment l'évolution doit se faire, et l'instruction for se charge de tout. Maintenant je voudrais ajouter deux types d'écritures de calculs que nous n'avons pas encore vu et qui sont très pratiques: l'incrémentation condensée avec l'affectation et la post-incrémentation. Ces écritures vont êtres très pratiques pour la boucle for, et pour d'autres cas aussi.
</div>
<br />
<h3>
L'opérateur d'incrémentation et l'opérateur de décrémentation:
</h3>
<div style="text-align: justify; text-indent: 3em;">
Vous avez remarqué, nous avons souvent besoin de faire évoluer une variable en l'augmentant de 1 ou plus. Et on fait donc l'opération avec une affectation dans la même variable. Du genre i = i + 1. Il existe pour cela un opérateur dédié: += et l'exemple s'écrit alors i += 1. Cela se traduit littéralement par ajouter 1 et réaffecter dans la même variable. Nous avons la même chose avec la décrémentation: i -= 1. On pourrait augmenter ou diminuer de n'importe quelle quantité: i += 3.
</div>
<br />
<h3>
L'opérateur de post-incrémentation ou décrémentation:
</h3>
<div style="text-align: justify; text-indent: 3em;">
Il y a parmi les incrémentations ou décrémentations précédentes un cas qui est très très utilisé: l'incrémentation ou décrémentation de 1. Il y a alors l'opérateur dédié: ++, et on note l'opération sur la variable comme ça: i++ ce qui est très condensé. (Il y a la même en i--) Cette notation est très souvent utilisée pour la troisième règle de la boucle for, à la place de i = i + 1. i++ signifie tout simplement "augmenter i de 1". De même pour i-- qui signifie diminuer i de 1.
</div>
<br />
<h3>
Amélioration de l'expert des moyennes du cours par seconde:
</h3>
<div style="text-align: justify; text-indent: 3em;">
Nous allons commencer à modifier l'expert précédemment fait pour rendre le code plus compact et compréhensible. (nous continuerons encore dans les posts suivants) La boucle while va donc être remplacée par une boucle for puisqu'elle contient un compteur qui doit être incrémenté à chaque passage. C'est typiquement ce que gère une boucle for. Du coup l'instruction d'incrémentation de noTick dans la boucle ne sert plus à rien, et il vaut mieux l'enlever car elle va même perturber en incrémentant une fois de trop à chaque passage. On va donc la supprimer. On en profite aussi pour remplacer les incrémentations dans tout le code par les opérateurs qui conviennent. La boucle while sera donc remplacée par:</div>
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
<span style="color: blue;">for</span>(noTick=<span style="color: #38761d;">0</span> ; noTick<nbTickDansSeconde ; noTick++) {
sommeCours += ticksDeLaSeconde[noTick];
}</code></pre>
<div style="text-align: justify; text-indent: 3em;">
Du coup lors de la déclaration de noTick deux lignes plus haut, nous n'avons plus besoin de la mettre à zéro, car la boucle for s'en charge. Remarquez que j'ai utilisé la post-incrémentation dans la troisième règle de la boucle for et l'opérateur d'incrémentation pour la somme des cours dans la boucle. La dernière instruction de la fonction start(), juste avant le return passe de:</div>
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
nbTickDansSeconde = nbTickDansSeconde + <span style="color: #38761d;">1</span>;
</code></pre>
<div style="text-align: justify; text-indent: 3em;">
à ceci :</div>
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code>
nbTickDansSeconde++;
</code></pre>
<div style="text-align: justify; text-indent: 3em;">
Les améliorations ne sont pas très nombreuses pour le moment, mais c'est déjà ça ! Vous allez le pratiquer avec moi en vidéo, ce sera assez rapide.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='480' height='360' src='https://www.youtube.com/embed/c5W0vB927dI?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<div style="text-align: justify; text-indent: 3em;">
La prochaine fois nous ferons de plus grosses améliorations avec une dernière notion à travailler pour faire le tour complet de l'initiation à MQL4: les fonctions.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5819740724101841193.post-87941440912030977262013-08-06T22:56:00.001+02:002014-01-24T08:34:39.910+01:00Les tableaux en MQL4: initiation à la programmation d'experts advisors<div style="text-align: justify; text-indent: 3em;">
Avant de passer à la dernière instruction, on va voir l'une des deux dernières notions à connaître en programmation, et appliquée ici au langage MQL4. La dernière instruction à voir est très liée aux tableaux, et j'ai beau chercher des exemples pratiques (qui ont du sens, pas les exemples bidons classiques pour apprendre et qui ne servent strictement à rien), mais ceux qui me viennent avec cette instruction sans les tableaux, sont trop compliqués pour une initiation. Déjà que les posts précédents ont eu des exemples assez copieux. J'ai donc décidé de vous présenter les tableaux avant.</div>
<br />
<div style="text-align: justify; text-indent: 3em;">
Un tableau qu'est-ce-que c'est ? Il s'agit d'une variable, c'est-à-dire un emplacement en mémoire pour stocker des données, qui contient plusieurs données du même type alignées les unes à côté des autres. Donc dans une même zone de la mémoire, on place un petit ou grand nombre de valeurs du même type. Toutes ces valeurs portent donc le même nom puisqu'elles sont regroupées dans la même variable, et elles sont accessibles individuellement avec un numéro. Ce numéro, ou indice est un nombre entier qui commence à zéro ! Attention, IL COMMENCE A ZERO ! C'est une faute classique de débutants et même des expérimentés, que d'oublier ça quand on code (et c'est facile car on a plein de choses à penser). On appelle donc une valeur bien précise en appelant la variable avec un indice entre crochets: <b>nom_tableau[indice]</b>. La création et l'initialisation des tableaux se fait de plusieurs manières. Nous commencerons avec la plus simple: on déclare le type, le nom, des crochets dans lequels on indique le nombre d'éléments qu'on veut y stocker. Par exemple: <b><code style="background-color: white; color: black;"><span style="color: blue;">double</span> ticks[<span style="color: #38761d;">100</span>];</code></b> Ici on déclare un tableau appelé ticks, qui pourra contenir 100 nombres décimaux (double) et ils seront numérotés de 0 à ... 99 ! Et on l'utilise de cette manière: <b><code style="background-color: white; color: black;">ticks[<span style="color: #38761d;">4</span>] = <span style="color: #38761d;">1.2345</span>;</code></b> où on fixe la valeur du cinquième (eh oui, la numérotation commence à zéro) à 1,2345.</div>
<br />
<div style="text-align: justify; text-indent: 3em;">
Comme nous utiliserons souvent, très souvent les tableaux j'aurai le temps de bien vous expliquer en long en large et en travers ! Donc nous allons passer immédiatement à l'exemple d'un EA. Celui que je vais vous présenter est un peu complexe pour débuter, mais nous y reviendrons plusieurs fois et ce, dès le post suivant, pour l'améliorer, et pour que vous puissiez mieux le comprendre et le maîtriser. Je considère cet exemple important car il nous conduira à un indicateur très utile et mathématiquement plus valable que ceux existants. (j'expliquerai pourquoi). Le programme que nous allons faire va nous donner la moyenne arithmétique des ticks de chaque seconde. En général, dans la journée, il y a plusieurs ticks par seconde (2 à 3), nous allons donc ne retenir que la moyenne du cours à chaque seconde. Nous aurons alors un découpage temporel par seconde du cours filtré des bruits internes à la seconde. l'EA que nous allons faire n'enregistrera pas la moyenne de chaque seconde, il ne fera que les afficher. Ce qui nous permettra de voir des fonctions d'affichage. Alors ... comment résoudre ce problème ...?</div>
<br />
<div style="text-align: justify; text-indent: 3em;">
Premier réflexe: nous allons enregistrer les cours de la même seconde dans un tableau. Nous en prendrons un de 10
éléments ce qui devrait être suffisant. C'est le problème avec les tableaux en général: il faut fixer la taille à l'avance, même si on ne sait pas encore la taille qu'il nous faut. Et les langages qui permettent de modifier la taille en cours de traitement ne sont pas nombreux et s'ils le font, il faut savoir que ça coûte cher en temps pour le processeur et en mémoire. Agrandir un tableau, ça demande de réserver une autre place en mémoire (en général beaucoup) et de copier toutes les valeurs. (ça prend du temps s'il y en a beaucoup). Il vaut donc mieux éviter de s'amuser à ce genre de choses, surtout que pour le forex, les tableaux sont très grands: ils contiennent les cours et autres valeurs calculées par les indicateurs.</div>
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code><span style="color: blue;">double</span> ticksDeLaSeconde[<span style="color: #38761d;">10</span>];</code></pre>
<br />
<div style="text-align: justify; text-indent: 3em;">
Je disais donc qu'il faut enregistrer les valeurs du cours de la même seconde dans un tableau. Mais il faut pouvoir déterminer dans quelle seconde on est ! Il y a pour cela une fonction qui nous donnera le dernier temps envoyé par le serveur, celui qui correspond à la dernière mise à jour du cours. Ces valeurs de temps sont du type datetime. Ces valeurs sont des nombres entiers et elles correspondent au nombre de secondes écoulées depuis le 1<sup>er</sup> janvier 1970. (en informatique on nomme ça un timestamp, soit en français: horodatage.) Donc quand cette valeur de type datetime augmente de 1, cela signifie qu'il y a une seconde de plus. Il suffit donc de stocker la valeur du temps de la seconde en cours de traitement et de la comparer à celle du tick qui vient d'arriver, si c'est la même, on enregistre dans le tableau une valeur supplémentaire du cours. Dans le cas où elle n'est pas la même, elle est forcément plus grande ( ... quoi que ? Imaginons qu'un paquet qui transite sur internet fasse un chemin bien plus long et arrive après le tick suivant !!! Il faudra veiller à ça ) Je disais qu'elle est normalement plus grande, donc dans ce cas on calcule la moyenne des valeurs dans le tableau, ensuite on remet les compteurs à zéro et on enregistre la nouvelle valeur du cours de la nouvelle seconde qui vient d'arriver au début du tableau, et surtout on dit que le datetime en cours de traitement c'est celui qui vient d'arriver. Ne pas oublier ce détail!</div>
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code><span style="color: blue;">datetime</span> tempsEnCoursTraitement, tempsTickActuel;
tempsEnCoursTraitement = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #674ea7;">Symbol</span>(), <span style="color: #073763;">MODE_TIME</span>);</code></pre>
<br />
<div style="text-align: justify; text-indent: 3em;">
Dernier point du traitement principal: il faut nécessairement un compteur pour dire où nous en sommes dans le tableau, et ce compteur indiquera lorsque nous ne serons plus dans la même seconde combien de tick il y aura eu dans la seconde qui était en cours de traitement, ce qui nous permettra de calculer la moyenne.</div>
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code><span style="color: blue;">int</span> nbTickDansSeconde;</code></pre>
<br />
<div style="text-align: justify; text-indent: 3em;">
La moyenne ! Parlons-en, il faut la calculer. Comment faire ? Nous avons donc un tableau de 10 places maximum, qui contient des valeurs décimales en partant de l'indice 0. Nous avons aussi un compteur qui dit combien de valeurs il y a eu dans la seconde. On va donc additionner toutes ces valeurs puis diviser la somme par le nombre de valeurs additionnées. Ça c'est facile, voyons juste comment les additionner. On va prendre une somme qu'on initialise à zéro, puis on parcours le tableau et on additionne à cette somme la valeur rencontrée à chaque fois dans la case du tableau. Cette case du tableau est désignée par un compteur, et pas le même que le précédent car le compteur dont on a parlé juste avant contient le nombre de valeurs de la seconde et il doit nous servir pour la division. Il nous faut donc un autre compteur qu'on initialise à zéro et qui va parcourir les cases du tableau de zéro jusqu'au nombre de valeurs à additionner, c'est le compteur précédent qui la contient. Attention on ne doit pas aller jusqu'à l'égalité avec cette valeur car les numéros des cases du tableau sont décalés, ils commencent à zéro. Pour calculer cette moyenne on prendra une boucle while qu'on a vu précédemment, la condition pour répéter sera que le compteur qui part de zéro doit être inférieur au nombre de ticks de la seconde en cours de traitement. Dans la boucle on additionne la somme partielle avec la valeur de la case désignée par le compteur, et on n'oublie surtout pas d'incrémenter le compteur de 1, sinon on reste sur la même case et la boucle est infinie. Un détail supplémentaire, il n'est pas sûr qu'on rentre dans la boucle, donc si on effectue le calcul après, ce sera peut-être avec une division par zéro donc on met une condition if pour pouvoir calculer. (j'ai ajouté ça après parce que j'avais des bugs et des divisions par zéro !) On fait donc notre somme par une boucle while, puis le calcul de la moyenne en divisant la somme par le nombre de valeurs, si on ne divise pas par zéro.</div>
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code><span style="color: blue;">int</span> noTick = <span style="color: #38761d;">0</span>;
<span style="color: blue;">double</span> sommeCours = <span style="color: #38761d;">0</span>, moyenneCours = <span style="color: #38761d;">0</span>;
<span style="color: blue;">while</span>(noTick < nbTickDansSeconde) {
sommeCours = sommeCours + ticksDeLaSeconde[noTick];
noTick = noTick + <span style="color: #38761d;">1</span>;
}
<span style="color: blue;">if</span>(noTick != <span style="color: #38761d;">0</span>) { moyenneCours = sommeCours / noTick; }</code></pre>
<br />
<div style="text-align: justify; text-indent: 3em;">
Précision pour la fontion marketInfo(), elle demande pour donner une valeur, de préciser sur quelle paire on veut la valeur et quelle type de valeur on désire. Pour la paire, on utilise la fonction Symbol() qui donne la paire sur laquelle on a lancé l'expert. Pour le type de valeur, c'est une constante, ici MODE_TIME. C'est une variable prédéfinie dont la valeur ne change pas, donc ici MODE_TIME est le nom d'une valeur numérique de type entier et cette valeur signifie pour la fonction qu'on veut l'horodatage du tick. On pourrait et on le fera, fournir d'autres constantes pour avoir d'autres types de valeur de la part de la fonction MarketInfo(). On pourrait tout aussi bien demander une valeur sur une autre paire de devises que celle sur laquelle l'expert a été lancé. Il faudrait mettre le symbole de la paire sous forme de texte.</div>
<br />
<div style="text-align: justify; text-indent: 3em;">
La valeur de la moyenne nous allons pour l'instant seulement l'afficher sur le graphique. Nous allons donc créer un objet de type Label lors de l'initialisation de l'expert, y mettre une valeur 0.00000 pour commencer, puis dans la fonction start(), à chaque fois qu'une moyenne est calculée, on la met dans l'objet Label. Il faudra au passage convertir un nombre de type double en texte avec la fonction doubleToStr() qui demande deux arguments: la valeur à convertir et le nombre de décimales à prendre, ici 5. Les fonctions employées ici ont des noms très explicites. Pour créer un objet graphique la fonction ObjectCreate() demande un nom unique à l'objet, le type d'objet, le numéro de la fenêtre dans laquelle le faire ( dans chaque graphique de paire, il y a une fenêtre principale numéro 0 et on peut ajouter, ce que font certains indicateurs, d'autres fenêtres qui prendront les numéros suivants), la position Y et X en pixels pour placer ce texte à partir du coin gauche haut. Ces coordonnées seront transformées par des multiplicateurs, donc ne vous étonnez pas de voir le texte ailleurs qu'à la position (2,5). La fonction de création renvoie une valeur vrai ou faux pour dire si ça a réussi. On déclare donc une variable pour la recevoir en même temps qu'on appelle la fonction. Après on teste si ça a réussi, si oui, on y entre un texte avec la fonction ObjectSetText() qui demande le nom de l'objet, la valeur sous forme de texte et la taille des caractères à afficher. Si non, on affiche qu'il y a eu une erreur et on précise le numéro de cette erreur avec la fonction GetLastError() qui nous le donne. (une fois que cette fonction a donné le numéro de l'erreur, elle ne le redonnera plus ! Attention !).</div>
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code><span style="color: blue;">bool</span> aReussi = <span style="color: #674ea7;">ObjectCreate</span>(<span style="color: #45818e;">"moyenne"</span>, <span style="color: #073763;">OBJ_LABEL</span>, <span style="color: #38761d;">0</span>, <span style="color: #38761d;">2</span>, <span style="color: #38761d;">5</span>);
<span style="color: blue;">if</span>(aReussi) { </code><code><span style="color: #674ea7;">ObjectSetText</span>(<span style="color: #45818e;">"moyenne"</span>, <span style="color: #45818e;">"0.00000"</span>, <span style="color: #38761d;">10</span>); }
<span style="color: blue;">else</span> { <span style="color: #674ea7;">Print</span>(<span style="color: #45818e;">"Erreur à la création du texte: "</span>, <span style="color: #674ea7;">GetLastError</span>()); }
<span style="color: #674ea7;">ObjectSetText</span>(<span style="color: #45818e;">"moyenne"</span>, <span style="color: #674ea7;">DoubleToStr</span>(moyenneCours, <span style="color: #38761d;">5</span>), <span style="color: #38761d;">10</span>);</code></pre>
<br />
<div style="text-align: justify; text-indent: 3em;">
Ouf! Ça fait déjà beaucoup tout ça ! Je vous propose de le faire avec moi en vidéo, où je redonne toutes les explications au fur et à mesure. Ensuite vous avez le code complet en modèle. Accrochez-vous, même si vous êtes un peu perdus car de toute façon on le reprendra dans les posts suivants pour le rendre plus clair, et avec des explications supplémentaires vous comprendrez mieux. Il n'y a pas de secrets, il faut faire un peu d'efforts devant la difficulté pour progresser. Je peux vous le garantir par expérience. Quand c'est plus difficile et qu'on fait les efforts pour y arriver, on progresse vite.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='480' height='360' src='https://www.youtube.com/embed/atmFmBMGMf0?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<div style="text-align: justify; text-indent: 3em;">
Et voici le code complet comme promis:</div>
<br />
<pre style="background-color: white; color: black; font-weight: bold; padding: 1em;"><code><span style="color: #999999;">
//+------------------------------------------------------------------+
//| moyenneParSeconde.mq4 |
//| Copyright 2013, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">#property copyright</span> <span style="color: #45818e;">"Copyright 2013, argent-facile-avec-robots-forex"</span>
<span style="color: blue;">#property link</span> <span style="color: #45818e;">"http://argent-facile-avec-robots-forex.blogspot.fr"</span>
<span style="color: blue;">double</span> ticksDeLaSeconde[<span style="color: #38761d;">10</span>];
<span style="color: blue;">int</span> nbTickDansSeconde;
<span style="color: blue;">datetime</span> tempsEnCoursTraitement, tempsTickActuel;
<span style="color: #999999;">
//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> init()
{
nbTickDansSeconde = <span style="color: #38761d;">0</span>;
tempsEnCoursTraitement = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #674ea7;">Symbol</span>(), <span style="color: #073763;">MODE_TIME</span>);
<span style="color: blue;">bool</span> aReussi = <span style="color: #674ea7;">ObjectCreate</span>(<span style="color: #45818e;">"moyenne"</span>, <span style="color: #073763;">OBJ_LABEL</span>, <span style="color: #38761d;">0</span>, <span style="color: #38761d;">2</span>, <span style="color: #38761d;">5</span>);
<span style="color: blue;">if</span>(aReussi) { </code><code><span style="color: #674ea7;">ObjectSetText</span>(<span style="color: #45818e;">"moyenne"</span>, <span style="color: #45818e;">"0.00000"</span>, <span style="color: #38761d;">10</span>); }
<span style="color: blue;">else</span> { <span style="color: #674ea7;">Print</span>(<span style="color: #45818e;">"Erreur à la création du texte: "</span>, <span style="color: #674ea7;">GetLastError</span>()); }
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| expert deinitialization function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> deinit()
{
<span style="color: blue;">int</span> nbObjetsEffaces;
nbObjetsEffaces = ObjectsDeleteAll();
<span style="color: #674ea7;">Print</span>(nbObjetsEffaces, <span style="color: #45818e;">" objets graphiques effaces !"</span>);
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+</span>
<span style="color: blue;">int</span> start()
{
tempsTickActuel = <span style="color: #674ea7;">MarketInfo</span>(<span style="color: #674ea7;">Symbol</span>(), <span style="color: #073763;">MODE_TIME</span>);
<span style="color: blue;">if</span>(tempsTickActuel > tempsEnCoursTraitement) {
<span style="color: blue;">int</span> noTick = <span style="color: #38761d;">0</span>;
<span style="color: blue;">double</span> sommeCours = <span style="color: #38761d;">0</span>, moyenneCours = <span style="color: #38761d;">0</span>;
<span style="color: blue;">while</span>(noTick < nbTickDansSeconde) {
sommeCours = sommeCours + ticksDeLaSeconde[noTick];
noTick = noTick + <span style="color: #38761d;">1</span>;
}
<span style="color: blue;">if</span>(noTick != <span style="color: #38761d;">0</span>) { moyenneCours = sommeCours / noTick; }
<span style="color: #674ea7;">ObjectSetText</span>(<span style="color: #45818e;">"moyenne"</span>, <span style="color: #674ea7;">DoubleToStr</span>(moyenneCours, <span style="color: #38761d;">5</span>), <span style="color: #38761d;">10</span>);
tempsEnCoursTraitement = tempsTickActuel;
nbTickDansSeconde = <span style="color: #38761d;">0</span>;
}
ticksDeLaSeconde[nbTickDansSeconde] = (<span style="color: magenta;">Bid</span> + <span style="color: magenta;">Ask</span>) / <span style="color: #38761d;">2</span>;
nbTickDansSeconde = nbTickDansSeconde + <span style="color: #38761d;">1</span>;
<span style="color: blue;">return</span>(<span style="color: #38761d;">0</span>);
}
<span style="color: #999999;">//+------------------------------------------------------------------+</span>
</code></pre>
<br />
<div style="text-align: justify; text-indent: 3em;">
Rassurez-vous, dès le prochain post sur la dernière instruction à connaître, nous remanierons ce code un peu confus, et on continuera encore sur le suivant. Vous aurez l'occasion de le voir et revoir ce code; vous le connaîtrez par cœur, et il sera plus agréable à lire et plus facile à comprendre.</div>
<br />Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-5819740724101841193.post-73715611664363981682013-08-01T22:33:00.001+02:002013-08-09T14:53:35.842+02:00La boucle while en MQL4: initiation à la programmation d'expert advisors<div style="text-align: justify; text-indent: 3em;">
L'avant-dernière instruction indispensable pour programmer: la boucle while. (comme vous pouvez le constater, il n'y a pas beaucoup d'instructions à savoir, le reste n'est que créativité de la part du programmeur). Le but d'une boucle while est de répéter un bloc d'instructions tant qu'une condition est vraie. Le premier piège dans lequel on tombe tous: écrire une condition qui ne sera jamais fausse, donc du coup, la boucle est répétée indéfiniment. Du genre: les paramètres de la condition ne changent pas, et du coup elle sera toujours vraie ! Autre piège: il faut que la condition soit vraie au départ pour au moins rentrer dans la boucle et exécuter au moins une fois le bloc. Voici sa syntaxe:</div>
<pre style="background-color: white; color: black; padding: 1em;"><code>
<span style="color: blue;">while</span>(condition) {
instruction 1;
instruction 2;
...
instruction n;
}
autres instructions;
</code>
</pre>
<div style="text-align: justify; text-indent: 3em;">
On écrit donc le mot while, puis une paire de parenthèses encadrant une condition (sous forme de variable booléenne dont le contenu doit changer, ou sous forme d'expression logique qui donne un résultat vrai ou faux et les paramètres de cette expression doivent aussi varier sinon elle donnera toujours le même résultat). Puis une accolade ouvrante pour débuter la série d'instruction à répéter. On fini évidemment après les instructions avec une accolade fermante. Nous allons appliquer cette instruction à un petit expert advisor qui va à l'initialisation répéter une demande de déblocage de l'expert s'il n'est pas autorisé à travailler. Je m'explique: il y a un bouton bascule dans MetaTrader qui autorise ou non les experts à travailler. Et dans la librairie de fonctions de MQL4, il y a une fonction qui va vérifier si le bouton est enclenché ou non. Elle renvoie vrai ou faux. On va donc l'utiliser comme condition de la boucle, et si l'expert n'est pas autorisé on va faire une alerte pour demander le déblocage. Puis après une pause de quelques secondes dans la boucle, on la recommence. La condition va être de nouveau vérifiée et dans le cas où elle serait encore vraie, le bloc serait encore exécuté: alerte puis pause (La pause c'est pour éviter de provoquer une avalanche d'alertes parce que dès que le bloc est terminé, il recommence. Et tout se passe très, très vite !). La fonction qui nous donne la condition est: IsExpertEnabled(), son nom est explicite (est-ce que l'expert est autorisé) et elle donne vrai si c'est le cas, faux sinon. Nous, on veut "est-ce que l'expert n'est pas autorisé?", donc on doit prendre la négation avec un point d'exclamation devant: !IsExpertEnabled(). Ce qui donnera vrai si l'expert n'est pas autorisé (bouton non enclenché) et faux s'il l'est. Comme ça, dès que l'expert est autorisé, on sort de la boucle. La fonction qui permet de faire une pause est: sleep(). C'est aussi très explicite ! On doit lui mettre entre parenthèses le nombre de millisecondes de pause désiré. Nous allons utiliser l'expert créé dans le tutoriel précédent: celui qui compte les changements de pente. Voici les étapes à suivre depuis le logiciel MetaTrader 4:</div>
<br />
<ul>
<li>Dans le navigateur arborescent, cliquez sur la croix des experts consultants pour les dérouler.</li>
<li>Faites un clic-droit sur l'expert DetectionChangementsPente puis Modifier dans le menu contextuel.</li>
<li> L'éditeur de code s'est ouvert avec l'expert advisor. Placez-vous à la fin de la ligne nbHausses = 0; dans la fonction init(). Appuyez sur la touche Entrée pour faire une nouvelle ligne.</li>
<li>Saisissez le code suivant:</li>
</ul>
<pre style="background-color: white; color: black; font-size: smaller; font-weight: bold;"><code>
<span style="color: blue;">while</span>(!<span style="color: #674ea7;">IsExpertEnabled</span>()) {
<span style="color: #674ea7;">Alert</span>(<span style="color: #45818e;">"il faut autoriser l\'expert !"</span>);
<span style="color: #674ea7;">Sleep</span>(<span style="color: #38761d;">5000</span>);
}
</code>
</pre>
<ul>
<li>Cliquez sur le bouton à la disquette bleue pour enregistrer.</li>
<li>Cliquez sur le bouton Compile.</li>
<li>Vérifiez qu'il n'y a pas d'erreurs de compilation en bas. Si oui, il faut contrôler ce que vous avez saisi et corriger. Dès que vous n'avez pas d'erreur, ni warning, retournez sous MetaTrader 4.</li>
<li>Cliquez sur le bouton Experts Advisors à droite de celui au losange jaune. Il faut qu'il soit désactivé pour ne pas autoriser les experts à travailler.</li>
<li>Faites un clic sur l'expert DetecteurChangementsPente dans le navigateur arborescent, et sans relâcher, glissez et déposez-le sur un graphique.</li>
<li>Cliquez sur Ok dans la fenêtre de paramétrage pour le lancer.</li>
<li>La fenêtre d'alerte doit s'ouvrir et sonner avec le message qu'on a inscrit dans le code. Si ce n'est pas le cas, il faut vérifier que vous n'avez pas oublié le point d'exclamation dans la condition de la boucle.</li>
<li>Toutes les 5000 millisecondes, soit 5 secondes, l'alerte se répète. Cliquez alors sur bouton Experts Advisors pour les autoriser de nouveau.</li>
<li>Vous pouvez fermer la fenêtre d'alerte.</li>
<li>Quand vous arrêtez l'expert, par un clic-droit sur le graphique et Experts Consultants > Retirer, il doit vous indiquer les hausses et baisses et stagnations comme il le faisait avant, dans la fenêtre Experts en bas de MetaTrader.</li>
</ul>
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='480' height='360' src='https://www.youtube.com/embed/RnJgZbK1UhQ?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<div style="text-align: justify; text-indent: 3em;">
Et le tout expliqué dans un tutoriel vidéo très court cette fois-ci. Il n'y a pas beaucoup de code à saisir aujourd'hui. Ce code peut très bien s'appliquer à n'importe quel expert advisor. La prochaine fois nous verrons une autre boucle, mais qui compte les répétitions: la boucle 'for'. Errata: J'ai annoncé au début dans le tutoriel vidéo "instruction switch", il faut bien sûr comprendre "instruction while".
</div>
Unknownnoreply@blogger.com0