Erreurs, bugs, questions - page 741

 
ivandurak:

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.

input bool trpar2=true; // вЫключен флажок
input int grusdchf=100; // включен флажок перебора 49-150
input int grusdjpy=100; // включен флажок перебора 50-150

if (grusdchf==49)  // если 49 то запрет торговли
  {
   x_trpar2=false;
  }
 else              // иначе берет установленное значение флага и параметров
  {
   x_trpar2=trpar2;
  }

// далее по коду для запрета используем x_trpar2
 
ivandurak:

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 :

int PartCount6(double _mult) {
   int __= (int)(1.0 / _mult) + 1;
   int x, y, z, t, t1, t2, count = 0;
   for (t = 0; t < __; ++t) for (x = 0; x < __; ++x) 
      for (y = 0; y < __; ++y) for (z = 0; z < __; ++z) 
         for (t1 = 0; t1 < __; ++t1) for (t2 = 0; t2 < __; ++t2) 
            if (x + y + z + t + t1 + t2 == __- 1) ++count;
   return(count);     
}

Il est possible de créer un script pour cela :

input double Mult = 0.04;

void OnStart() {
   Alert(PartCount6(Mult));
}

En outre, la tâche optimisée a deux paramètres - Mult (non optimisé) et part - de 1 à PartCount6(Mult) par pas de 1 :

input double Mult  = 0.04;
input int    part = 3276;

CZ1 gbp;
CZ2 jpy;
CZ3 eursek, eur;
CZ4 audcad, sek;

int x, y, z, t, t1, t2; 

int OnInit() {
   int __= (int)(1.0 / Mult) + 1;
   int count = 0;
   for (x = 0; x < __; ++x) {
      for (y = 0; y < __; ++y) {
         for (z = 0; z < __; ++z) {
            for (t = 0; t < __; ++t) {
               for (t1 = 0; t < __; ++t1) {
                  for (t2 = 0; t2 <__; ++t2) { 
                     if (x + y + z + t + t1 + t2 == __- 1) {
                        ++count;
                        if (count == part) break; // Вот где goto был бы полезен, или break n
                     }
                  }
                  if (count == part) break;
               }
               if (count == part) break; 
            }
            if (count == part) break;
         }
         if (count == part) break;
      }
      if (count == part) break;
   }
   if (x) gbp.Init(..);//его доля - x * Mult, т. е., нужно в Init долю передавать как параметр
   if (y) jpy.Init(..); 
   if (z) eur.Init(..);
   if (t) eursek.Init(..);
   if (t1) audcad.Init(..);
   if (t2) sek.Init(...);
}

void OnTick() {
   if (x) gbp.Trade();
   if (y) jpy.Trade();
   if (z) eur.Trade();
   if (t) eursek.Trade();
   if (t1) audcad.Trade();
   if (t2) sek.Init(Trade);
}

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 :

void OnDeinit(const int reason) {
  Print("x:", x * Mult, "; y:", y * Mult, "; z:", z * Mult, "; t:", t * Mult, "; t1:", t1 * Mult, "; t2:", t2 * Mult);
}
 

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.

class COracleTemplate
  {
private:
public:
   string            ClassName;
                     COracleTemplate(){Init();};
                    ~COracleTemplate(){DeInit();};
   virtual void      Init(){ClassName=this.Name();Print("loadSettings from ",ClassName);};
   virtual void      DeInit(){Print("saveSettings to ",ClassName);};
   virtual string    Name(){return("Prpototype");};
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CCO2:public COracleTemplate
  {
   virtual string    Name(){return("CO2");};
  };
class CH2O:public COracleTemplate
  {
   virtual string    Name(){return("H2O");};
  };
COracleTemplate* CO2,*H2O;
void OnStart()
  {
   CO2=new CCO2;
   CO2.Init();
   Print(CO2.Name()," ClassName=",CO2.ClassName);
   delete CO2;
   
   H2O=new CH2O;
//   H2O.Init();
   Print(H2O.Name()," ClassName=",H2O.ClassName);
   delete H2O;
  }

Imprimés :

2012.05.18 14:13:48     VirtualTest (EURUSD,M15)        saveSettings to Prpototype
2012.05.18 14:13:48     VirtualTest (EURUSD,M15)        H2O ClassName=Prpototype
2012.05.18 14:13:48     VirtualTest (EURUSD,M15)        loadSettings from Prpototype
2012.05.18 14:13:48     VirtualTest (EURUSD,M15)        saveSettings to CO2
2012.05.18 14:13:48     VirtualTest (EURUSD,M15)        CO2 ClassName=CO2
2012.05.18 14:13:48     VirtualTest (EURUSD,M15)        loadSettings from CO2
2012.05.18 14:13:48     VirtualTest (EURUSD,M15)        loadSettings from Prpototype

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.

Dossiers :
 

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.

 
MetaDriver:

Si c'est un mal inévitable, veuillez le mentionner dans l'aide, dans une case spéciale.

C'est une pratique courante de ne pas appeler les fonctions virtuelles avant le constructeur et après le début du destructeur.
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
  • www.mql5.com
Основы языка / Объектно-ориентированное программирование / Виртуальные функции - Документация по MQL5
 
stringo:

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... ?

LeXpert:
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.

 
MetaDriver:

OK. Mais mettez-le quand même en évidence dans le service d'assistance, si c'est comme ça que ça doit être.


La documentation reflétera ce fait à plusieurs endroits
 
stringo:
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.

Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
  • www.mql5.com
Основы языка / Объектно-ориентированное программирование / Виртуальные функции - Документация по MQL5
 
MetaDriver:
Alors faites une usine. Le problème sera résolu.