Errores, fallos, preguntas - página 741

 
ivandurak:

No soy un gran explicador. Déjame intentarlo de nuevo. La tarea consiste en formar una cartera de divisas, cada una con sus propios parámetros. En una cartera optimizada, una moneda puede no participar. He calculado seis monedas en 21 pasos de optimización para cada moneda, y la suma total es de miles de millones.

Ahora la pregunta. Si prohibimos que una moneda opere con una bandera, entonces no tiene sentido optimizar sus parámetros, de todos modos no afectarán al resultado de ninguna manera, pero el optimizador estará tratando de ajustar los parámetros que no afectan al resultado. Al igual que yo, sé que no se puede, pero la esperanza sigue floreciendo.

Sí, está bien. Habrá pases innecesarios.

Si el TC te lo permite, deberías optimizar cada par por separado.

La optimización general implica, en mi opinión, caer en la trampa de la cobertura mágica ))).

Hay otra solución. En la otra dirección de la propuesta por mí, pero reduce las carreras innecesarias.

Por ejemplo, su enumeración del parámetro 100 en el intervalo 50-150.

Esto reduce el número de opciones en una dimensión.

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:

No soy un gran explicador. Déjame intentarlo de nuevo. La tarea consiste en formar una cartera de divisas, cada una con sus propios parámetros. En una cartera optimizada, una moneda puede no participar. He calculado seis monedas en 21 pasos de optimización para cada moneda, y la suma total es de miles de millones.

Ahora la pregunta. Si prohibimos que una moneda opere con una bandera entonces no tiene sentido optimizar sus parámetros, de todas formas no afectarán al resultado de ninguna manera, pero el optimizador estará tratando de ajustar parámetros que no afectan al resultado. Al igual que yo, sé que no se puede, pero la esperanza sigue ardiendo.

Si tengo algo como Init() y Trade() para cada par + los parámetros ya han sido elegidos, lo único que queda es determinar las acciones, entonces la tarea puede ser resuelta. Aunque, por desgracia, en términos generales, para cualquier número de sistemas - no se puede resolver.

Por lo tanto, tenemos que especificar las "fracciones del sistema" de los pasos. En el caso de los 6 sistemas, el número de pases se calcula mediante 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);     
}

Es posible hacer un script para esto:

input double Mult = 0.04;

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

Además, la tarea optimizada tiene dos parámetros - Mult (no optimizado) y part - de 1 a PartCount6(Mult) en pasos 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);
}

Sólo hay que tener en cuenta que cuanto más pequeño sea el paso, más pasos del bucle habrá que recorrer. Por ejemplo, si el script que calcula el número de pases no devuelve más de 5 minutos, sería mejor reducir el paso. Si no quieres reducir el paso, por ejemplo, divide las monedas por la mitad, prooptimiza cada grupo y luego vuelve a juntarlas "como grupos". (o mejor aún, utilizar correlaciones de sistemas y optimizar por parejas - entonces los ciclos no son tan malos, pero esa es otra historia).

Para otro número de sistemas (incluso menos, incluso más) - todo es lo mismo.

 

Casi se me olvida - después de la optimización necesitarás saber las fracciones - así que ejecuta el pase único que más te guste y escríbelo en 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);
}
 

Descubrí y probé este fallo hace un año e incluso lo mencioné en el foro.

Resulta que sigue vivo.

En resumen: cuando se llama a una función virtual en el constructor, se llama a la función antecesora en lugar de a la función 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;
  }

Impresiones:

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 esto es un error, por favor, arréglalo.

Si se trata de una función, descríbala con detalle en la ayuda y explique cuáles son sus ventajas.

Si es un mal necesario, menciónelo en la casilla especial de la ayuda.

De lo contrario, no te volverás loco buscando un error en tu programa.

Archivos adjuntos:
 

El constructor antecesor no sabe nada de sus descendientes y sus funciones virtuales.

¿Cómo se construye un objeto?

1. En primer lugar, se llama al constructor del "motor principal". Expone su tabla de funciones virtuales. El ancestro no sabe nada de los descendientes que siguen la jerarquía de la herencia, y las tablas de funciones virtuales de los descendientes aún no existen.

2. Se llama al constructor del siguiente descendiente en la jerarquía. Este descendiente expone su tabla de funciones virtuales. Las funciones (incluidas las virtuales) del descendiente están disponibles en el descendiente. Pero, de nuevo, este descendiente no sabe nada de los descendientes que le siguen en una jerarquía (como en el punto 1).

3. El punto 2 se repite, hasta que se cumpla la jerarquía.

Resumen. No utilice funciones virtuales en los constructores. Y tampoco lo utilices en los destructores.

 
MetaDriver:

Si se trata de un mal inevitable, menciónelo en la casilla especial del manual.

Es una práctica común no llamar a las funciones virtuales antes del constructor y después del inicio del destructor.
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
  • www.mql5.com
Основы языка / Объектно-ориентированное программирование / Виртуальные функции - Документация по MQL5
 
stringo:

El constructor antecesor no sabe nada de sus descendientes y sus funciones virtuales.

¿Cómo se construye un objeto?

1. En primer lugar, se llama al constructor del "motor principal". Expone su tabla de funciones virtuales. El ancestro no sabe nada de los descendientes que siguen la jerarquía de la herencia, y las tablas de funciones virtuales de los descendientes aún no existen.

2. Se llama al constructor del siguiente descendiente en la jerarquía. Este descendiente expone su tabla de funciones virtuales. Las funciones (incluidas las virtuales) del descendiente están disponibles en el descendiente. Pero, de nuevo, este descendiente no sabe nada de los descendientes que le siguen en una jerarquía (como en el punto 1).

3. Repite el punto 2, hasta que se cumpla la jerarquía.

Resumen. No utilice funciones virtuales en los constructores. Tampoco en los destructores.

Vale, pero aún así ponlo en un lugar destacado, si va a ser así.

En general, no se trata de la jerarquía del ensamblaje (que es como me lo imaginaba), sino en qué lugar del constructor se añade el VMT. Si se añade al principio (antes del código escrito por el usuario) entonces este problema no parece existir, y el código posterior ya puede llamar a las funciones virtuales. Es imposible, indeseable o... ?

TheXpert:
Es una práctica común no llamar a las funciones virtuales antes del final del constructor y después del inicio del destructor.

Pues no sabía nada de eso, aún teniendo algo de experiencia con otros lenguajes orientados a objetos. Quizá porque no suele ser necesario hacer llamadas virtuales dentro de un constructor.

 
MetaDriver:

De acuerdo, pero ponlo en un lugar destacado en el servicio de asistencia, si es que va a ser así.


La documentación reflejará este hecho en varios lugares
 
stringo:
En la documentación, este hecho se reflejará en varios lugares

Vale, genial.

Slava, ¿puedo preguntar (para el desarrollo general) por qué no se puede inicializar la tabla de métodos virtuales al principio del constructor (después de la inicialización de los ancestros)?

--

En algunos casos el código con llamadas virtuales en el constructor podría ser bastante útil. Un ejemplo reciente: quería cargar objetos desde un archivo directamente en el constructor. El plan era comprobar los tipos durante la carga comparándolos con los ID de tipo devueltos por las funciones virtuales. Esto era un fastidio, debido a la imposibilidad de realizar llamadas virtuales desde el constructor. Resuelto el problema, pero no de forma tan elegante como estaba previsto.

Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
  • www.mql5.com
Основы языка / Объектно-ориентированное программирование / Виртуальные функции - Документация по MQL5
 
MetaDriver:
Así que haz una fábrica. El problema se resolverá.