Bibliothèque de classes génériques - bogues, description, questions, caractéristiques d'utilisation et suggestions - page 14

 
Sergey Dzyublik:

Pour ma part, si un objet n'implémente pas une interface ou une méthode, il est préférable de générer une exception plutôt que de garder le silence et de chercher ensuite la source du problème.

  • Dans MQL5, il n'y a pas d'interfaces.
  • Il n'y a pas d'exception dans MQL5.

Et à la fin, vous obtenez un noble autodafé et une dissimulation évidente du problème avec le code.

 
Vasiliy Sokolov:

Pour la même raison, la comparaison est incorrecte. Comment pouvez-vous comparer CHashMap personnalisé et travailler avec les fonctions du système pour obtenir un environnement de trading ?

Continuez à écrire du code sous-optimal puisque vous n'acceptez pas les arguments à toute épreuve.

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

Bibliothèque de classes génériques - bogues, description, problèmes, cas d'utilisation et suggestions

fxsaber, 2017.12.08 22:46

Pour un cas de test plus réaliste (2000 transactions et 1 000 000 d'accès à l'historique unique), le résultat ressemble à ceci

2017.12.05 00:00:00   Time[Print(SumProfit(Deals,GetDealProfitFull))] = 122969
2017.12.05 00:00:00   Time[SetHashMap()] = 816
2017.12.05 00:00:00   4829800340.792288
2017.12.05 00:00:00   Time[Print(SumProfit(Deals,GetDealProfitHashClear))] = 23852
2017.12.05 00:00:00   Time[HistorySelect(0,INT_MAX)] = 1
2017.12.05 00:00:00   4829800340.792288
2017.12.05 00:00:00   Time[Print(SumProfit(Deals,GetDealProfitClear))] = 114427

Près de 100 ms d'économie par passage ! Si, par exemple, nous effectuons l'optimisation pour 10 000 passages complets, la variante Hash sera finalement 15 minutes plus rapide.

Vasiliy Sokolov:

Dans l'ensemble, oui, c'est un noble autodestruction et une dissimulation apparente du problème avec le code.

Ils ont tous deux écrit des bêtises et n'ont pas compris que HashMap dans sa forme actuelle ne fonctionne pas pour les structures et les unions.
 
fxsaber:

Continuez à écrire du code sous-optimal si vous n'acceptez pas des arguments irréfutables.

Vous avez tous deux écrit des absurdités, sans comprendre le moins du monde que HashMap dans sa forme actuelle ne fonctionne pas pour struct et union.

Mon cher, si tu fumes quelque chose et que tu es incapable de lire attentivement le message de ton interlocuteur - alors c'est ton problème et ce n'est pas tout le monde qui a besoin de traitement, mais seulement la personne malade.
Je le répète : personne n'a soulevé la question de la structure et de l'union, personne n'a contesté vos idées sur le sujet.....


C'était spécifiquement sur ces termes de code.
De la bibliothèque standard :

//+------------------------------------------------------------------+
//| Returns a hashcode for custom object.                            |
//+------------------------------------------------------------------+
template<typename T>
int GetHashCode(T value)
  {
//--- try to convert to equality comparable object  
   IEqualityComparable<T>*equtable=dynamic_cast<IEqualityComparable<T>*>(value);
   if(equtable)
     {
      //--- calculate hash by specied method   
      return equtable.HashCode();
     }
   else
     {
      //--- calculate hash from name of object
      return GetHashCode(typename(value));
     }
  }
//+------------------------------------------------------------------+



Et ceux que vous avez ajoutés :

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

Bibliothèque de classes génériques - bogues, description, problèmes, cas d'utilisation et suggestions

fxsaber, 2017.12.08 21:17

Ajout d'une autre surcharge

template<typename T>
int GetHashCode(T &value)
  {
    return GetHashCode(typename(value));
  }


Ce que tu essayais de faire passer :
Le hachage est utilisé pour accélérer la recherche d'éléments dans un conteneur. La vitesse est de O(1) - elle ne dépend pas du nombre d'éléments ajoutés au conteneur.
Situation - l'utilisateur utilise sa propre classe comme clé.
1) En raison de l'absence d'héritage multiple des interfaces(il n'y a pas d'interfaces dans MQL5), l'utilisateur ne peut pas hériter de IEqualityComparable ;
2) L'utilisateur oublie également d'indiquer une spécification explicite pour la fonction de modèle GetHashCode.

Les conséquences - l'utilisateur n'est pas informé qu'il a omis quelque chose et le code est exécuté avec succès sans générer d'exceptions(il n'y a pas d'exceptions dans MQL5).
La vitesse passe de O(1) avec une constante de calcul de hachage moyenne à O(n) avec une constante assez grande en comparaison.
Ce n'est qu'avec un grand nombre d'éléments dans un conteneur et en perdant beaucoup de temps à chercher un
goulot d'étranglement dans l'implémentation que l'utilisateur pourra trouver la cause des problèmes - l'absence d'une spécification GetHashCode explicite pour sa classe.
Sans vouloir vous offenser, merci.

 
Mais pourquoi toutes ces choses indubitablement cool pour le commerce ?
Je n'ai jamais eu à récupérer des milliers de transactions dans l'historique, à rechercher les ordres qui les ont générées, etc.
 
Sergey Dzyublik:

Cher Monsieur, si vous fumez quelque chose et que vous ne pouvez pas lire attentivement le post de votre interlocuteur, c'est votre problème et ce n'est pas tout le monde qui doit être soigné, mais seulement la personne malade.

Apparemment, il n'y a aucun moyen pour les abstinents de fermer la mitaine.

#include <TypeToBytes.mqh> // https://www.mql5.com/ru/code/16280
#include <crc64.mqh>       // https://www.mql5.com/en/blogs/post/683577

template<typename T>
int GetHashCode( T &value )
{
  ulong crc = 0;

  return((int)crc64(crc, _R(value).Bytes, sizeof(T)));
}

template<typename T>
int GetHashCode( T &value[] )
{
  ulong crc = 0;

  return((int)crc64(crc, _R(value).Bytes, ArraySize(value) * sizeof(T)));
}
 
Les commentaires non pertinents pour ce sujet ont été déplacés vers "Algorithmes, méthodes de solution, comparaison de leurs performances".
 

Bien qu'il n'ait pas été prévu à l'origine qu'il s'agisse d'un recueil d'exemples, je ressens tout de même le besoin d'ajouter quelques exemples afin que ceux qui n'ont pas encore utilisé ces algorithmes dans leur pratique puissent comprendre pourquoi ils sont pratiques et, surtout, simples.

 

Exemple 1 : association d'une erreur d'exécution à sa description sous forme de chaîne de caractères

Il est souvent nécessaire de traduire des constantes numériques en chaînes de caractères. Par exemple, il est préférable de dupliquer les codes d'erreur avec une légende claire décrivant l'erreur. Ce n'est pas une tâche très difficile et elle est généralement résolue par une fonction spéciale, un boîtier de commutation ou de nombreux "si" :

string ErrorDescription(int error_code)
   if(error_code == 40001)
      return ("Неожиданная внутренняя ошибка");
   //...
}

Toute solution de ce type a droit à la vie. Mais nous allons décrire ici une solution basée sur CHashMap et vous montrer ses avantages.

L'algorithme peut ressembler à ceci :

  • Nous créons un tableau associatif du type <code du bug - description du bug>;
  • Ajoutez les codes d'erreur possibles et leur description dans ce dictionnaire ;
  • Directement et sans intermédiaire nous nous adressons au dictionnaire pour obtenir la description de l'erreur par son code
Ce code se présente comme suit :

//+------------------------------------------------------------------+
//|                                                     OrdersID.mq5 |
//|                        Copyright 2017, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
#include <Generic\HashMap.mqh>
input ulong FindTicketOrder = 82479995;

CHashMap<int, string> ErrorDescription;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void AddDescriptionInfo(void)
{
   // Добавим коды системных ошибок
   ErrorDescription.Add(0,    "Операция выполнена успешно");
   ErrorDescription.Add(4001, "Неожиданная внутренняя ошибка");
   ErrorDescription.Add(4002, "Ошибочный параметр при внутреннем вызове функции клиентского терминала");
   ErrorDescription.Add(4003, "Ошибочный параметр при вызове системной функции");
   ErrorDescription.Add(4004, "Недостаточно памяти для выполнения системной функции");
   // Можно добавлять константные значения вместо чисел
   ErrorDescription.Add(ERR_STRUCT_WITHOBJECTS_ORCLASS, "Структура содержит объекты строк и/или динамических массивов и/или структуры с такими объектами и/или классы");
   ErrorDescription.Add(ERR_INVALID_ARRAY, "Массив неподходящего типа, неподходящего размера или испорченный объект динамического массива");   
   ErrorDescription.Add(ERR_ARRAY_RESIZE_ERROR, "Недостаточно памяти для перераспределения массива либо попытка изменения размера статического массива");
   //...
}
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
   AddDescriptionInfo();
   string last_error = "";
   ErrorDescription.TryGetValue(GetLastError(), last_error);
   printf("Последняя ошибка: " + last_error);
}
//+------------------------------------------------------------------+

Une fois les codes d'erreur renseignés, on y accède en une seule ligne, sans utiliser de fonctions différentes. En outre, je vous rappelle que dans certains cas, ce code fonctionnera encore plus vite que plusieurs dizaines de ifs, car l'adressage à l'erreur nécessaire se fait directement, avec une vitesse moyenne de O(1).

 
Vasiliy Sokolov:

Une fois que les codes d'erreur sont remplis, il est possible d'y accéder avec une seule chaîne de caractères, sans utiliser différentes fonctions.

ErrorToString devra être écrit de toute façon. Donc l'argument, en tant que plus, est faible.

En outre, je vous rappelle que dans certains cas, ce code fonctionnera encore plus rapidement que plusieurs dizaines de ifs, car l'adressage de l'erreur nécessaire se fait directement, avec une vitesse moyenne de O(1).

Mais c'est un avantage évident.

 

La solution proposée pour le dictionnaire présente plusieurs avantages, dont le plus important n'est pas entièrement évident au premier abord. Quand on écrit du code comme ça :

string ErrorDescription(int error_code)
   if(error_code == 40001)
      return ("Неожиданная внутренняя ошибка");
   //...
}

Nous sommes câblés dans le code du conseiller expert lui-même. Lorsque nous remplissons le dictionnaire, nous le faisons de manière dynamique, c'est-à-dire au moment de l'exécution du programme. L'approche dynamique nous donne plus de flexibilité. Par exemple, les codes d'erreur peuvent être contenus dans un fichier spécial, par exemple ErrorsCode.txt :

4001;Операция выполнена успешно
4002;Неожиданная внутренняя ошибка
4003;Ошибочный параметр при вызове системной функции
...

Au moment du lancement, le programme peut lire ce fichier et remplir le dictionnaire avec les codes requis, puis renvoyer la variante requise de la chaîne à l'utilisateur. Il peut y avoir plusieurs fichiers de ce type : un fichier par langue. Il est ainsi possible d'effectuer une localisation, où les codes d'erreur sont affichés dans la langue de l'utilisateur, en fonction de la langue de ce dernier. En outre, l'utilisateur peut traduire lui-même ces codes d'erreur dans sa propre langue une fois, et le programme lui-même "apprend" à émettre le message souhaité dans sa langue. C'est ainsi que la plupart des programmes sont localisés, lorsque la traduction d'un menu est contenue dans un fichier texte et que le programme le charge, en fonction des paramètres. C'est-à-dire que sans aucune recompilation du programme et sans changer son algorithme, nous pouvons influencer de manière significative la présentation de ses résultats.

Raison: