Vous manquez des opportunités de trading :
- Applications de trading gratuites
- Plus de 8 000 signaux à copier
- Actualités économiques pour explorer les marchés financiers
Inscription
Se connecter
Vous acceptez la politique du site Web et les conditions d'utilisation
Si vous n'avez pas de compte, veuillez vous inscrire
Je ne suis pas très doué pour les explications. Laissez-moi essayer à nouveau. La tâche consiste à constituer un portefeuille de devises, chaque devise ayant ses propres paramètres. Dans un portefeuille optimisé, une devise peut ne pas participer. J'ai calculé six devises en 21 étapes d'optimisation pour chaque devise, et la somme totale se chiffre en milliards.
Maintenant la question. Si nous interdisons à une monnaie de s'échanger avec un drapeau, il n'y a aucun sens à optimiser ses paramètres, de toute façon ils n'affecteront en rien le résultat, mais l'optimiseur continuera à essayer d'adapter des paramètres qui n'affectent pas le résultat. Comme moi, je sais que vous ne pouvez pas, mais l'espoir est toujours présent.
Oui, d'accord. Il y aura des passes inutiles.
Si TC vous le permet, vous devriez optimiser chaque paire séparément.
L'optimisation générale consiste à tomber dans le piège de la couverture magique ;))).
Il y a une autre solution, dans l'autre sens que celle que je propose, mais qui réduit les courses inutiles.
Par exemple, votre énumération du paramètre 100 dans l'intervalle 50-150.
Cela réduit le nombre de choix d'une dimension.
Je ne suis pas très doué pour les explications. Laissez-moi essayer à nouveau. La tâche consiste à constituer un portefeuille de devises, chaque devise ayant ses propres paramètres. Dans un portefeuille optimisé, une devise peut ne pas participer. J'ai calculé six devises en 21 étapes d'optimisation pour chaque devise, et la somme totale se chiffre en milliards.
Maintenant la question. Si nous interdisons à une monnaie de s'échanger avec un drapeau, il n'y a aucun sens à optimiser ses paramètres, de toute façon ils n'affecteront en rien le résultat, mais l'optimiseur continuera à essayer d'adapter des paramètres qui n'affectent pas le résultat. Comme moi, je sais que vous ne pouvez pas, mais l'espoir est toujours là.
Si j'ai quelque chose comme Init() et Trade() pour chaque paire + les paramètres ont déjà été choisis, la seule chose qui reste est de déterminer les actions, alors la tâche peut être résolue. Bien que, malheureusement, en termes généraux, pour n'importe quel nombre de systèmes - ne peut être résolu.
Nous devons donc préciser les "fractions du système" par étapes. Pour 6 systèmes, le nombre de passages est calculé par f-eye :
Il est possible de créer un script pour cela :
En outre, la tâche optimisée a deux paramètres - Mult (non optimisé) et part - de 1 à PartCount6(Mult) par pas de 1 :
Gardez à l'esprit que plus le pas est petit, plus le nombre d'étapes de la boucle que vous devez franchir est élevé. Par exemple, si le script qui calcule le nombre de passages ne retourne pas plus de 5 min, il serait préférable de réduire l'étape. Si vous ne voulez pas réduire l'étape, par exemple, divisez les monnaies en deux, prooptimisez chaque groupe, puis revenez ensemble "en tant que groupes". (ou mieux encore, utiliser les corrélations entre systèmes et optimiser par paires - les cycles ne sont alors pas si mauvais, mais c'est une autre histoire).
Pour un autre nombre de systèmes (même moins, même plus), tout est identique.
J'ai presque oublié - après l'optimisation, vous aurez besoin de connaître les fractions - alors exécutez la passe unique que vous préférez et écrivez-la dans OnDeinit :
J'ai découvert et testé ce bug il y a un an et je l'ai même mentionné sur le forum.
Il s'avère qu'il est toujours en vie.
En résumé, lorsqu'une fonction virtuelle est appelée dans le constructeur, la fonction ancestrale est appelée au lieu de la fonction native.
Imprimés :
Si c'est un bogue, veuillez le corriger.
S'il s'agit d'une fonctionnalité, décrivez-la en détail dans l'aide et expliquez quels en sont les avantages.
Si c'est un mal nécessaire, veuillez le mentionner dans la case spéciale de l'aide.
Sinon, vous ne deviendrez pas fou en cherchant un bug dans votre programme.
Le constructeur de l'ancêtre ne sait rien de ses descendants et de leurs fonctions virtuelles.
Comment un objet est-il construit ?
1. Tout d'abord, le constructeur du "moteur principal" est appelé. Il expose sa table de fonctions virtuelles. L'ancêtre ne sait rien des descendants qui suivent la hiérarchie d'héritage, et les tables de fonctions virtuelles des descendants n'existent pas encore.
2. Le constructeur du descendant suivant dans la hiérarchie est appelé. Ce descendant expose sa table de fonctions virtuelles. Les fonctions (y compris les fonctions virtuelles) du descendant sont disponibles dans le descendant. Mais, là encore, ce descendant ne sait rien des descendants qui le suivent dans une hiérarchie (comme au point 1).
3. Le point 2 est répété, jusqu'à ce que la hiérarchie soit remplie.
Résumé. N'utilisez pas de fonctions virtuelles dans les constructeurs. Et ne l'utilisez pas non plus dans les destructeurs.
Si c'est un mal inévitable, veuillez le mentionner dans l'aide, dans une case spéciale.
Le constructeur de l'ancêtre ne sait rien de ses descendants et de leurs fonctions virtuelles.
Comment un objet est-il construit ?
1. Tout d'abord, le constructeur du "moteur principal" est appelé. Il expose sa table de fonctions virtuelles. L'ancêtre ne sait rien des descendants qui suivent la hiérarchie d'héritage, et les tables de fonctions virtuelles des descendants n'existent pas encore.
2. Le constructeur du descendant suivant dans la hiérarchie est appelé. Ce descendant expose sa table de fonctions virtuelles. Les fonctions (y compris les fonctions virtuelles) du descendant sont disponibles dans le descendant. Mais, là encore, ce descendant ne sait rien des descendants qui le suivent dans une hiérarchie (comme au point 1).
3. Répétez le point 2, jusqu'à ce que la hiérarchie soit remplie.
Résumé. N'utilisez pas de fonctions virtuelles dans les constructeurs. Ni dans les destructeurs.
Ok, mais mets-le quand même en évidence, si c'est comme ça.
En général, il ne s'agit pas de la hiérarchie de l'assemblage (c'est comme ça que je l'imaginais), mais à quel endroit du constructeur la VMT est ajoutée. Si elle est ajoutée au début (avant le code écrit par l'utilisateur) alors ce problème ne semble pas exister, et le code suivant peut déjà appeler les fonctions virtuelles. Est-ce impossible, indésirable ou... ?
C'est une pratique courante de ne pas appeler les fonctions virtuelles avant la fin du constructeur et après le début du destructeur.
Eh bien, je n'en savais rien, même en ayant une certaine expérience d'autres langages orientés objet. Peut-être parce qu'il n'est pas souvent nécessaire de faire des appels virtuels à l'intérieur d'un constructeur.
OK. Mais mettez-le quand même en évidence dans le service d'assistance, si c'est comme ça que ça doit être.
Dans la documentation, ce fait sera reflété à plusieurs endroits
OK, super.
Slava, puis-je demander (pour le développement général) pourquoi la table des méthodes virtuelles ne peut pas être initialisée au début du constructeur (après l'initialisation de l'ancêtre) ?
--
Dans certains cas, le code avec des appels virtuels dans le constructeur peut être très pratique. Un exemple récent : je voulais charger des objets à partir d'un fichier directement dans le constructeur. Le plan était de vérifier les types pendant le chargement en les comparant avec les ID de type retournés par les fonctions virtuelles. Le problème est apparu, en raison de l'impossibilité d'effectuer des appels virtuels depuis le constructeur. A résolu le problème, mais pas aussi élégamment que prévu.