Erreurs, bugs, questions - page 105

 
Interesting:

Le testeur possède sa propre liste d'outils et doit être généré (de préférence lors de l'initialisation de l'expert).

Merci beaucoup ! Je l'ai. J'ai raté beaucoup de choses...
 
Renat:

Le code était approximatif (copié à partir de deux pièces), mais vos commentaires sont corrects.

Voici la version corrigée :

J'ai ajouté quelques appels à la fonction Print() pour montrer clairement comment elle fonctionne :

double CalculateMaxVolume(string symbol)
  {
   double price=0.0;
   double margin=0.0;
//--- select lot size
   if(!SymbolInfoDouble(symbol,SYMBOL_ASK,price))                return(0.0);
   if(!OrderCalcMargin(ORDER_TYPE_BUY,symbol,1.0,price,margin)) return(0.0);
   if(margin<=0.0)                                            return(0.0);

   double lot_pure=AccountInfoDouble(ACCOUNT_FREEMARGIN)/margin;
   double lot=NormalizeDouble(lot_pure,2);
   Print("lot_pure = ", lot_pure, ", lot = ", lot);
//--- normalize and check limits
   double stepvol=SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP);
   if(stepvol>0.0)
     {
      double newlot=stepvol*NormalizeDouble(lot/stepvol,0);
      if(newlot>lot) { Print("Чёрт побери: lot = ", lot, ", newlot = ", newlot);
                       lot=NormalizeDouble(newlot-stepvol,2);
                     }
      else           lot=newlot;
     }

   double minvol=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN);
   if(lot<minvol) lot=0.0;   // 

   double maxvol=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX);
   if(lot>maxvol) lot=maxvol;
//--- return trading volume
   return(lot);
  }

void OnStart()
{
  Print("CalculateMaxVolume(Symbol()) = ", CalculateMaxVolume(Symbol()));
}

/* Вывод в лог (хронология - сверху вниз)
CO      0       1 (EURUSD,M15)  01:40:33        lot_pure = 7.799703611262773, lot = 7.8
JG      0       1 (EURUSD,M15)  01:40:33        Чёрт побери: lot = 7.8, newlot = 7.800000000000001
MQ      0       1 (EURUSD,M15)  01:40:33        CalculateMaxVolume(Symbol()) = 7.7
*/

Il fonctionne correctement maintenant. Mais avec une réserve - dans les conditions que l'on rencontre actuellement. S'ils sont étendus à l'avenir, ce code commencera à faire des erreurs dans certains cas et sous certaines conditions. Je vais l'expliquer ci-dessous.

En fait, j'ai dû faire quelques recherches et j'ai obtenu des résultats très intéressants. Mais parlons-en un par un.

La première chose qui me saute aux yeux est la suivante : pourquoi ai-je dû danser autant avec NormalizeDouble() ? Alors, que fait NormalizeDoubel() ? Lie une valeur libre à la grille. Par exemple, dans ce fragment de code :

double lot=NormalizeDouble(lot_pure,2);

