Errori, bug, domande - pagina 741

 
ivandurak:

Non sono un grande spiegatore. Lasciatemi provare di nuovo. Il compito è quello di formare un portafoglio di valute, ogni valuta con i propri parametri. In un portafoglio ottimizzato una valuta può non partecipare. Ho calcolato sei valute in 21 passi di ottimizzazione per ogni valuta, e la somma totale è in miliardi.

Ora la domanda. Se vietiamo a una valuta di commerciare con una bandiera, allora non ha senso ottimizzare i suoi parametri, in ogni caso non influiranno in alcun modo sul risultato, ma l'ottimizzatore continuerà a cercare di adattare i parametri che non influiscono sul risultato. Come me so che non si può, ma la speranza è ancora fiorente.

Sì, va bene, ci saranno passaggi non necessari.

Se TC te lo permette, dovresti ottimizzare ogni coppia separatamente.

L'ottimizzazione generale implica imho cadere nella trappola dell'hedging magico ))).

C'è un'altra soluzione, nell'altra direzione di quella proposta da me, ma riduce le corse inutili.

Per esempio, la vostra enumerazione del parametro 100 nell'intervallo 50-150.

Questo riduce il numero di scelte di una dimensione.

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:

Non sono un grande spiegatore. Lasciatemi provare di nuovo. Il compito è quello di formare un portafoglio di valute, ogni valuta con i propri parametri. In un portafoglio ottimizzato una valuta può non partecipare. Ho calcolato sei valute in 21 passi di ottimizzazione per ogni valuta, e la somma totale è in miliardi.

Ora la domanda. Se proibiamo a una valuta di commerciare con una bandiera, allora non ha senso ottimizzare i suoi parametri, in ogni caso non influenzeranno il risultato in alcun modo, ma l'ottimizzatore continuerà a cercare di adattare i parametri che non influiscono sul risultato. Come me so che non si può, ma la speranza è ancora fumante.

Se ho qualcosa come Init() e Trade() per ogni coppia + i parametri sono già stati scelti, l'unica cosa rimasta è determinare le azioni, poi il compito può essere risolto. Anche se, purtroppo, in termini generali, per qualsiasi numero di sistemi - non può essere risolto.

Quindi, abbiamo bisogno di specificare passo "frazioni del sistema". Per 6 sistemi, il numero di passaggi è calcolato da 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);     
}

È possibile fare uno script per questo:

input double Mult = 0.04;

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

Inoltre, il compito ottimizzato ha due parametri - Mult (non ottimizzato) e part - da 1 a PartCount6(Mult) in passi di 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);
}

Basta tenere a mente che più piccolo è il passo, più passi nel ciclo è necessario attraversare. Per esempio, se lo script che calcola il numero di passaggi non restituisce più di 5 minuti, sarebbe meglio ridurre il passo. Se non volete ridurre il passo, per esempio, dividete le valute a metà, proottimizzate ogni gruppo, e poi tornate insieme "come gruppi". (o meglio ancora usare le correlazioni dei sistemi e ottimizzare in coppia - allora i cicli non sono così male, ma questa è un'altra storia).

Per un altro numero di sistemi (anche meno, anche più) - tutto è uguale.

 

Quasi dimenticavo - dopo l'ottimizzazione avrete bisogno di conoscere le frazioni - quindi eseguite il singolo passaggio che vi piace di più e scrivetelo in 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);
}
 

Ho scoperto e testato questo bug un anno fa e l'ho anche menzionato sul forum.

A quanto pare, è ancora vivo.

In conclusione: quando una funzione virtuale viene chiamata nel costruttore, viene chiamata la funzione antenata invece della funzione nativa.

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;
  }

Stampe:

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

Se questo è un bug, per favore correggetelo.

Se si tratta di una caratteristica, copritela in dettaglio nell'aiuto e spiegate quali sono i vantaggi.

Se è un male necessario, menzionatelo nell'apposita casella dell'aiuto.

Altrimenti, non impazzirete a cercare un bug nel vostro programma.

File:
 

Il costruttore antenato non sa nulla dei suoi discendenti e delle loro funzioni virtuali.

Come si costruisce un oggetto?

1. In primo luogo, viene chiamato il costruttore del "prime mover". Espone la sua tabella delle funzioni virtuali. L'antenato non sa nulla dei discendenti che seguono la gerarchia di eredità, e le tabelle delle funzioni virtuali dei discendenti non esistono ancora.

2. Viene chiamato il costruttore del prossimo discendente nella gerarchia. Questo discendente espone la sua tabella delle funzioni virtuali. Le funzioni (comprese le funzioni virtuali) del discendente sono disponibili nel discendente. Ma, di nuovo, questo discendente non sa nulla dei discendenti che lo seguono in una gerarchia (come nel punto 1).

3. Si ripete il punto 2, fino a quando la gerarchia è soddisfatta.

Riassunto. Non usare funzioni virtuali nei costruttori. E non usatelo nemmeno nei distruttori.

 
MetaDriver:

Se è un male inevitabile, menzionatelo nell'aiuto, in una casella speciale.

È una pratica comune non chiamare funzioni virtuali prima del costruttore e dopo l'inizio del distruttore.
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
  • www.mql5.com
Основы языка / Объектно-ориентированное программирование / Виртуальные функции - Документация по MQL5
 
stringo:

Il costruttore antenato non sa nulla dei suoi discendenti e delle loro funzioni virtuali.

Come si costruisce un oggetto?

1. In primo luogo, viene chiamato il costruttore del "prime mover". Espone la sua tabella delle funzioni virtuali. L'antenato non sa nulla dei discendenti che seguono la gerarchia di eredità, e le tabelle delle funzioni virtuali dei discendenti non esistono ancora.

2. Viene chiamato il costruttore del prossimo discendente nella gerarchia. Questo discendente espone la propria tabella di funzioni virtuali. Le funzioni (comprese le funzioni virtuali) del discendente sono disponibili nel discendente. Ma, di nuovo, questo discendente non sa nulla dei discendenti che lo seguono in una gerarchia (come nel punto 1).

3. Ripetere il punto 2, fino a quando la gerarchia è soddisfatta.

Riassunto. Non usare funzioni virtuali nei costruttori. Né nei distruttori.

Ok, ma mettetelo comunque in un posto ben visibile, se deve essere così.

In generale, non si tratta della gerarchia dell'assemblaggio (che è come me la immaginavo), ma in quale posto del costruttore viene aggiunta la VMT. Se viene aggiunta all'inizio (prima del codice scritto dall'utente) allora questo problema non sembra esistere, e il codice successivo può già chiamare le funzioni virtuali. È impossibile, indesiderabile o... ?

TheXpert:
È una pratica comune non chiamare funzioni virtuali prima della fine del costruttore e dopo l'inizio del distruttore.

Beh, non ne sapevo nulla, anche avendo qualche esperienza con altri linguaggi orientati agli oggetti. Forse perché non è spesso necessario fare chiamate virtuali all'interno di un costruttore.

 
MetaDriver:

Ok, ma mettetelo comunque in un posto ben visibile nell'helpdesk, se è così che deve essere.


La documentazione rifletterà questo fatto in diversi punti
 
stringo:
Nella documentazione questo fatto si rifletterà in diversi punti

Ok, perfetto.

Slava, posso chiedere (per lo sviluppo generale) perché la tabella dei metodi virtuali non può essere inizializzata all'inizio del costruttore (dopo l'inizializzazione dell'antenato)?

--

In alcuni casi il codice con chiamate virtuali nel costruttore potrebbe essere abbastanza comodo. Un esempio recente: volevo caricare oggetti da file direttamente nel costruttore. Il piano era di controllare i tipi durante il caricamento confrontandoli con gli ID dei tipi restituiti dalle funzioni virtuali. È venuto fuori il rompiscatole, a causa dell'impossibilità di chiamate virtuali dal costruttore. Risolto il problema, ma non in modo elegante come previsto.

Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
  • www.mql5.com
Основы языка / Объектно-ориентированное программирование / Виртуальные функции - Документация по MQL5
 
MetaDriver:
Quindi fate una fabbrica. Il problema sarà risolto.