Erreurs, bugs, questions - page 1931

 
Aleksey Vyazmikin:

Dans le service d'assistance

MT4 :

Pour les objets de taille fixe : les propriétés OBJ_BUTTON, OBJ_RECTANGLE_LABEL et OBJ_EDIT OBJPROP_XDISTANCE et OBJPROP_YDISTANCE définissent la position du point supérieur gauche de l'objet par rapport au coin du graphique (OBJPROP_CORNER), à partir duquel les coordonnées X et Y en pixels seront comptées.


MT5 :

Pour les objets de taille fixe : OBJ_BUTTON, OBJ_RECTANGLE_LABEL, OBJ_EDIT et OBJ_CHART, les propriétés OBJPROP_XDISTANCE et OBJPROP_YDISTANCE définissent la position du point supérieur gauche de l'objet par rapport au coin du graphique (OBJPROP_CORNER), à partir duquel les coordonnées X et Y en pixels seront mesurées.

Le problème est que l'ancienne version de MT4 utilisant ObjectSet permet de placer les objets par rapport à leurs bords (coins) - pour les objets dans la partie gauche le calcul des pixels est effectué à partir du premier symbole, pour les objets dans la partie droite - à partir du dernier symbole, tandis que la nouvelle version effectue toujours le calcul à partir du premier symbole, ce qui rend le positionnement des étiquettes avec du texte difficile, parce que vous ne savez pas toujours combien de symboles de texte seront. Je demande aux développeurs d'ajouter un choix de méthode d'alignement du texte !


Si quelqu'un sait comment obtenir un alignement gauche et droit dans MT5, merci de partager la fonction correspondante !

Ne vous mettez pas en colère, mais lisez attentivement l'aide :

Pour les objets OBJ_LABEL, OBJ_BITMAP_LABEL et OBJ_RECTANGLE_LABEL, vous pouvez définir l'angle du graphique par rapport auquel le point d'ancrage de l'objet est positionné. Cet angle est défini via la propriété d'objet OBJPROP_CORNER, qui peut avoir l'une des quatre valeurs de l'énumération ENUM_BASE_CORNER :

Identifiant

Description

COIN_GAUCHE_SUPÉRIEUR

Coordonnées du point d'ancrage par rapport au coin supérieur gauche du graphique

COIN_GAUCHE_INFÉRIEUR

Les coordonnées du point d'ancrage sont données par rapport au coin inférieur gauche de la carte.

COIN_DROIT_INFÉRIEUR

Les coordonnées du point d'ancrage sont définies par rapport au coin inférieur droit du graphique.

COIN_DROIT_SUPÉRIEUR

Les coordonnées du point d'ancrage sont définies par rapport au coin supérieur droit du graphique.

La position du point d'ancrage de l'objet est spécifiée par la propriété OBJPROP_ANCHOR et peut être l'une des 9 valeurs de l'énumération ENUM_ANCHOR_POINT :

Identifiant

Description

ANCRE_GAUCHE_SUPÉRIEURE

Point d'ancrage dans le coin supérieur gauche

ANCRE_GAUCHE

Point d'ancrage à gauche au centre

ANCRE_GAUCHE_INFÉRIEURE

Point d'ancrage dans le coin inférieur gauche

ANCRE_BAS

Point d'ancrage sous le centre

ANCHOR_RIGHT_LOWER

Point d'ancrage dans le coin inférieur droit

ANCHOR_RIGHT

Point d'ancrage à droite au centre

ANCRE_DROITE_SUPÉRIEURE

Point d'ancrage dans le coin supérieur droit

ANCRE_UPPER

Point d'ancrage au centre supérieur

CENTRE D'ANCRE

Point d'ancrage exactement au centre de l'objet

 
Artyom Trishkin:

Dois-je avancer l'élément de la liste que vous essayez d'étiqueter avec le numéro 4, qui n'existe pas ? Il devient zéro - et tout est en place.

Bien sûr, j'ai tout déplacé - je suis peut-être stupide...



void OnStart()
  {
      Label("0",//Название
            0,       //Окно
            10,      //X
            32,      //Y
            "0 - Центр координат в левом верхнем углу графика",
            10,//Размер шрифта
            Yellow,//Цвет шрифта
            0        //Выбор угла: 3 - нижний правый, 1 - верхний правый. 2 - нижний левый, 4 - верхний левый                   
            );     
      Label("1",//Название
            0,       //Окно
            10,      //X
            32,      //Y
            "1 - Центр координат в левом нижнем углу графика",
            10,//Размер шрифта
            Yellow,//Цвет шрифта
            1        //Выбор угла: 3 - нижний правый, 1 - верхний правый. 2 - нижний левый, 4 - верхний левый                   
            );     
      Label("2",//Название
            0,       //Окно
            10,      //X
            32,      //Y
            "2 - Центр координат в правом нижнем углу графика",
            10,//Размер шрифта
            Yellow,//Цвет шрифта
            2        //Выбор угла: 3 - нижний правый, 1 - верхний правый. 2 - нижний левый, 4 - верхний левый                   
            );
      Label("3",//Название
            0,       //Окно
            10,     //X
            32,      //Y
            "3 - Центр координат в правом верхнем углу графика",
            10,//Размер шрифта
            Yellow,//Цвет шрифта
            3      //Выбор угла: 3 - нижний правый, 1 - верхний правый. 2 - нижний левый, 4 - верхний левый                   
            ); 

  }

//+------------------------------------------------------------------+
//|Функция вывода информации на экран -- Старый вариант              |
//+------------------------------------------------------------------+
void Label(string _name,int _window,int _x,int _y,string _text,int _font,color _color,int corner)
  {
   ObjectDelete(_name);
   ObjectCreate(_name,OBJ_LABEL,_window,0,0);
   ObjectSet(_name,OBJPROP_CORNER,corner);
   ObjectSet(_name,OBJPROP_XDISTANCE,_x);
   ObjectSet(_name,OBJPROP_YDISTANCE,_y);
   ObjectSetText(_name,_text,_font,"Arial",_color);
  }
/*
//+------------------------------------------------------------------+
//|Функция вывода информации на экран -- Новый вариант               |
//+------------------------------------------------------------------+
void Label(string _name,int _window,int _x,int _y,string _text,int _font,color _color,int corner)
  {
   //corner=4;
   ObjectDelete(0,_name);
   ObjectCreate(0,_name,OBJ_LABEL,_window,0,0);
   ObjectSetInteger(0,_name,OBJPROP_CORNER,corner);
   ObjectSetInteger(0,_name,OBJPROP_XDISTANCE,_x);
   ObjectSetInteger(0,_name,OBJPROP_YDISTANCE,_y);
   ObjectSetText(_name,_text,_font,"Arial",_color);
  }
*/   
 
Artyom Trishkin:

Et ne vous énervez pas, lisez attentivement l'aide :

Pour les objets OBJ_LABEL, OBJ_BITMAP_LABEL et OBJ_RECTANGLE_LABEL, vous pouvez définir l'angle du graphique par rapport auquel le point d'ancrage de l'objet est positionné. Cet angle est défini via la propriété d'objet OBJPROP_CORNER, qui peut avoir l'une des quatre valeurs de l'énumération ENUM_BASE_CORNER :

Identifiant

Description

COIN_GAUCHE_SUPÉRIEUR

Coordonnées du point d'ancrage par rapport au coin supérieur gauche du graphique

COIN_GAUCHE_INFÉRIEUR

Les coordonnées du point d'ancrage sont données par rapport au coin inférieur gauche de la carte.

COIN_DROIT_INFÉRIEUR

Les coordonnées du point d'ancrage sont définies par rapport au coin inférieur droit du graphique.

COIN_DROIT_SUPÉRIEUR

Les coordonnées du point d'ancrage sont définies par rapport au coin supérieur droit du graphique.

La position du point d'ancrage de l'objet est spécifiée par la propriété OBJPROP_ANCHOR et peut être l'une des 9 valeurs de l'énumération ENUM_ANCHOR_POINT :

Identifiant

Description

ANCRE_GAUCHE_SUPÉRIEURE

Point d'ancrage dans le coin supérieur gauche

ANCRE_GAUCHE

Point d'ancrage à gauche au centre

ANCRE_GAUCHE_INFÉRIEURE

Point d'ancrage dans le coin inférieur gauche

ANCRE_BAS

Point d'ancrage sous le centre

ANCHOR_RIGHT_LOWER

Point d'ancrage dans le coin inférieur droit

ANCHOR_RIGHT

Point d'ancrage à droite au centre

ANCRE_DROITE_SUPÉRIEURE

Point d'ancrage dans le coin supérieur droit

ANCRE_UPPER

Point d'ancrage au centre supérieur

CENTRE D'ANCRE

Point d'ancrage directement au centre de l'objet

Merci, je vais essayer de trouver quelque chose demain...

 
prostotrader:

C'est toujours mieux le matin... :)

C'est souvent le cas :)
 
Le SD dit que c'est la bonne chose à faire dans ce cas.

Forum sur le trading, les systèmes de trading automatisés et les tests de stratégies de trading

Bugs, bugs, questions

fxsaber, 2017.07.18 09:51

Une question presque enfantine : pourquoi est-ce comme ça ?
void OnStart()
{
  const double Norm = NormalizeDouble(8905 / 1000.0, 3);
  Print(Norm); // 8.904999999999999
  Print(DoubleToString(Norm, 3)); // 8.905
  
  const double Norm2 = (double)DoubleToString(Norm, 3);
  Print(Norm2); // 8.904999999999999
  Print(Norm == Norm2); // true
}

Pour une raison quelconque, j'étais sûr que DoubleToString n'avait aucun sens après la normalisation. Mais non, comme le montre le scénario. Pourquoi en est-il ainsi ?

Il semble que la conversion double -> chaîne de caractères ne fonctionne pas correctement.


Cet exemple est assez compliqué à comprendre, je vous en donne donc un autre.

void OnStart()
{
  Print((double)"8.905" == 8.905); // true
  Print(((string)(double)"8.905")); // 8.904999999999999
}

Voilà ce que je veux dire.

Строковая в double переводится без проблем. Обратно - получаем другой результат.

J'ai pris la chaîne "8.905", je l'ai convertie en double et immédiatement en chaîne, et j'ai obtenu 8.9049999999999999999. Mais la première ligne de OnStart montre que (double) "8.905" == 8.905. C'est-à-dire que 8,905 devrait être imprimé.

Bien sûr, la situation évidente de fin zéro ne devrait pas fonctionner :

Si la condition(double) "8.9050" == 8.9050est remplie, alors la condition(chaîne)(double) "8.9050" == "8.9050"devrait également être remplie.

Après avoir étudié un peu le problème, j'en suis arrivé à la situation suivante

void OnStart()
{
  const double Num = 8.274;
  const double Norm = NormalizeDouble(Num, 3);
  
  Print(Num);  // 8.273999999999999
  Print(Norm); // 8.274000000000001
}

Veuillez expliquer pourquoi la conversion double -> chaîne est toujours considérée comme correcte. Le dernier exemple m'épate complètement.

 
fxsaber:

Veuillez expliquer pourquoi la conversion double -> chaîne est toujours considérée comme correcte. Le dernier exemple est complètement hallucinant.

Commentaire sur le dernier exemple

Les nombres réels peuvent être considérés comme identiques s'ils ont subi les mêmes conversions. Même des conversions apparemment identiques - num*0,5 et num/2,0 - donnent des résultats différents. On peut dire la même chose des opérations en miroir. num*=num2, num/=num2. Le nombre résultant ne sera pas égal au nombre original. Bienvenue dans le monde des nombres réels.

Pendant le processus de normalisation, 3 opérations ont été effectuées dans cet échantillon avec un nombre réel - num*=1000, num+=0.5, num/=1000.

Vous pouvez vérifier les étapes dans le débogueur

 
fxsaber:
SD dit qu'il est correct dans ce cas.

Pourquoi est-ce que ça prête à confusion ?

La grande majorité des nombres réels décimaux ne sont pas représentables sous forme de fraction binaire sans reste. Si vous ajoutez à cela un double format de stockage, vous obtenez des choses bien moches.

En fait, le type décimal serait bien, c'est pratique.

 
Slava:

Commentaire sur le dernier exemple

Les nombres réels peuvent être considérés comme identiques si les mêmes conversions sont effectuées sur eux. Même des conversions apparemment identiques - num*0,5 et num/2,0 - donnent des résultats différents. On peut dire la même chose des opérations en miroir. num*=num2, num/=num2. Le nombre résultant ne sera pas égal au nombre original. Bienvenue dans le monde des nombres réels.

Dans cet exemple, 3 opérations - num*=1000, num+=0.5, num/=1000 - ont été effectuées sur un nombre réel pendant la normalisation.

Vous pouvez vérifier les étapes dans le débogueur


Explication très constructive, merci !


Mais ce contre-exemple m'épate.

void OnStart()
{
  const double Num = 8.274;
  const double Norm = NormalizeDouble(Num, 3);
   
  Print(Num);  // 8.273999999999999
  Print(Norm); // 8.274000000000001
  
  Print((double)DoubleToString(Num, 3) == Num);     // true - без нормализации все замечательно
  Print((double)DoubleToString(Norm, 3) == Norm);   // false - а после нормализации полный облом!
}

Est-ce ainsi que la normalisation est censée fonctionner ?

 
Комбинатор:

Pourquoi est-ce que ça prête à confusion ?

Après l'explication de Slava, cela ne prête pas à confusion, mais il y a ensuite un exemple qui nous fait douter de la justesse de NormalizeDouble lui-même.

 
Комбинатор:

D'une manière générale, le type décimal serait utile, c'est une chose pratique.

Oui, son absence dans les logiciels qui fonctionnent avec les prix a été pour le moins déroutante depuis le début de l'existence de MT.

PS. Maintenant, avec l'existence du langage OOP, MQ pense probablement que ceux qui le souhaitent peuvent écrire une classe pour eux-mêmes. Seulement, vous ne pouvez pas le mettre dans une structure simple par la suite - vous devriez le sérialiser/désérialiser en quelque chose de simple comme ulong.