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

 

Voici le code ainsi que le champ de saisie. (Cela peut être utile à quelqu'un. Cela peut être raffiné).

//+------------------------------------------------------------------+
//|                                                   Dictionary.mq5 |
//|                                                      Peter Konow |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Peter Konow"
#property link      ""
#property version   "1.00"
#property strict
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
#define  Max_possible_collisions    100
#define  Max_letters_in_word        100
#define  All_letters_in_alphabet    255 
//------------------------------------
string Dictionary[Max_possible_collisions][All_letters_in_alphabet][Max_letters_in_word];
//-------------------------------------------------------------------
int OnInit()
  {
//---
   Create_text_box();
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   ObjectDelete(0,"Text_box");
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
    if(id == CHARTEVENT_OBJECT_ENDEDIT)
      { 
       //-----------------------
       string Text;     
       //---------------------
       ObjectGetString(0,"Text_box",OBJPROP_TEXT,0,Text);
       //-------------------------------------
       Add(Text);
      } 
  }
//+------------------------------------------------------------------+

void Add(string word)
{
 uchar First_letter = (uchar)StringGetCharacter(word,0) - 97;
 //-----------------------
 int All_letters_in_word = StringLen(word);
 //-----------------------
 for(int a1 = 0; a1 < Max_possible_collisions; a1++)
   {
     string word_inside = Dictionary[a1][First_letter][All_letters_in_word];
     //-----------------------   
    if(word_inside == NULL)
      {
       Dictionary[a1][First_letter][All_letters_in_word] = word;
       Print("Your word has been added to our dictionary!");
       break;
      }
    if(word_inside == word)
      {
       Print("This word already exists in our dictionary");
       break;
      } 
   }   
 //------------------------   
}
//--------------------------------------------------------------------+


//--------------------------------------------------------------------
void Create_text_box()
{
  ObjectCreate(0,"Text_box",OBJ_EDIT,0,0,0);
  ObjectSetInteger(0,"Text_box",OBJPROP_XDISTANCE,500);
  ObjectSetInteger(0,"Text_box",OBJPROP_YDISTANCE,250);
  ObjectSetInteger(0,"Text_box",OBJPROP_XSIZE,400);
  ObjectSetInteger(0,"Text_box",OBJPROP_YSIZE,30);
  ObjectSetString(0,"Text_box",OBJPROP_TEXT,"Please enter your word here...");
  ObjectSetString(0,"Text_box",OBJPROP_FONT,"TimesNewRoman");
  ObjectSetInteger(0,"Text_box",OBJPROP_STATE,1);
  //----------------------------------------------
  ObjectSetInteger(0,"Text_box",OBJPROP_FONTSIZE,12);
  ObjectSetInteger(0,"Text_box",OBJPROP_BGCOLOR,clrWhite);
  ObjectSetInteger(0,"Text_box",OBJPROP_COLOR,clrBlack);
  ObjectSetInteger(0,"Text_box",OBJPROP_BORDER_COLOR,clrBlack);
  ObjectSetInteger(0,"Text_box",OBJPROP_ALIGN,ALIGN_CENTER);
  //----------------------------------------------
  ObjectSetInteger(0,"Text_box",OBJPROP_CORNER,CORNER_LEFT_UPPER);
  ObjectSetInteger(0,"Text_box",OBJPROP_ANCHOR,ANCHOR_LEFT_UPPER);  
  //---------------------------------------------- 
}
//----------------------------------------------------------------------- 

Seulement, pour une raison quelconque, il fonctionne pleinement sur le quatrième. Sur le cinquième, le champ n'apparaît pas. J'ai cherché la raison et je ne l'ai pas trouvée.

 
fxsaber:

C'est-à-dire qu'il faut trouver le bon équilibre entre la taille du dictionnaire (RAM) et la complexité de calcul de la fonction de hachage (CPU) pour chaque tâche.


Relativement oui.
Lorsque le nombre d'éléments est petit, la taille optimale du dictionnaire est le nombre d'éléments au carré (d'après mes souvenirs du cours de 3 ans, mais il est toujours préférable de revérifier).
Lorsqu'un grand nombre d'éléments rend impossible le choix de la taille optimale, ils prennent une taille du dictionnaire plusieurs fois supérieure au nombre d'éléments attendus et optimisent la gestion des collisions, par exemple en utilisant des tables de hachage internes pour chacune des collisions.

On essaie de choisir une table de hachage de manière à ce que la recherche soit aussi rapide que possible, tout en assurant une distribution uniforme des résultats obtenus sur la taille de la liste de mots.
L'utilisation de nombres premiers dans les hachages est liée à l'uniformité de la distribution.

 
Balise Konow:
Nous avons dû augmenter la taille du tableau, car les lettres majuscules ont un code différent et " sortent " du tableau.

Le code du caractère "A" diffère du code du caractère "a" par exactement 32. Par conséquent, tous les autres ont également une différence de 32.

Peut-être que la taille du tableau n'aurait pas dû être augmentée et que le premier caractère aurait dû être remplacé.
 
Alexey Viktorov:

Le code du caractère "A" diffère du code du caractère "a" par exactement 32. Par conséquent, tous les autres ont également une différence de 32.

Peut-être que la taille du tableau n'aurait pas dû être augmentée et que le premier caractère aurait dû être remplacé.

Je suis d'accord. L'algorithme est incomplet à cet égard.

Lataille du tableau est trop grande. Hier, je n'ai pas tout à fait compris les codes de lettres.

 
Tag Konow:

Voici le code ainsi que le champ de saisie. (Cela peut être utile à quelqu'un. Vous pouvez l'affiner).

Mais il fonctionne parfaitement bien sur 4. Le champ n'apparaît pas sur cinq. J'ai cherché la raison et je ne l'ai pas trouvée.

Une autre remarque : dans l'exemple de Vasiliy, il est fait mention d'un tableau

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

Bibliothèque des classes génériques - erreurs, descriptions, questions, particularités d'utilisation, suggestions

Vasiliy Sokolov, 2017.12.07 14:30

Très simple dans le tableau associatif #1

De très nombreux algorithmes présentés dans Generic sont basés sur des tableaux associatifs ou des dictionnaires. C'est également l'un des deux algorithmes les plus utilisés. Je pense être proche de la vérité lorsque j'affirme que 90 % de toutes les tâches de programmation sont couvertes par les tableaux et les dictionnaires. Avant de passer à la pratique, décrivons le travail du dictionnaire de la manière la plus claire et la plus simple possible, en simplifiant volontairement certains détails.

Nous allons montrer le dictionnaire sur un exemple très simple : une liste de mots réguliers. Supposons que nous n'ayons que quelques mots, qui commencent tous par des lettres différentes de l'alphabet :

string words[] = {"apple", "cat", "fog", "dog", "walk", "zero"};

L'alphabet anglais contient 26 caractères. Créons un tableau de chaînes de caractères, de taille 26 éléments :

string dictionary[26];

Maintenant, si nous acceptons de stocker les mots dans des index correspondant à leur première lettre, nous obtiendrons un dictionnaire simple. Nous allons indexer à partir de zéro. Le mot "pomme" sera stocké dans notre dictionnaire à l'index 0, car le caractère "a" est la première lettre de l'alphabet, "chat" - à l'index 1, "chien" - à l'index 3, brouillard - occupera l'index 4, marche - index 24 et zéro - le dernier index 25.

Notez que les index 5 à 23 ne seront pas utilisés. C'est un gaspillage supplémentaire de mémoire, mais nous pouvons accéder instantanément, par exemple, au mot "walk", car nous savons que s'il existe, il est situé à l'index 24.

Écrivons notre premier dictionnaire vide :



Et dans votre exemple.

#define  Max_possible_collisions    100
#define  Max_letters_in_word        100
#define  All_letters_in_alphabet    255 
//------------------------------------
string Dictionary[Max_possible_collisions][All_letters_in_alphabet][Max_letters_in_word];

Combien de mémoire prend un tableau tridimensionnel ? Et si vous devez augmenter la dimensionnalité ?

 
Alexey Viktorov:

Une remarque supplémentaire : dans l'exemple de Vasiliy, il est fait mention d'un tableau


Et dans votre exemple.

Combien de mémoire prend un tableau tridimensionnel ? Et si nous devons augmenter la dimensionnalité ?

Lataille du tableau est trop grande car :

1. J'ai décidé que le nombre maximum de lettres dans un mot peut être de 100. C'est évidemment trop. Nous pourrions le réduire à 30.

2. Le nombre de lettres possibles s'est également avéré excessif. J'ai décidé de prendre de la place pour autant de personnages différents que possible. Peut être réduit.

3. Le nombre de "collisions", c'est-à-dire la correspondance des mots par la première lettre et par le nombre de lettres du mot, est fixé à 100. C'est aussi trop. Vous pourriez descendre jusqu'à 50.


Je ne vois pas la raison de l'augmenter. Vous pouvez simplement ajouter un dictionnaire.

 
Tag Konow:

La taille du tableau est trop grande car :

1. J'ai décidé que le nombre maximum de lettres dans un mot peut être de 100. C'est clairement exagéré. Il pourrait être réduit à 30.

2. Le nombre de lettres possibles s'est également avéré excessif. J'ai décidé de prendre de la place pour autant de personnages différents que possible. Peut être réduit.

3. Le nombre de "collisions", c'est-à-dire la correspondance des mots par la première lettre et par le nombre de lettres du mot, est fixé à 100. C'est aussi trop. Vous pouvez le réduire à 50.


Je ne vois pas de raison d'augmenter la taille. Tu peux juste faire un autre dictionnaire.

La question ne porte pas sur le dictionnaire. Le dictionnaire n'est qu'un exemple de la manière de construire un algorithme. Il peut y avoir bien moins de 100 éléments comme dans votre exemple, mais 1e10 et plus... Quelle est la taille du tableau dans un tel cas ?

Par exemple, rassemblez tous les historiques de tics disponibles dans un tableau. Il peut y avoir plus d'un tick dans une milliseconde, donc le tableau ne peut pas être unidimensionnel... Combien de tics y avait-il en une milliseconde au maximum ? ?? Deux ou cinq ? ?? Quelle devrait être la dimension du tableau dans ce cas ? ??? Combien de mémoire serait gaspillée ?

 
Alexey Viktorov:

Par exemple, rassemblez tous les historiques de tics disponibles dans un tableau.

Après avoir écrit tout cela, il m'est apparu qu'il n'y a pas de tâche pratique pour stocker les ticks de la manière discutée dans le fil de discussion. Ils sont triés par heure et stockés dans un tableau simple.

Il en va de même pour les commandes/offres historiques. Et, à en juger par HistorySelect, ils sont stockés dans un tableau par temps. Et je pense qu'il n'y a rien (dans l'implémentation actuelle) qui permette de rechercher des enregistrements par ticket ou par ID.

Et tout cela parce que dans le cas de l'histoire nommée, il n'est pas raisonnable de faire quelque chose comme ça. Un simple tableau pour s'entraîner est tout à fait suffisant.

C'est pourquoi je m'intéresse à la formulation pratique des tâches dans le domaine du trading.


Lorsque vous essayez d'accélérer HistorySelect, je suis sûr que vous avez résolu le problème avec la mise en cache, et non avec des hachages et des dictionnaires.

 
fxsaber:

Après avoir écrit tout cela, il m'est apparu qu'il n'y a pas de tâche pratique pour stocker les ticks de la manière discutée dans le fil de discussion. Ils sont triés par heure et stockés dans un tableau simple.

Il en va de même pour les commandes/offres historiques. Et, à en juger par HistorySelect, ils sont stockés dans un tableau par temps. Et je pense qu'il n'y a rien (dans l'implémentation actuelle) qui permette de rechercher des enregistrements par ticket ou par ID.

Et tout cela parce que dans le cas de l'histoire nommée, il n'est pas raisonnable de faire quelque chose comme ça. Un simple tableau pour s'entraîner est tout à fait suffisant.

C'est pourquoi je m'intéresse à la formulation pratique des tâches dans le domaine du trading.


Lorsque vous accélérez HistorySelect, vous avez probablement résolu le problème avec la mise en cache, et non avec des dictionnaires de hachage.

Pas d'argument, mais si quelqu'un veut implémenter une tâche de cette façon, alors il faut le signaler sur place...

Quelqu'un pense que ça ne sert à rien, quelqu'un ne peut pas le maîtriser... Et dans les deux cas, il existe des mises en œuvre plus simples. Mais qui sait comment le commerce évoluera "demain"... Il est probablement préférable de l'avoir et de ne pas la réclamer que de la rendre nécessaire en son absence.

 
Alexey Viktorov:

La question ne porte pas sur le dictionnaire. Le dictionnaire n'est qu'un exemple de la construction d'un algorithme. Et il peut y avoir bien plus que 100 éléments comme dans votre exemple, mais 1e10 et plus... Quelle est la taille du tableau dans un tel cas ?

Par exemple, rassemblez tous les historiques de tics disponibles dans un tableau. Il peut y avoir plus d'un tick dans une milliseconde, donc le tableau ne peut pas être unidimensionnel... mais combien de ticks y avait-il en une milliseconde au plus ? ?? Deux ou cinq ? ?? Quelle devrait être la dimension du tableau dans ce cas ? ??? Combien de mémoire sera gaspillée ?

J'étais en train de résoudre la tâche de construire un dictionnaire pratique.

Les ticks ou d'autres éléments ont leurs propres propriétés spécifiques, qui peuvent être indexées avec succès pour un accès rapide à l'emplacement de stockage.

L'essentiel de la tâche d'accès rapide aux données, consiste à identifier plusieurs propriétés classables d'un élément et à les indexer.

Un élément est pris, les propriétés pratiques à partir desquelles vous pouvez obtenir des index sont trouvées, et l'accès à l'emplacement de stockage est obtenu grâce aux index.

Si les index ne sont pas suffisants (par exemple, nous pouvons indexer la première lettre et le nombre de lettres, mais les autres propriétés ne fournissent pas d'index pratique), nous effectuons un bruteforcing direct des éléments à l'intérieur de la zone qui l'entoure.

Le principe est universel, les mises en œuvre peuvent varier.