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 Bars 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é
Une fonction donnant un numéro de période:
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
NULL
. 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 ERREUR_INT_POSITIF
, constante définie précédemment dans un include. La séquence des instructions est alors comme celle des deux fonctions précédentes:
- Initialisation de la variable à retourner à la valeur
ERREUR_INT_POSITIF
- Test si la valeur de l'argument est celle par défaut:
NULL
, et dans l'affirmative remplacement par la valeur pour la période courante, à demander à la fonctionobtenirNbSecsDsPeriode()
précédemment définie. - Test si l'argument est positif.
- Si l'argument est positif, alors faire le calcul et l'affecter à la variable à retourner.
- Sinon, afficher une alerte avec un message explicatif et la valeur erronée.
- Retourner la variable.
int obtenirNoPeriode(datetime horodatage, int nbSecsDansPeriode=NULL) {
int noPeriode = ERREUR_INT_POSITIF;
if(nbSecsDansPeriode == NULL) { nbSecsDansPeriode = obtenirNbSecsDsPeriode(); }
bool nbSecsEstValide = (nbSecsDansPeriode > 0);
if(nbSecsEstValide) { noPeriode = horodatage / nbSecsDansPeriode; }
else { Alert(" ObtenirNoPeriode() ", msgErrNbSecsNonValide, nbSecsDansPeriode); }
return(noPeriode);
}
Code de test de cette fonction:
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:
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:
n° cas | horodatage | nbSecsDsPeriode | résultat retourné | commentaires |
---|---|---|---|---|
1 | 0 | 0 | 0 | 0 divisé par le nombre de secondes dans la période courante |
2 | 0 | 300 | 0 | 0 / 300 = 0 |
3 | 0 | -10 | ERREUR_INT_POSITIF | le mauvais argument compte en priorité |
4 | 0 | ARG_INT_EMPTY | 0 | 0 divisé par le nombre de secondes dans la période courante |
5 | 1207 | 0 | 1207 / (60 * Period()) | 1207 divisé par le nombre de secondes dans la période courante |
6 | 1207 | 300 | 4 | 1207 / 300 = 4 + un reste fractionnaire non pris en compte |
7 | 1207 | -10 | ERREUR_INT_POSITIF | mauvais argument |
8 | 1207 | ARG_INT_EMPTY | 1207 / (60 * Period()) | 1207 divisé par le nombre de secondes dans la période courante |
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:
// section defines
#define NB_CAS_NO_PERIOD 8
// section constantes
string nomObtenirNoPeriode = "obtenirNoPeriode()"
// section fonctions
int execObtenirNoPeriode(datetime argumentHorodatage, int argumentNbSecsDsPeriode) {
int resultat;
if(argumentNbSecsDsPeriode == ARG_INT_EMPTY) {
resultat = obtenirNoPeriode(argumentHorodatage); }
else { resultat = obtenirNoPeriode(argumentHorodatage, argumentNbSecsDsPeriode); }
return(resultat);
}
int testObtenirNoPeriode() {
int noCas, nbErreurs = 0;
int resultat;
datetime argumentsHorodatages[NB_CAS_NO_PERIOD] = {0,
0,
0,
0,
1207,
1207,
1207,
1207};
int argumentsNbSecsDsPeriode[NB_CAS_NO_PERIOD] = {0,
300,
-10,
ARG_INT_EMPTY,
0,
300,
-10,
ARG_INT_EMPTY};
string parametresCas[NB_CAS_NO_PERIOD] = {" 0, 0 => ",
" 0, 300 => ",
" 0, -10 => ",
" 0, => ",
" 1207, 0 => ",
" 1207, 300 => ",
" 1207, -10 => ",
" 1207, => "};
int resultatsAttendus[NB_CAS_NO_PERIOD];
resultatsAttendus[0] = 0;
resultatsAttendus[1] = 0;
resultatsAttendus[2] = ERREUR_INT_POSITIF;
resultatsAttendus[3] = 0;
resultatsAttendus[4] = (1207 / (60 * Period()));
resultatsAttendus[5] = 4;
resultatsAttendus[6] = ERREUR_INT_POSITIF;
resultatsAttendus[7] = (1207 / (60 * Period()));
for(noCas=0 ; noCas<NO_CAS_NB_SEC_IN_PERIOD ; noCas++) {
resultat = execObtenirNoPeriode(argumentsHorodatages[noCas],
argumentsNbSecsDsPeriode[noCas]);
nbErreurs += analyserResultatIntDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNoPeriode,
parametresCas[noCas]);
}
return(nbErreurs);
}
// ajouter dans la fonction init()
nbErreurs += testObtenirNoPeriode();
Le tutoriel vidéo et les codes complets de l'include et de l'expert de test:
//+------------------------------------------------------------------+
//| ArithmetiqueTemporelle.mqh |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, argent-facile-avec-robots-forex"
#property link "http://argent-facile-avec-robots-forex.blogspot.fr"
//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| DLL imports |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| EX4 imports |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| includes |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| variables globales |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| constantes globales |
//+------------------------------------------------------------------+
string msgErrNbMinsNonValide = " a reçu un nombre de minutes non valide: ";
string msgErrNbSecsNonValide = " a reçu un nombre de secondes non valide: ";
//+------------------------------------------------------------------+
//| fonctions comptage |
//+------------------------------------------------------------------+
datetime obtenirNoDerniereSecConnue(string paire="NULL") {
datetime horodatage;
if(paire=="NULL") { horodatage = TimeCurrent(); }
else { horodatage = MarketInfo(paire, MODE_TIME); }
return(horodatage);
}
int obtenirNbSecsDsPeriode(int nbMinsDansPeriode=NULL) {
int nbSecsDsPeriode = ERREUR_INT_POSITIF;
if(nbMinsDansPeriode == NULL) { nbMinsDansPeriode = Period(); }
bool nbMinsEstValide = (nbMinsDansPeriode > 0);
if(nbMinsEstValide) { nbSecsDsPeriode = 60 * nbMinsDansPeriode; }
else { Alert("ObtenirNbSecsDsPeriode() ", msgErrNbMinsNonValide, nbMinsDansPeriode); }
return(nbSecsDsPeriode);
}
int obtenirNoSecDsPeriode(datetime horodatageSec, int nbSecsDansPeriode=NULL) {
int noSecDansPeriode = ERREUR_INT_POSITIF;
if(nbSecsDansPeriode == NULL) { nbSecsDansPeriode = obtenirNbSecsDsPeriode(); }
bool nbSecsEstValide = (nbSecsDansPeriode > 0);
if(nbSecsEstValide) { noSecDansPeriode = horodatageSec % nbSecsDansPeriode; }
else { Alert("ObtenirNoSecDsPeriode() ", msgErrNbSecsNonValide, nbSecsDansPeriode); }
return(noSecDansPeriode);
}
int obtenirNoPeriode(datetime horodatage, int nbSecsDansPeriode=NULL) {
int noPeriode = ERREUR_INT_POSITIF;
if(nbSecsDansPeriode == NULL) { nbSecsDansPeriode = obtenirNbSecsDsPeriode(); }
bool nbSecsEstValide = (nbSecsDansPeriode > 0);
if(nbSecsEstValide) { noPeriode = horodatage / nbSecsDansPeriode; }
else { Alert("ObtenirNoPeriode() ", msgErrNbSecsNonValide, nbSecsDansPeriode); }
return(noPeriode);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| testsArithmetiqueTemporelle.mqh |
//| Copyright 2014, argent-facile-avec-robots-forex |
//| http://argent-facile-avec-robots-forex.blogspot.fr |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, argent-facile-avec-robots-forex"
#property link "http://argent-facile-avec-robots-forex.blogspot.fr"
#include <Constantes.mqh>
#include <UtilitairesTests.mqh>
#include <ArithmetiqueTemporelle.mqh>
//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+
#define NB_CAS_LAST_KNOWN_SEC_NO 5
#define NB_CAS_NB_SECS_IN_PERIOD 5
#define NB_CAS_NO_SEC_IN_PERIOD 7
#define NB_CAS_NO_PERIOD 8
//+------------------------------------------------------------------+
//| constantes de tests |
//+------------------------------------------------------------------+
string nomObtenirNoDerniereSecConnue = "obtenirNoDerniereSecConnue()";
string nomObtenirNbSecsDsPeriode = "obtenirNbSecsDsPeriode()"
string nomObtenirNoSecDsPeriode = "obtenirNoSecDsPeriode()"
string nomObtenirNoPeriode = "obtenirNoPeriode()"
//+------------------------------------------------------------------+
//| fonctions de tests |
//+------------------------------------------------------------------+
datetime execObtenirNoDerniereSecConnue(string argument) {
datetime resultat;
if(argument == ARG_STRING_EMPTY) { resultat = obtenirNoDerniereSecConnue(); }
else { resultat = obtenirNoDerniereSecConnue(argument); }
return(resultat);
}
int testObtenirNoDerniereSecConnue() {
int noCas, nbErreurs = 0;
datetime resultat;
string arguments[NB_CAS_LAST_KNOWN_SEC_NO] = {ARG_STRING_EMPTY,
"EURUSD",
"GBPJPY",
"EUR",
""};
string parametresCas[NB_CAS_LAST_KNOWN_SEC_NO] = {" sans paramètre => ",
" \"EURUSD\" => ",
" \"GBPJPY\" => ",
" \"EUR\" => ",
" \"\" => "};
datetime resultatsAttendus[NB_CAS_LAST_KNOWN_SEC_NO];
resultatsAttendus[0] = TimeCurrent();
resultatsAttendus[1] = MarketInfo("EURUSD", MODE_TIME);
resultatsAttendus[2] = MarketInfo("GBPJPY", MODE_TIME);
resultatsAttendus[3] = 0;
resultatsAttendus[4] = 0;
for(noCas=0 ; noCas<NB_CAS_LAST_KNOWN_SEC_NO ; noCas++) {
resultat = execObtenirNoDerniereSecConnue(arguments[noCas]);
nbErreurs += analyserResultatDatetimeDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNoDerniereSecConnue,
parametresCas[noCas]);
}
return(nbErreurs);
}
int execObtenirNbSecsDsPeriode(int argument) {
int resultat;
if(argument == ARG_INT_EMPTY) { resultat = obtenirNbSecsDsPeriode(); }
else { resultat = obtenirNbSecsDsPeriode(argument); }
return(resultat);
}
int testObtenirNbSecsDsPeriode() {
int noCas, nbErreurs = 0;
int resultat;
int arguments[NB_CAS_NB_SECS_IN_PERIOD] = {ARG_INT_EMPTY, 5, 240, -2, 0};
string parametresCas[NB_CAS_NB_SECS_IN_PERIOD] = {" sans paramètres => ",
" 5 => ",
" 240 => ",
" -2 => ",
" 0 => "};
int resultatsAttendus[NB_CAS_NB_SECS_IN_PERIOD];
resultatsAttendus[0] = 60 * Period();
resultatsAttendus[1] = 300;
resultatsAttendus[2] = 14400;
resultatsAttendus[3] = ERREUR_INT_POSITIF;
resultatsAttendus[4] = 60 * Period();
for(noCas=0 ; noCas<NB_CAS_NB_SECS_IN_PERIOD ; noCas++) {
resultat = execObtenirNbSecsDsPeriode(arguments[noCas]);
nbErreurs += analyserResultatIntDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNbSecsDsPeriode,
parametresCas[noCas]);
}
return(nbErreurs);
}
int execObtenirNoSecDsPeriode(datetime argumentHorodatage, int argumentNbSecsDsPeriode) {
int resultat;
if(argumentNbSecsDsPeriode == ARG_INT_EMPTY) {
resultat = obtenirNoSecDsPeriode(argumentHorodatage); }
else { resultat = obtenirNoSecDsPeriode(argumentHorodatage, argumentNbSecsDsPeriode); }
return(resultat);
}
int testObtenirNoSecDsPeriode() {
int noCas, nbErreurs = 0;
int resultat;
datetime argumentsHorodatages[NB_CAS_NO_SEC_IN_PERIOD] = {127,
123456789,
123456789,
123456789,
127,
127,
127};
int argumentsNbSecsDsPeriode[NB_CAS_NO_SEC_IN_PERIOD] = {ARG_INT_EMPTY,
ARG_INT_EMPTY,
240,
900,
60,
0,
-4};
string parametresCas[NB_CAS_NO_SEC_IN_PERIOD] = {" 127, EMPTY => ",
" 123456789, EMPTY => ",
" 123456789, 240 => ",
" 123456789, 900 => ",
" 127, 60 => ",
" 127, 0 => ",
" 127, -4 => "};
int resultatsAttendus[NB_CAS_NO_SEC_IN_PERIOD];
resultatsAttendus[0] = 127 % (60 * Period());
resultatsAttendus[1] = 123456789 % (60 * Period());
resultatsAttendus[2] = 69;
resultatsAttendus[3] = 189;
resultatsAttendus[4] = 7;
resultatsAttendus[5] = 127 % (60 * Period());
resultatsAttendus[6] = ERREUR_INT_POSITIF;
for(noCas=0 ; noCas<NO_CAS_NB_SEC_IN_PERIOD ; noCas++) {
resultat = execObtenirNbSecsDsPeriode(argumentsHorodatages[noCas],
argumentsNbSecsDsPeriode[noCas]);
nbErreurs += analyserResultatIntDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNoSecDsPeriode,
parametresCas[noCas]);
}
return(nbErreurs);
}
int execObtenirNoPeriode(datetime argumentHorodatage, int argumentNbSecsDsPeriode) {
int resultat;
if(argumentNbSecsDsPeriode == ARG_INT_EMPTY) {
resultat = obtenirNoPeriode(argumentHorodatage); }
else { resultat = obtenirNoPeriode(argumentHorodatage, argumentNbSecsDsPeriode); }
return(resultat);
}
int testObtenirNoPeriode() {
int noCas, nbErreurs = 0;
int resultat;
datetime argumentsHorodatages[NB_CAS_NO_PERIOD] = {0,
0,
0,
0,
1207,
1207,
1207,
1207};
int argumentsNbSecsDsPeriode[NB_CAS_NO_PERIOD] = {0,
300,
-10,
ARG_INT_EMPTY,
0,
300,
-10,
ARG_INT_EMPTY};
string parametresCas[NB_CAS_NO_PERIOD] = {" 0, 0 => ",
" 0, 300 => ",
" 0, -10 => ",
" 0, => ",
" 1207, 0 => ",
" 1207, 300 => ",
" 1207, -10 => ",
" 1207, => "};
int resultatsAttendus[NB_CAS_NO_PERIOD];
resultatsAttendus[0] = 0;
resultatsAttendus[1] = 0;
resultatsAttendus[2] = ERREUR_INT_POSITIF;
resultatsAttendus[3] = 0;
resultatsAttendus[4] = (1207 / (60 * Period()));
resultatsAttendus[5] = 4;
resultatsAttendus[6] = ERREUR_INT_POSITIF;
resultatsAttendus[7] = (1207 / (60 * Period()));
for(noCas=0 ; noCas<NO_CAS_NB_SEC_IN_PERIOD ; noCas++) {
resultat = execObtenirNoPeriode(argumentsHorodatages[noCas],
argumentsNbSecsDsPeriode[noCas]);
nbErreurs += analyserResultatIntDuTest(resultat,
resultatsAttendus[noCas],
nomObtenirNoPeriode,
parametresCas[noCas]);
}
return(nbErreurs);
}
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
int nbErreurs = 0;
nbErreurs += testObtenirNoDerniereSecConnue();
nbErreurs += testObtenirNbSecsDsPeriode();
nbErreurs += testObtenirNoSecDsPeriode();
nbErreurs += testObtenirNoPeriode();
Print("-------------------------------------------------------------------");
Print("TESTS DE ArithmetiqueTemporelle.mqh TERMINES AVEC ", nbErreurs, " ERREUR(S).");
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
return(0);
}
//+------------------------------------------------------------------+
Aucun commentaire:
Enregistrer un commentaire