NormalizeDouble() prend comme paramètre lot_pure (valeur libre, c'est-à-dire celle calculée par la marge libre et la marge nécessaire pour 1 lot sans aucun arrondi et autre liaison) et donne la valeur, liée à la valeur la plus proche de la grille avec départ à 0 et pas 0.01.
Il est important de noter ici : au nœud le plus proche de la grille, y compris le plus grand!

A quoi sert cette liaison à cet endroit du code ? Et pourquoi à la grille de 0,01 et pas à, disons, 0,001 ?

D'ailleurs, nous pouvons voir que le résultat marqué par CO dans le journal (la première ligne du fragment montré) a entraîné l'augmentation de la valeur.

De plus, nous savons que toutes les fonctions commerciales qui acceptent le nombre de lots comme l'un des paramètres, exigent que cette valeur soit liée à la grille : minvol + N * stepvol, où N est un nombre entier compris entre 0 et la valeur d'une partie entière de l'expression (maxvol - minvol) / stepvol. En conséquence, la valeur du lot libre obtenue dans ce fragment :

double lot_pure=AccountInfoDouble(ACCOUNT_FREEMARGIN)/margin;

doit être lié au nœud le plus proche de la grille spécifiée : minvol + N * stepvol. Cela signifie que vous devez d'abord soustraire minvol de la valeur de lot avant de diviser par stepvol (pour obtenir cet entier N), et après avoir multiplié par N, ajouter minvol. Mais vous divisez immédiatement par stepvol, en supposant implicitement que stepvol est le diviseur de minvol, c'est-à-dire qu'il correspond à un nombre entier de fois, car ce n'est que si cette condition est remplie que vous pouvez "simplifier" de cette manière sans obtenir d'effets secondaires :

double newlot=stepvol*NormalizeDouble(lot/stepvol,0);

Vous utilisez à nouveau NormalizeDouble(), mais cette fois pour vous lier à une grille dont le point de départ est 0 et l'étape 1, c'est-à-dire à des entiers. Les paramètres de liaison au maillage sont corrects, mais l'outil d'accrochage est un peu malheureux : il se lie au nœud de maillage le plus proche, y compris un plus grand s'il se trouve être plus proche. Et dans notre cas, cela conduira à l'élaboration obligatoire ultérieure d'un code de correction. Pourquoi ne pas utiliser ici un merveilleux outil de liaison à "une grille d'entiers" en utilisant, au lieu d'appeler NormalizeDouble(), un cast vers un type d'entier qui n'incrémente pas la valeur castée, mais la décrémente seulement à l'entier le plus proche si nécessaire, c'est-à-dire ce dont nous avons besoin ?

Mais un artefact plus intéressant se produit ici qui est prouvé dans la deuxième ligne du fragment cité marqué avec JG. Il s'avère que l'expression "0.1 * NormalizeDouble(7.8 / 0.1)" donne le résultat 7.800000000000001, ce qui fait que le code de correction fonctionne ! Pourquoi auriez-vous besoin d'un code dont les performances sont si faibles qu'il faut lui ajouter un correcteur ?

Il est clair que le code de liaison à la grille des valeurs de lot acceptables doit être remplacé par un meilleur code.

Bien sûr, nous pouvons aussi laisser ce code - après tout, la partie de correction du code, le cas échéant, fonctionnera. La troisième ligne du journal le prouve : le résultat est finalement vrai. Mais ce code, en revanche, est un indicateur du professionnalisme et de la qualité de ses créateurs. Y compris la qualité du code de la plateforme MT5. Et la preuve en sera donnée par moi, car je suis tombé sur deux bugs à la suite de mes recherches.

A propos, regardons à nouveau le code de liaison initiale de la valeur calculée de lot_pure et le code de correction :

double lot=NormalizeDouble(lot_pure,2);
...
lot=NormalizeDouble(newlot-stepvol,2);
Dans les deux cas, il y a une liaison avec la grille avec le pas 0.01. Pourquoi cette grille ? Parce que vous voulez vous lier à la grille minvol + N * stepvol qui a un stepvol. Que se passera-t-il lorsque, à l'avenir, nous aurons à la fois une valeur de lot minimale et un stepvol de 0,001 ?

C'est très simple - le code donnera des résultats erronés dans les cas où, dans le processus de liaison à la grille avec le pas 0,01, la valeur libre change sur la valeur plus de 0,001. C'est l'avertissement que j'ai mentionné au début.

En cas d'"arrondi vers le haut" de plus de 0,001, les valeurs de lot seront renvoyées avec une marge libre insuffisante pour ouvrir la position, tandis qu'en cas d'"arrondi vers le bas" du même montant - valeurs sous-évaluées ou 0, si la valeur libre est dans la plage de 0,001 - 0,004999...

C'est-à-dire que le code contient un bogue potentiel pour l'avenir. C'est une question de professionnalisme des développeurs et de qualité de leur code.

Maintenant, en tenant compte de ce que j'ai trouvé, je vais proposer ma propre variante de la fonction :

double CalculateMaxVolume_New(string symbol)
{
  double stepvol = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
  double minvol  = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
  double maxvol  = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);

  // Не доверяем значениям, которые вернули функции
  if(stepvol > 0 && minvol > 0 && maxvol > minvol)
  {
    double tmp = 0;

    // Вычисляем цену Ask, Margin на 1 лот, лотов на FreeMargin
    if(SymbolInfoDouble(symbol, SYMBOL_ASK, tmp)            && tmp > 0       &&
       OrderCalcMargin(ORDER_TYPE_BUY, symbol, 1, tmp, tmp) && tmp > 0       &&
       (tmp = AccountInfoDouble(ACCOUNT_FREEMARGIN) / tmp)         >= minvol &&
       tmp < ULONG_MAX * stepvol)
    {
      Print("pure_lot = ", tmp); // Эту строку нужно удалить из рабочего кода

      if(tmp > maxvol) // Здесь в tmp содержится недискретизированное число лотов
        return maxvol;

      // Привязываемся к сетке дискретизации
      return minvol + stepvol * (ulong)((tmp - minvol) / stepvol);
    }
  }

  return 0;
}

