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

 
Renat Fatkhullin:

Vous ne pouvez pas comparer HistorySelect(met la plage d'accès dans le testeur) et HistoryDealSelect(ticket), qui recherche réellement un ticket spécifique et le met en cache.

Parce que nous avons compris cela, la variante Clear a été créée immédiatement. Pour pouvoir comparer Clear et Full en même temps.

 
fxsaber:
De cette façon, l'historique (surtout chez le testeur) est seulement complété, les anciens enregistrements ne sont pas modifiés. Je veux dire la variante claire.


En réalité, il semble que même lorsqu'un ordre est partiellement exécuté et génère plusieurs transactions, il n'est pas enregistré dans l'historique tant qu'il n'est pas complètement exécuté ou annulé. C'est-à-dire que la règle de l'histoire figée est préservée.

Si nous écrivions des logiciels sans contrôles, tout se serait écroulé depuis longtemps.

Les logiciels financiers ne vous permettent pas d'écrire en mode "coupe-file". Vous coupez à un endroit, puis à un autre, et alors les développeurs croiront au droit de sauter les contrôles difficiles et l'échec est inévitable.

Dans le testeur, vous pouvez toujours réduire la vérification, mais dans l'EA réel, de nombreux processus asynchrones travaillent sur les changements constants de l'ensemble de l'environnement du marché simultanément avec le travail de votre EA. Vous ne pouvez même pas penser que quelque chose soit sauvegardé entre les appels MQL5.

 
Renat Fatkhullin:

Si nous écrivions des logiciels sans contrôles, tout se serait écroulé depuis longtemps.

Les logiciels financiers ne vous permettent pas d'écrire en mode "coupe-file". Vous coupez à un endroit, puis à un autre, et alors les développeurs croiront au droit de sauter les contrôles difficiles et l'échec est inévitable.

Vous pouvez toujours relâcher les contrôles dans le testeur, mais dans le monde réel, il existe de nombreux processus asynchrones qui modifient constamment l'ensemble de l'environnement du marché, parallèlement à votre conseiller expert. C'est effrayant de penser que quelque chose sera sauvegardé entre les appels MQL5.

Merci pour cette précision ! Le testeur va, je l'espère, le resserrer un peu.

 
fxsaber:

Grâce à cette compréhension, la variante Clear a été créée immédiatement. Ainsi, vous pouvez comparer Clear et Full en même temps.

Vous comprenez mal ce que vous testez. Il ne s'agit en aucun cas d'une variante claire et il n'y a aucun rapport avec la référence à HistorySelect mentionnée à l'origine.

Votre variante complète signifie essentiellement un double appel (recherche de billets), dont le premier sélectionne le métier dans le cache et le second accède au résultat mis en cache. Dans une tâche particulière, où l'on sait qu'il existe un métier, le premier appel de sélection est redondant. Les méthodes Get mettent implicitement en cache l'enregistrement concerné.



Pour information, nous devons exposer en interne les codes détaillés de la dernière erreur (sous l'appel GetLastError()), afin que les développeurs puissent connaître les raisons sous-jacentes de l'échec. En général, il y a plusieurs vérifications de ce type par appel en profondeur dans la plate-forme.
 
Renat Fatkhullin:

Vous comprenez mal ce que vous testez. Il ne s'agit en aucun cas d'une option claire et il n'y a aucun lien avec la référence à HistorySelect mentionnée à l'origine.

Il semble que vous ne l'ayez pas remarqué.

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

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

fxsaber, 2017.12.08 22:46

  BENCH(HistorySelect(0, INT_MAX));
  BENCH(Print(SumProfit(Deals, GetDealProfitClear))); // Реализация с предварительно загруженной историей
Ou peut-être que nous parlons de choses différentes.
 
fxsaber:

Vous ne semblez pas l'avoir remarqué.

Ou peut-être que nous parlons de choses différentes.

Je l'ai remarqué.

Quel historique préchargé ? J'ai fait remarquer que HistorySelect dans le testeur est faux et ne fait pas un transfert réel vers le cache de tout l'historique spécifié dans la requête, mais marque seulement les positions de & à dans la base de données existante des transactions. Par conséquent, le coût est nul.

Dans GetDealProfitClear, vous faites exactement une demande au même endroit en utilisant HistoryDealGetDouble(Deal, DEAL_PROFIT), comme dans votre méthode incomprise GetDealProfitFull, qui utilise deux méthodes qui sont exactement les mêmes dans leur essence physique

return(HistoryDealSelect(Deal) ? HistoryDealGetDouble(Deal, DEAL_PROFIT) : 0)

En d'autres termes, l'accès à l'historique dans le testeur est très optimisé et se concentre vraiment sur le fait que personne ne peut modifier l'historique des transactions à l'exception de votre conseiller expert (et les contrôles sont toujours là).

Dans le terminal réel, tout est différent et HistorySelect est coûteux.

 
Renat Fatkhullin:

Je vois ce que vous voulez dire. Merci pour les détails ! Je me demande quel sera le résultat.

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, description, questions, particularités d'utilisation et suggestions

Renat Fatkhullin, 2017.12.08 23:19

J'ai regardé notre code - il est possible d'optimiser les appels à la base commerciale. Nous essaierons de l'implémenter d'ici la sortie de la semaine prochaine.

Et le sujet générique est très utile, cependant ! Je le suivrai avec intérêt.
 

J'ai vérifié l'implémentation deCHashMap
. J'ai bien aimé, honnêtement.

//+------------------------------------------------------------------+
//| Class CHashMap<TKey, TValue>.                                    |
//| Usage: Represents a collection of keys and values.               |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
class CHashMap: public IMap<TKey,TValue>
  {
protected:
   int               m_buckets[];                        
   Entry<TKey,TValue>m_entries[];
   int               m_count;
   int               m_free_list;
   int               m_free_count;
   IEqualityComparer<TKey>*m_comparer;
   bool              m_delete_comparer;

public:
                     CHashMap(void);
                     CHashMap(const int capacity);
                     CHashMap(IEqualityComparer<TKey>*comparer);
                     CHashMap(const int capacity,IEqualityComparer<TKey>*comparer);
                     CHashMap(IMap<TKey,TValue>*map);
                     CHashMap(IMap<TKey,TValue>*map,IEqualityComparer<TKey>*comparer);
                    ~CHashMap(void);
   //--- methods of filling data 
   bool              Add(CKeyValuePair<TKey,TValue>*pair);
   bool              Add(TKey key,TValue value);
   //--- methods of access to protected data
   int               Count(void)                                       { return(m_count-m_free_count); }
   IEqualityComparer<TKey>*Comparer(void)                        const { return(m_comparer);           }
   bool              Contains(CKeyValuePair<TKey,TValue>*item);
   bool              Contains(TKey key,TValue value);
   bool              ContainsKey(TKey key);
   bool              ContainsValue(TValue value);
   //--- methods of copy data from collection   
   int               CopyTo(CKeyValuePair<TKey,TValue>*&dst_array[],const int dst_start=0);
   int               CopyTo(TKey &dst_keys[],TValue &dst_values[],const int dst_start=0);
   //--- methods of cleaning and deleting
   void              Clear(void);
   bool              Remove(CKeyValuePair<TKey,TValue>*item);
   bool              Remove(TKey key);
   //--- method of access to the data
   bool              TryGetValue(TKey key,TValue &value);
   bool              TrySetValue(TKey key,TValue value);

private:
   void              Initialize(const int capacity);
   void              Resize(int new_size,bool new_hash_codes);
   int               FindEntry(TKey key);
   bool              Insert(TKey key,TValue value,const bool add);
  };


Il y a quelques suggestions d'améliorations possibles :

1) À mon humble avis, l'implémentation contient un choix de capacité pas tout à fait correct - à la fois la taille initiale 3 et les suivantes lors de la reconstruction de la table de hachage.
Oui, il est exact qu'un nombre premier doit être choisi pour l'uniformité de la distribution.
Cependant, l'implémentation de CPrimeGenerator ne répond pas aux attentes et contient des omissions de nombres premiers.
L'objectif d'un tel "générateur" est clair : fournir un facteur d'incrémentation de l'ordre de 1,2 avec la génération automatique de nombres premiers.
Toutefois, ce coefficient n'est-il pas trop faible ? En C++ pour les vecteurs, le coefficient est généralement de 1,5 à 2,0, selon la bibliothèque (car il affecte fortement la complexité moyenne de l'opération).
La solution pourrait être un coefficient constant suivi d'un arrondi au nombre premier via une recherche binaire d'une liste de nombres premiers.
Et une taille initiale de 3 est trop petite, nous ne vivons pas au siècle dernier.

2) Actuellement, la reconstruction de la table de hachage (Resize) est exécutée uniquement lorsque la capacité de 100 % est remplie (toutes les m_entries[] sont remplies).
De ce fait, il peut y avoir beaucoup de collisions pour des clés qui ne sont pas distribuées de manière très uniforme.
En option, envisagez d'introduire un facteur de remplissage qui réduit de 100% la limite requise pour effectuer une reconstruction de la table de hachage.

 
fxsaber:

Et la version classique de la question "combien cela rapporte-t-il dans votre cas ?

ulong GetDealOrder( const ulong Deal )
{
  return(HistoryDealSelect(Deal) ? HistoryDealGetInteger(Deal, DEAL_ORDER) : 0);
}
2017.12.08 17:56:05.184 OrdersID (SBRF Splice,M1)       Время выполнения запроса: 9 микросекунд

C'est le temps d'exécution de printf.

Vous avez en quelque sorte compris mon exemple de façon étrange. Je n'ai pas l'intention de comparer quoi que ce soit avec la fonctionnalité standard de MetaTrader. Il s'agit uniquement de savoir comment organiser des algorithmes efficaces d'associations et d'échantillonnage de n'importe quoi avec n'importe quoi à votre niveau d'utilisateur. L'exemple de l'association d'un numéro de transaction avec un numéro de commande ne doit être considéré que comme un exemple à faible valeur pratique, car il existe un systèmeHistoryDealGetInteger(Deal, DEAL_ORDER).

 
fxsaber:

Eh bien, voici une comparaison des deux paramètres mis en évidence. Il s'avère que l'accès au HashMap est 4 fois plus rapide que celui des développeurs. Mais les développeurs l'ont déjà, y compris l'histoire...

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