Comparaison de la moyenne mobile (et de tout autre indicateur) et de l'erreur

 

Bonjour à tous !

Je suis en train d'écrire un EA basé sur le croisement des SMA (ou plutôt je pensais l'avoir déjà fait, car cela semble simple). Mais... J'ai été confronté à un problème. Le Conseiller Expert fonctionne selon le principe suivant : lorsqu'une nouvelle barre apparaît, il analyse la SMA des deux dernières barres, sans compter celle qui vient d'apparaître (l'avant-dernière et la précédente). Je compare les valeurs apparemment correctement comme décrit ici. La seule exception est que iMA est appelé avec le dernier paramètre (décalage en barres) 1 et 2 respectivement. Approximativement comme ceci (si le code est réécrit par analogie avec le cité) :

// берем два соседних значения Быстрой МА
double fast0=iMA(Symbol(), Period(), 10, 0, MODE_SMA, PRICE_CLOSE, 1);
double fast1=iMA(Symbol(), Period(), 10, 0, MODE_SMA, PRICE_CLOSE, 2);
 
// берем два значения Медленной МА
double slow0=iMA(Symbol(), Period(), 20, 0, MODE_SMA, PRICE_CLOSE, 1);
double slow1=iMA(Symbol(), Period(), 20, 0, MODE_SMA, PRICE_CLOSE, 2);
 
// сравниваем значения и определяем направление пересечения
if (fast0>slow0 && fast1<slow1) Print("Пересечение ВВЕРХ");
if (fast0<slow0 && fast1>slow1) Print("Пересечение ВНИЗ");

Le conseiller expert fonctionne sous une forme primitive en présence d'un signal de croisement sur le principe suivant : fermer la transaction précédente - en ouvrir une nouvelle. Bien entendu, si tous les croisements sont détectés, les transactions seront toujours exécutées les unes après les autres (VENTE - ACHAT - VENTE - ACHAT - ...). En d'autres termes, le conseiller expert n'a qu'une seule position ouverte à tout moment (à l'exception du moment précédant l'entrée de la toute première position). Voici donc le nœud du problème... Pour le timeframe minute et les périodes SMA 5 et 34 pour Close dans le testeur de stratégie dans la barre du 17.02.2015 à 01:24 j'ai attrapé une situation intéressante. Les mouvements présentant ces caractéristiques se croisent directement à la clôture de la barre. Voici la photo :

17.02.2015 01:24

Pour des raisons de débogage, je sors les informations. La correspondance dans le journal par rapport au code donné est la suivante :

SMAFastCurrent =fast0

SMASlowCurrent =slow0

SMAFastPrevious =fast1

SMASlowPrevious=slow1 et

SMACurDifférence = SMAFastCurrent - SMASlowCurrent

SMAPrevDifference = SMAFastPrevious - SMASlowPreviousc (c'est-à-dire la différence entrefast0,slow0 etfast1,slow1 respectivement).

Ainsi, lorsque ces différences changent de signe, cela signifie qu'il s'agit d'un signal pour un passage à niveau Mooving. Mais dans cet exemple particulier, la vérification de plus ou moins ne fonctionne pas. Les valeurs de ces différences sont indiquées dans le journal. Le rectangle rouge montre les valeurs des différences sur la barre suivante après le problème (à 1:25), orange - sur la suivante (à 1:26). Et il est clair que les valeurs SMACurDifference sur la barre précédente et SMAPrevDifference sur la barre actuelle doivent être égales (la barre actuelle devient la précédente et la nouvelle barre prend sa place). Ainsi, puisque le croisement Mooving se produit à la clôture de la barre problématique à 1:24, sur la barre suivante (à 1:25) les valeurs de SMAFastCurrent et SMASlowCurrent sont égales (approximativement). Le débogueur les imprime généralement à 5 chiffres près (SMAFastCurrent = 1.13371 SMASlowCurrent = 1.13371 voir figure). Leur différence est infinitésimale mais pas nulle (SMACurDifference = 2.220446049250313e-016). Sur la barre suivante, leur différence aux mêmes valeurs exactes devient exactement zéro (comparez SMACurDifference en rouge et SMAPrevDifference en rectangles orange). En fait, il n'est pas clair comment éliminer ces erreurs, si même des valeurs apparemment identiques donnent des différences. D'où deux questions :

1. Pourquoi la différence des mêmes mouvements, comptée au moment de l'apparition alternée de deux mesures adjacentes, donne-t-elle un résultat différent ?

2. Je pensais introduire un epsilon et comparer avec lui, plutôt qu'avec zéro. Mais on le fait généralement pour comparer un infiniment petit à 0. Qu'en est-il du cas où je dois déterminer un changement de signe de cet infinitésimal ?

Bien sûr, je peux analyser trois barres adjacentes, mais il est toujours théoriquement possible qu'aux prix de leurs fermetures, les muvings se touchent à une distance infinitésimale. Je me rends compte qu'une telle situation se produit rarement (surtout si l'on prend un horizon temporel plus large), mais elle peut tout de même se produire. Et il faudrait l'attraper d'une manière ou d'une autre et détecter le franchissement de Mouvements dans ce cas également.

Merci d'avance pour toute aide !

Навигатор по форуму и ответы на часто задаваемые вопросы. Настоятельно Рекомендуется к Прочтению! - MQL4 форум
  • www.mql5.com
Навигатор по форуму и ответы на часто задаваемые вопросы. Настоятельно Рекомендуется к Прочтению! - MQL4 форум
 

Essayez la normalisation et la comparaison.

Le manuel de référence de MQL4 (et c'est la même chose pour MQL5) dit, ouvrez sur"Real Types (double, float)":

"...Vous ne pouvez pas comparer l'égalité de deux nombres réels entre eux. Dans la plupart des cas, deux nombres apparemment identiques peuvent s'avérer inégaux en raison de la différence de 15 décimales. Pour comparer correctement deux nombres réels, vous devez comparer la différence normalisée de ces nombres à une valeur nulle....."

"... il est fortement déconseillé de comparer deux nombres réels l'un à l'autre pour l'égalité, car une telle comparaison n'est pas correcte.

..............


Si, toutefois, il est nécessaire de comparer deux nombres réels pour vérifier leur égalité, on peut le faire de deux manières différentes. La première méthode consiste à comparer la différence entre les deux nombres avec une petite valeur qui définit la précision de la comparaison.

.............


La deuxième méthode consiste à comparer la différence normalisée de deux nombres réels avec une valeur nulle. Il est inutile de comparer la différence des nombres normalisés à zéro, car toute opération mathématique avec des nombres normalisés donne un résultat non normalisé.

...."

 
rosomah:

Essayez la normalisation et la comparaison.

Le manuel de référence de MQL4 (et c'est la même chose pour MQL5) dit, ouvrez sur"Real Types (double, float)":

"...Vous ne pouvez pas comparer l'égalité de deux nombres réels entre eux. Dans la plupart des cas, deux nombres apparemment identiques peuvent se révéler inégaux en raison de la différence de 15 décimales. Pour comparer correctement deux nombres réels, vous devez comparer la différence normalisée de ces nombres à une valeur nulle....."

"Il est catégoriquement déconseillé de comparer deux nombres réels entre eux pour en vérifier l'égalité, car cette comparaison n'est pas valable.

..............


Si, toutefois, il est nécessaire de comparer deux nombres réels pour vérifier leur égalité, on peut le faire de deux manières différentes. La première méthode consiste à comparer la différence entre les deux nombres avec une petite valeur qui définit la précision de la comparaison.

.............


La deuxième méthode consiste à comparer la différence normalisée de deux nombres réels avec zéro. Il est inutile de comparer la différence des nombres normalisés à zéro, car toute opération mathématique avec des nombres normalisés donne un résultat non normalisé.

...."

Je suis bien conscient qu'il n'est pas possible de comparer des chiffres réels pour l'égalité. Il n'y a pas de comparaison d'égalité dans le code que j'ai cité. Et ce n'est pas nécessaire non plus. Nous nous trouvons ici dans une situation où nous devons prendre en compte les changements d'un signe infinitésimal qui pourrait bien atteindre 0. Dans ce cas également, il est dangereux de tout comparer simplement à plus ou à 0. Et la normalisation peut être encore plus dangereuse ici... Les valeurs initiales de MA sont normalisées à un nombre inconnu (plus l'horizon temporel est petit, plus la valeur de MA est petite). Si la normalisation à un chiffre constant après la virgule est appliquée, il peut en résulter que toutes les valeurs de MA seront exactement 0. Pour être honnête, je ne comprends pas vraiment ce que sera la différence de deux valeurs MA...

 

gammaray:

Je suis bien conscient que la comparaison de chiffres réels sur l'égalité n'est pas possible. Dans le code que j'ai cité, il n'y a pas de comparaison d'égalité. Et ce n'est pas nécessaire non plus. Nous nous trouvons ici dans une situation où nous devons capter des changements de signe infinitésimal qui peuvent très bien atteindre 0. Dans ce cas aussi, il est dangereux de tout comparer simplement à plus ou à 0. Et la normalisation peut être encore plus dangereuse ici... Les valeurs initiales de MA sont normalisées à un nombre inconnu (plus l'horizon temporel est petit, plus la valeur de MA est petite). Si la normalisation à un chiffre constant après la virgule est appliquée, il peut en résulter que toutes les valeurs de MA seront exactement 0. Pour être honnête, je ne comprends pas vraiment quelle sera la différence entre deux valeurs MA...

Pourquoi la normalisation est-elle plus dangereuse ?

Donc :

...

Si vous devez comparer deux nombres réels pour vérifier leur égalité, vous pouvez le faire de deux manières différentes. La première méthode consiste à comparer la différence entre les deux nombres avec une petite valeur qui détermine la précision de la comparaison.

...

La deuxième méthode consiste à comparer la différence normalisée de deux nombres réels à une valeur nulle. Comparer la différence des nombres normalisés à zéro est inutile, puisque toute opération mathématique avec des nombres normalisés donne un résultat non normalisé.

Exemple :

bool CompareDoubles(double number1,double number2)
  {
   if(NormalizeDouble(number1-number2,8)==0) return(true);
   else return(false);
  }
void OnStart()
  {
   double d_val=0.3;
   float  f_val=0.3;
   if(CompareDoubles(d_val,f_val)) Print(d_val,"equals",f_val);
   else Print("Different: d_val = ",DoubleToString(d_val,16),
              "  f_val = ",DoubleToString(f_val,16));
// Результат: Different: d_val= 0.3000000000000000   f_val= 0.3000000119209290
  }
  • Et mon expérience pratique personnelle (pour le dire modestement, elle n'est pas mince en termes de nombre de vérifications méticuleuses du fonctionnement du programme, où j'ai appliqué et applique encore la comparaison de nombres avec le double, en termes de justesse des conditions se déclenchant sur la base de telles comparaisons),
Cela me permet de considérer que ces comparaisons ne sont pas seulement non menaçantes :
if(NormalizeDouble(number1-number2,dig)==0)
if(NormalizeDouble(number1-number2,dig)>0)
if(NormalizeDouble(number1-number2,dig)<0)

// dig=Digits();

mais, à l'inverse, une variante de l'une des deux manières qui peut, comme le dit la Documentation, être appliquée aux comparaisons de nombres doubles.

Parce que:

Vous ne pouvez pas comparer l'égalité de deux nombres réels l'un par rapport à l'autre. Dans la plupart des cas, deux nombres apparemment identiques peuvent se révéler inégaux en raison d'une différence de valeur de 15 décimales. Pour comparer correctement deux nombres réels, la différence normalisée de ces nombres doit être comparée à zéro.



P./S. : Il s'est avéré que la première méthode de la Documentation était moins pratique pour moi, même sur la base de tâches que je résous généralement moi-même. Par conséquent, je n'ai pas beaucoup d'expérience avec la première méthode.

Mais en utilisant la deuxième méthode (c'est-à-dire en comparant la différence normalisée de deux nombres réels avec la valeur zéro dans l'expression de l'opérateur conditionnel), aucun problème ne s'est produit.

Mais si j'ai fait une comparaison de nombres non normalisés (je veux dire ici, y compris, ce que j'ai fait sans utiliser la première méthode), alors oui, il y avait, que j'ai trouvé le déclenchement incorrect des conditions sur la base des comparaisons des nombres de type double.

 
gammaray:

Ce sont les phrases de la documentation:

La deuxième méthode consiste à comparer la différence normalisée de deux nombres réels à zéro. Comparer la différence des nombres normalisés à zéro est inutile, car toute opération mathématique avec des nombres normalisés donne un résultat non normalisé.

Pour moi, il est perçu que, en termes simplistes, dans les opérations mathématiques (et notamment les diverses transformations), on ne devrait pas faire quelque chose comme ça :

// dig=Digits();

double delta=NormalizeDouble(number1-number2,dig);

if (delta>0)


C'est-à-dire que dans le post précédent, j'ai donné des exemples de comparaisons de la différence normalisée de deux nombres réels avec une valeur nulle. Et dans ce post, en comparant la différence des nombres normalisés à zéro (selon ma compréhension du texte des phrases ci-dessus de la Documentation).

C'est à peu près tout, en résumé.

 

gammaray:

...

Pour être honnête, je ne comprends pas vraiment à quoi servira la normalisation de la différence entre les deux valeurs MA.

P./S. : Sur ce point, vous pouvez simplement mettre Print() dans votre code pendant un moment pour voir ce qui sera affiché sur une grande quantité de données. Dans Imprimer, imprimez les valeurs non normalisées et normalisées (jusqu'à une certaine décimale, y compris plus grande que sur le tableau où vous ferez les expériences) obtenues à partir d'opérations mathématiques. Y compris simplement les valeurs iMA normalisées et non normalisées, car elles sont formées sur la base d'opérations mathématiques.

Au cas où, je précise également que lors de l'impression de valeurs non normalisées et normalisées de type double, il convient de les convertir en plus, bien sûr, de la valeur numérique à la valeur texte en utilisant DoubleToString (et en expérimentant dans DoubleToString le nombre de décimales).

 
gammaray:

P./S. : Je veux aussi ajouter que je pense que dans les exemples de n'importe quels schémas écrits pour ceux qui veulent apprendre la programmation MQL4, la normalisation des valeurs des calculs mathématiques peut ne pas être prescrite ou/et pas directement spécifiée :

  • pour faciliter la compréhension des schémas de formation de toutes les conditions ;
  • Une normalisation n'est pas toujours et/ou pas partout nécessaire (on peut notamment supposer qu'il faut appliquer pour différentes tâches des niveaux d'erreurs tolérables et, par conséquent, une normalisation supplémentaire différente (ou l'absence de normalisation) des résultats des opérations mathématiques sur le nombre de décimales pour certaines tâches individuelles) ;
  • et/ou, le plus souvent, on suppose qu'un développeur connaît la documentation et/ou l'a lue, afin de clarifier ses questions.
Quelque chose comme ça.
 
C'est plus précis.
// сравниваем значения и определяем направление пересечения
if (fast0>slow0 && fast1<=slow1) Print("Пересечение ВВЕРХ");
if (fast0<slow0 && fast1>=slow1) Print("Пересечение ВНИЗ");

Je veux dire qu'il n'a pas pris en compte le fait que les valeurs ma pouvaient aussi être égales.

сравнивать вещественные числа на равенство нельзя

légèrement différent.
 
Aleksey Lebedev:
Un peu d'autre chose.

Cela dépend de ce que vous avez en tête et de vos tâches/objectifs.

Donc, en écrivant les messages dans ce fil, je me base sur :

  • La capture d'écran et les questions dans le premier message ;
  • le deuxième message de l'auteur du fil de discussion (sur les dangers de la normalisation),

et, par conséquent, d'ici et, pour le dire brièvement, le sens de mes posts ci-dessus :

Grâce à la normalisation, il est possible de définir/ajuster le niveau de précision requis des comparaisons (et/ou des valeurs de sortie) et/ou les erreurs acceptables pour certaines tâches et certains objectifs, ce qui permet de déclencher les conditions du programme exactement où et comment cela était prévu lors de la prescription de conditions spécifiques dans le code. Et la comparaison de la différence normalisée avec zéro, permet d'ajuster/réajuster non seulement pour les comparaisons utilisant l'opération de relations : "==".


P./S. : Ainsi sur n'importe quel cas je préciserai encore une fois, que la comparaison des nombres réels par la première manière de deux énumérés ici, en raison de la comparaison d'une différence des nombres avec n'importe quelle petite valeur, je ne peux pas nommer pire, que l'application de la normalisation, quand il est nécessaire d'ajuster le niveau des comparaisons (y compris, comme pour moi la deuxième manière a semblé plus commode, la première et n'a pas considéré pour elle-même plus détaillée pour l'application pratique).


 

Cela n'a rien à voir avec mql en principe. Prenons un langage de programmation abstrait. Dans cet exemple particulier que j'ai donné, le problème principal est que les valeurs de la différence des muwings dans une même barre ne sont pas égales (2e-16 dans le premier calcul et exactement 0 dans le second). Dans ce cas, cette intersection ne peut être déterminée d'aucune manière. Si nous revenons à mql, la normalisation implique d'arrondir le nombre (ou plutôt, de laisser tomber tous les nombres après un certain signe, comme dans la fonction Sish floor, mais à une certaine décimale). Alors comment savoir à quel chiffre normaliser ? Si le mauvais chiffre est choisi, toutes les valeurs peuvent TOUJOURS être arrondies à 0 exactement. La normalisation est donc dangereuse ici et ne résout généralement pas le problème.

Quant à ce qu'Alexey Lebedev a écrit. Oui, je pensais dans ce sens. Mais si nous comparons les deux différences par plus ou égale à 0, il y a une probabilité d'obtenir un faux signal (par exemple, la situation théoriquement possible lorsque les muvings entre des barres voisines ont exactement les mêmes valeurs). Alors leur différence ne change pas le signe (il n'y a pas de croisement), mais le signal pour le croisement sera déterminé par programme. Vous pourriez ne mettre qu'une seule comparaison sur plus ou égal, comme vous l'avez suggéré. Mais alors le problème est que dans le calcul, dans cette situation, d'abord il ne sera pas égal à 0 (2e-16), et sur la barre suivante il sera exactement 0 mais ce sera une comparaison stricte.

Il est important de comprendre pourquoi la même différence, lorsqu'elle est calculée sur des barres différentes, ne produit PAS le même résultat. Si le résultat était le même, le problème serait toujours résolu en introduisant une comparaison non stricte

 

gammaray:

Mais alors tout le problème est que lors du calcul dans cette situation, au début il ne sera pas égal à 0 (2e-16), et sur la barre suivante il sera déjà exactement 0, mais il y aura déjà une comparaison stricte.

Il est important de comprendre pourquoi la même différence, lorsqu'elle est calculée sur des barres différentes, ne produit PAS le même résultat. Si le résultat était le même, le problème serait toujours résolu en introduisant une comparaison non stricte

Il est fort probable que le calcul de la fonction iMA soit optimisé. Première valeur = somme(close)/N, deuxième = valeur précédente de la MA+(nouvelle close - ancienne close)/N.