void OnStart()
{
  Print("CalculateMaxVolume_New(Symbol()) = ", CalculateMaxVolume_New(Symbol()));
}

/* Вывод в лог (хронология - сверху вниз)
LQ      0       1 (EURUSD,M15)  01:39:07        pure_lot = 7.799095304944626
KD      0       1 (EURUSD,M15)  01:39:07        CalculateMaxVolume_New(Symbol()) = 7.7
*/

Il y a plusieurs cas, par rapport à la valeur des lots (stockée dans mon tmp), calculée mais pas encore liée à une grille de valeurs valides. Appelons la valeur de la grille discrétisée.

1. Le cas où tmp < minvol. Dans ce cas, l'inégalité subsistera également après la discrétisation de tmp, car le processus de discrétisation n'implique que la réduction de la valeur calculée (sinon il n'y a pas assez de marge libre, car la valeur calculée est la valeur maximale possible pour la quantité donnée de marge libre).

Ce cas peut donc être éliminé à un stade précoce, avant l'échantillonnage.

2. Le cas où tmp > maxvol. Dans ce cas, la limite n'est pas la marge libre, mais le nombre maximal de lots acceptés par les fonctions de négociation. Dans ce cas, il suffit de retourner la valeur de maxvol.

Pour retourner simplement la valeur de maxvol, aucun échantillonnage de tmp n'est nécessaire, donc ce cas est également coupé avant le code d'échantillonnage.

3. Le cas où minvol <= tmp <= maxvol. Dans ce cas, il est nécessaire de discrétiser, mais la valeur discrétisée reste dans une inégalité pour ce cas, c'est-à-dire qu'il n'est pas nécessaire de corriger quoi que ce soit après la discrétisation.

Le code d'échantillonnage est simple et efficace :

return minvol + stepvol * (ulong)((tmp - minvol) / stepvol);

Ici, l'expression "(tmp - minvol) / stepvol" calcule le même nombre N (le paramètre de la grille d'ancrage), mais avec une partie fractionnaire. Comme l'inégalité minvol <= tmp (cas 3) est remplie ici, il est ainsi garanti que la valeur calculée est non négative. Ensuite, nous convertissons explicitement la valeur calculée en une valeur de type ulong. C'est ulong parce qu'il est garanti que la valeur calculée est non négative.

Lors de la conversion en type entier, la partie fractionnaire du type réel est rejetée. Il ne s'agit pas d'un arrondi à l'unité la plus proche, mais la partie fractionnaire est écartée, ce qui garantit que la valeur maximale des lots, que la marge libre permet, ne sera pas augmentée. C'est exactement ce dont nous avons besoin.

Puisque la valeur entière de N est obtenue, alors la valeur discrétisée maximale du nombre de lots, qui permet la marge libre, est obtenue de la manière standard (c'est-à-dire que l'entier suivant dans la grille des valeurs discrétisées des lots ne permettra pas la marge libre, alors que le N obtenu permettra toujours la marge libre) : "minvol + stepvol * N".

Je voudrais souligner un point très important. Le fait est que les nombres de type double peuvent prendre des valeurs maximales jusqu'à environ 1.8e308, alors que les nombres de type ulong - seulement environ 1.8e19 (c'est juste une entrée pour la commodité, la constante 1.8e19 elle-même n'est pas de type ulong).

Que se passe-t-il si la valeur de l'expression "(tmp - minvol) / stepvol" dépasse 1.8e19 ? Dans ce cas, lors de la conversion au type ulong, une "coupure" se produira - la valeur sera le reste de la division entière de la valeur de l'expression par ULONG_MAX.

Si les nombres n'étaient pas si grands, en termes de MQL5, cela ressemblerait à "X % ULONG_MAX", où X est un entier égal à "(tmp - minvol) / stepvol".

Ce n'est pas un cas typique, mais pourquoi laisser des bogues dans le code ? De plus, on ne peut pas faire confiance aux fonctions de la bibliothèque MQL5, elles peuvent renvoyer n'importe quelle absurdité (je vais en donner la preuve).

Pour les cas où la valeur de l'expression "tmp / stepvol" ne correspond pas à 1.8e19, nous avons volontairement introduit une vérification (la dernière ligne de la condition if) :

tmp < ULONG_MAX * stepvol

Bien sûr, vous pouvez écrire "tmp / stepvol < (double)ULONG_MAX" mais premièrement, j'essaie d'éviter les opérations de division lorsqu'il n'y a pas de nécessité explicite et deuxièmement, je devrais effectuer une conversion de type explicite puisque la constante ULONG_MAX est de type ulong, Lors de la comparaison des opérandes, ils ne sont pas implicitement castés vers un type supérieur (du moins c'est le cas en C/C++), et dans le troisième - je n'aurais pas rencontré un beau bug dans le langage lui-même, pas même dans les fonctions de la bibliothèque - le bug n'est pas celui de l'ADN, mais littéralement dans les molécules et les atomes de MQL5.

L'opérande gauche de l'opération de comparaison est tmp et a le type double tandis que l'opérande droit est l'expression "ULONG_MAX * stepvol" et a également le type double.

Cette expression a deux opérandes, l'un de type ulong et l'autre de type double. Selon les règles de la conversion de type implicite, l'opérande du type inférieur est d'abord converti en opérande du type supérieur, l'opération est exécutée et le résultat est converti en opérande du type supérieur. Le type double est plus "ancien" que le type ulong, c'est pourquoi la valeur ULONG_MAX de ulong est implicitement convertie en double, l'opération est effectuée et le résultat est de type double.

Cependant, il y a un bogue ici qui, soit dit en passant, n'apparaît pas toujours mais seulement dans certains cas dont celui-ci, et le bogue consiste en ce que le résultat de l'expression "ULONG_MAX * stepvol" est seulement la valeur de stepvol.

Par conséquent, la fonction que j'affiche ne fonctionne pas et ne fonctionnera pas tant que les développeurs de MetaQuotes n'auront pas corrigé ce bug.

Pour commencer à utiliser cette fonction dès maintenant, vous devez profiter de la particularité de ce bogue : il disparaîtra si vous effectuez une conversion de type explicite :

tmp < (double)ULONG_MAX * stepvol

Pour en revenir à la vérification décrite, elle garantit que la valeur de l'expression "tmp / stepvol" ne dépassera pas ULONG_MAX. Mais le code d'échantillonnage utilise l'expression "(tmp - minvol) / stepvol".

La valeur de cette expression ne dépassera pas non plus ULONG_MAX car les vérifications précédentes garantissent que minvol > 0 et tmp >= minvol, c'est-à-dire que tmp - minvol < tmp.

Par conséquent, la garantie de ne pas dépasser ULOMG_MAX s'applique également à l'expression "(tmp - minvol) / stepvol".

En règle générale, l'une des principales différences entre un professionnel et un profane est qu'un professionnel peut au moins garantir quelque chose, alors qu'un profane...

J'ai démonté les deux bugs trouvés dans l'autrepost, en clarifiant en même temps ce que MetaQuotes a fait et n'a pas réussi à faire.

 

Для чего в этом месте кода выполняется эта привязка? И почему именно к сетке 0.01, а не к, скажем, 0.001?

Dans le système, le lot minimum = 0.01


Notes :

  1. Votre condition initiale minvol + N * stepvol n'est pas garantie d'être correcte, vous pouvez définir minlot à une valeur différente et votre logique sera brisée.
  2. Vous auriez dû passer à ulong pour rien - vous vous êtes créé des difficultés et vous avez ensuite écrit une page entière de réflexions à ce sujet.
  3. La substitution de tmp dans votre code est trop astucieuse, ma version est beaucoup plus claire en termes d'opérations
 

Je ne parle que pour moi (mais si vous voyez votre reflet, vous n'êtes pas le seul).

Au cours des derniers mois de la chasse aux bugs, j'ai pris l'habitude de considérer d'abord un programme qui ne fonctionne pas comme un bug dans MetaTrader.

Pourquoi ? Il s'agit simplement d'un modèle bien testé, si quelque chose ne fonctionne pas, c'est un bogue et il faut tirer la sonnette d'alarme.

Exemple : j'ai trouvé un bug, j'ai envoyé une demande à Servicedesk, ils ont écrit un code de vérification, mais rien.

J'ai fait une nouvelle demande et, dans l'attente d'une réponse, j'ai découvert ma maladresse.

Le résultat est que j'ai honte d'avoir distrait les gens sur place.

Mais en analysant le flux des messages, je comprends que la masse des gens, même s'ils sont intelligents, est toujours soumise à la psychologie de la foule.

S'il y a des bogues, j'écrirai un bogue et laisserai Renat trier mon code et pointer du doigt mon erreur.

Je comprends que la tolérance ne permet pas de dire : oui tu es un crétin, ton code est tordu.

Mais vous ne pouvez pas aller aussi loin, et le prolongeant encore tout le personnel MQ sera bientôt engagé dans que s'asseoir sur les codes d'autres personnes dans la contemplation pleurnicharde "mais pourquoi avons-nous besoin de tout cela", alors que le championnat est à venir, et là et aller aux comptes réels ne sont pas loin.

Je vais conclure, ma devise pour aujourd'hui est "Si vous allez publier un bug, vérifiez si le problème est entre vos mains".

Общайтесь с разработчиками через Сервисдеск!
Общайтесь с разработчиками через Сервисдеск!
  • www.mql5.com
Ваше сообщение сразу станет доступно нашим отделам тестирования, технической поддержки и разработчикам торговой платформы.
 

Nouvelle construction - nouveaux problèmes. Expert, qui a fonctionné sans problème dans la 306 après la compilation dans la 314 (compilation sans erreurs), abandonne dans le testeur :

2010.08.21 17:03:36 Core 1 déconnecté
2010.08.21 17:03:36 Core 1 testeur arrêté car OnInit a échoué
2010.08.21 17:03:36 Core 1 2010.01.04 00:00:00 Violation d'accès en lecture à 0x0000000000000014
2010.08.21 17:03:36 Core 1 2010.01.04 00:00:00 Balance=10000.00 Equite=10000.00 Profit=0.00
2010.08.21 17:03:36 Core 1 2010.01.04 01.04 00:00:00 PriceChannel_multi_Ch_Timer Expert Advisor a commencé à travailler en 2010.01.04 00:00 sur le graphique EURUSD pour la période H1

Il se décharge aussi dans la vie réelle. Il est apparu que la source de l'erreur est une ligne

m_symbol[j].Name(TradeSymbols[i]);

En le remplaçant par quelques lignes

string curSymbol=TradeSymbols[i];
m_symbol[j].Name(curSymbol);

a retourné le statu quo au conseiller expert.

Qu'est-ce qui se passe ?

D'ailleurs, le code compilé dans la dernière version fonctionne bien dans celle-ci.

 
Valmars:

Qu'est-ce qu'il y a ?

D'ailleurs, le code compilé dans la dernière version fonctionne bien dans celle-ci également.

Notre erreur - nous allons certainement la réparer.
 
Renat:

Lot minimum = 0,01


Notes :

  1. Votre condition initiale minvol + N * stepvol n'est pas garantie d'être correcte, vous pouvez définir minlot à une valeur différente et votre logique sera brisée.
  2. Vous n'auriez pas dû passer à ulong - vous vous êtes créé des difficultés et avez ensuite écrit une page entière de réflexions à ce sujet.
  3. La substitution de tmp dans votre code est trop intelligente, alors que ma version est beaucoup plus claire en termes d'opérations.

Actuellement, le lot minimum du système est de 0,01. Mais qu'en sera-t-il dans un an ? Dans deux ans ?

1) Quelle condition est correcte ? Quelle est donc la formule correcte ? Disons, pour minvol = 0,15 et stepvol = 0,1 - quelles seraient les premières valeurs de lot valides ? a) 0,15, 0,25, 0,35... ? б) 0.15, 0.2, 0.3... ? в) ... ? J'ai supposé que la variante a.

2. Je suis passé à l'ulong pour une raison : j'ai le droit de choisir le type avec la gamme la plus large, afin qu'il suffise pour le plus grand nombre de cas possibles, car ces fonctions sont des briques très basiques. Et le fait que j'aie rencontré un bug ne signifie pas que c'est moi qui ai créé les problèmes. :) Le raisonnement écrit plus pour les autres afin de le faire comprendre au plus grand nombre - nous n'avons pas ici une correspondance personnelle.

3. La substitution n'est pas délicate - il suffit d'économiser, afin de ne pas créer des variables à usage unique. Et il a été contrôlé et vérifié que la variable est passée par référence lorsqu'une fonction est appelée au maximum une fois, de sorte que d'éventuelles erreurs sont évitées à cause de cela. Si cela dérange certains d'entre nous, nous pouvons créer une variable pour chaque valeur transférée (même une valeur intermédiaire, comme le prix de vente), comme vous l'avez fait. Ce point n'est pas important.

Beaucoup plus important est le mécanisme de liaison à la grille des valeurs admissibles, qui, en outre, ne nécessite pas de correction, et qui garantit contre l'apparition de pépins dans différents cas peu typiques, tout en maintenant la plus grande simplicité possible.

Le principe est que le bloc de construction de base doit être aussi robuste et polyvalent que possible - alors la maison entière survivra probablement même à un tremblement de terre.

 
Urain:

Je ne parle que pour moi (mais si vous voyez votre reflet, vous n'êtes pas le seul).

Au cours des derniers mois de la chasse aux bugs, j'ai pris l'habitude de considérer d'abord un programme qui ne fonctionne pas comme un bug dans MetaTrader.

Pourquoi, c'est juste un modèle bien établi, si quelque chose ne fonctionne pas, alors c'est un bug et il faut tirer la sonnette d'alarme.

Le fait que les bugs de MQL5 et MQL5 ressemblent beaucoup aux leurs joue un rôle important ici. Et il y a beaucoup de bogues de MQL5.

Si MQL5 avait beaucoup moins de bogues et s'ils n'étaient pas si simples, il serait beaucoup plus difficile de les confondre.

Urain:

Ils ont déjà commencé à réfléchir à la possibilité de lancer le championnat, qui est sur le point de commencer la véritable session de négociation.

Je vais conclure, la devise d'aujourd'hui est "Si vous allez publier un bug, vérifiez si le problème est entre vos mains".

Le fait que le Championnat pour les conseillers experts écrits UNIQUEMENT en MQL5 est un pari était clair au moment où la décision a été annoncée. Mais la direction de l'EA a sa propre vision. Ils l'ont décidé eux-mêmes. Personne n'a interféré avec leur décision. Et alors, qu'importe si le championnat est au coin de la rue, ils ont fait leur vie.

Ici, c'est facile : vous devez travailler sur la localisation du bogue : commencez à retirer du code tout ce qui n'affecte pas le bogue. Enfin, vous obtiendrez une sorte d'exemple de test, qui est assez petit mais qui démontre principalement le bug. Ce ne sera plus "le code de quelqu'un d'autre" mais "le code qui démontre le bug MQL5".

 
Rédaction d'un script pour tester la fonction OrderCalcMargin()
void OnStart()
  {
//---
   int total=SymbolsTotal(false);
   double marginbay;
   double marginsell;
   MqlTick last_tick;
   for(int i=0;i<total;i++)
     {

      string symbol=SymbolName(i,false);
      Print("************************************************");
      Print("Инструмент - ",symbol);
      Print("Валюта депозита = ",AccountInfoString(ACCOUNT_CURRENCY));
      Print("Базовая валюта = ",SymbolInfoString(symbol,SYMBOL_CURRENCY_BASE));
      Print("Валюта маржи = ",SymbolInfoString(symbol,SYMBOL_CURRENCY_MARGIN));
      if(SymbolInfoTick(symbol,last_tick))
        {
         OrderCalcMargin(ORDER_TYPE_BUY,symbol,1.0,last_tick.ask,marginbay);
         OrderCalcMargin(ORDER_TYPE_SELL,symbol,1.0,last_tick.bid,marginsell);
         Print("Маржа для покупки = ",marginbay);
         Print("Маржа для продажи = ",marginsell);
        }
      else Print("SymbolInfoTick() failed, error = ",GetLastError());
     }
  }
//+------------------------------------------------------------------+
La fonction renvoie zéro pour certains instruments, s'agit-il d'un bug ou est-ce conçu de cette façon ?
 
sergey1294:
J'ai écrit un script pour vérifier la fonction OrderCalcMargin(). La fonction renvoie zéro pour certains symboles.

C'est probablement pour les symboles qui ne sont pas dans MarketWatch, car SymbolName est dit être pour SymbolName:

Nom du symbole

Renvoie le nom du symbole spécifié.

stringSymbolName(
intpos,// numéro dans la liste
bool selected// true - seulement les symboles dans MarketWatch
) ;

Paramètres

pos

[in] Numéro du symbole dans l'ordre.

sélectionné

[en] Mode d'interrogation. Si c'est vrai, alors le symbole est pris dans la liste des sélectionnés dans MarketWatch. Si la valeur est false, alors le symbole est pris dans la liste commune.

Valeur retournée

Valeur de type chaîne de caractères avec le nom du symbole.

Imprimez le nom du symbole pour lequel vous obtenez un résultat inattendu et comparez-le à la liste de MarketWatch.
Raison: