Erros, bugs, perguntas - página 741

 
ivandurak:

Não sou muito de explicar. Deixe-me tentar novamente. A tarefa consiste em formar uma carteira de moedas, cada moeda com os seus próprios parâmetros. Numa carteira optimizada, uma moeda não pode participar. Calculei seis moedas em 21 etapas de optimização para cada moeda, e a soma total é em milhares de milhões.

Agora a questão. Se proibirmos uma moeda a negociar com uma bandeira então não faz sentido optimizar os seus parâmetros, de qualquer forma eles não afectarão o resultado de forma alguma, mas o optimizador tentará encaixar parâmetros que não afectem o resultado. Como eu sei que não podeis, mas a esperança ainda está a prosperar.

Sim, tudo bem. Haverá passes desnecessários.

Se o TC lhe permitir, deve optimizar cada par separadamente.

A optimização geral envolve imho cair na armadilha da cobertura mágica )))))

Há outra solução. Na outra direcção da proposta por mim, mas reduz as corridas desnecessárias.

Por exemplo, a sua enumeração do parâmetro 100 no intervalo 50-150.

Isto reduz o número de escolhas por uma dimensão.

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:

Não sou muito de explicar. Deixe-me tentar novamente. A tarefa consiste em formar uma carteira de moedas, cada moeda com os seus próprios parâmetros. Numa carteira optimizada, uma moeda não pode participar. Calculei seis moedas em 21 etapas de optimização para cada moeda, e a soma total é em milhares de milhões.

Agora a questão. Se proibirmos uma moeda de negociar com uma bandeira então não faz sentido optimizar os seus parâmetros, de qualquer forma eles não afectarão o resultado de forma alguma, mas o optimizador continuará a tentar encaixar parâmetros que não afectem o resultado. Como eu sei que não podeis, mas a esperança continua a ser ardente.

Se eu tiver algo como Init() e Trade() para cada par + parâmetros já foram escolhidos, a única coisa que me resta é determinar as acções, então a tarefa pode ser resolvida. Embora, infelizmente, em termos gerais, para qualquer número de sistemas - não pode ser resolvido.

Portanto, precisamos de especificar o passo "fracções do sistema". Para 6 sistemas, o número de passes é calculado por 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);     
}

É possível fazer um guião para isto:

input double Mult = 0.04;

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

Além disso, a tarefa optimizada tem dois parâmetros - Mult (não optimizada) e parte - de 1 a PartCount6(Mult) em passos 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);
}

Basta ter em mente que quanto menor for o passo, mais passos no laço terá de percorrer. Por exemplo, se o guião que calcula o número de passes não regressar mais de 5 minutos, seria melhor reduzir o passo. Se não quiser reduzir o passo, por exemplo, dividir as moedas ao meio, optimizar cada grupo, e depois voltar juntos "como grupos". (ou melhor ainda utilizar correlações de sistemas e optimizar aos pares - então os ciclos não são assim tão maus, mas isso é outra história).

Para outro número de sistemas (ainda menos, ainda mais) - tudo é igual.

 

Quase me esquecia - após a optimização, terá de conhecer as fracções - por isso, faça a passagem única que mais lhe agrada e escreva-a no 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);
}
 

Descobri e testei este vírus há um ano atrás e até o mencionei no fórum.

Ao que parece, ainda está vivo.

Conclusão: quando uma função virtual é chamada no construtor, a função dos antepassados é chamada em vez da função 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;
  }

Estampas:

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 se tratar de um bug, por favor repare-o.

Se for uma característica, cubra-a em detalhe na ajuda e explique quais são os benefícios.

Se for um mal necessário, por favor mencione-o na caixa especial na ajuda.

Caso contrário, não ficará louco à procura de um bug no seu programa.

Arquivos anexados:
 

O construtor antepassado nada sabe sobre os seus descendentes e as suas funções virtuais.

Como é construído um objecto?

1. Primeiro, o construtor do "motor principal" é chamado. Expõe a sua tabela de funções virtuais. O antepassado não sabe nada sobre os descendentes seguindo a hierarquia da herança, e as tabelas de funções virtuais dos descendentes ainda não existem.

2. O construtor do próximo descendente na hierarquia é chamado. Este descendente expõe a sua tabela de funções virtuais. As funções (incluindo funções virtuais) do descendente estão disponíveis no descendente. Mas, mais uma vez, este descendente nada sabe sobre os descendentes que o seguem numa hierarquia (como no ponto 1).

3. O ponto 2 é repetido, até que a hierarquia seja cumprida.

Resumo. Não utilizar funções virtuais em construtores. E também não a utilize em destruidores.

 
MetaDriver:

Se for um mal inevitável, por favor mencione-o na ajuda, numa caixa especial.

É uma prática comum não chamar funções virtuais antes do construtor e depois do início do destrutor.
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
  • www.mql5.com
Основы языка / Объектно-ориентированное программирование / Виртуальные функции - Документация по MQL5
 
stringo:

O construtor antepassado nada sabe sobre os seus descendentes e as suas funções virtuais.

Como é construído um objecto?

1. Primeiro, o construtor do "motor principal" é chamado. Expõe a sua tabela de funções virtuais. O antepassado não sabe nada sobre os descendentes seguindo a hierarquia da herança, e as tabelas de funções virtuais dos descendentes ainda não existem.

2. O construtor do próximo descendente na hierarquia é chamado. Este descendente expõe a sua tabela de funções virtuais. As funções (incluindo funções virtuais) do descendente estão disponíveis no descendente. Mas, mais uma vez, este descendente nada sabe sobre os descendentes que o seguem numa hierarquia (como no ponto 1).

3. Repetir o ponto 2, até que a hierarquia seja cumprida.

Resumo. Não utilizar funções virtuais em construtores. Nem em destruidores.

Está bem, mas ainda assim coloque-o num lugar de destaque, se vai ser assim.

Em geral, não se trata de hierarquia de montagem (que é como eu imaginava), mas em que lugar do construtor é acrescentado o VMT. Se for acrescentado no início (antes do código escrito pelo utilizador) então este problema não parece existir, e o código subsequente pode já chamar as funções virtuais. É impossível, indesejável ou... ?

TheXpert:
É uma prática comum não chamar funções virtuais antes do fim do construtor e depois do início do destrutor.

Bem, eu não sabia nada sobre isso, mesmo tendo alguma experiência com outras línguas orientadas para objectos. Talvez porque muitas vezes não é necessário fazer chamadas virtuais dentro de um construtor.

 
MetaDriver:

OK. Mas ainda assim coloque-o num lugar de destaque no helpdesk, se é assim que vai ser.


A documentação irá reflectir este facto em vários locais
 
stringo:
Na documentação, este facto reflectir-se-á em vários locais

OK, óptimo.

Slava, posso perguntar (para desenvolvimento geral) porque não se pode inicializar a tabela do método virtual no início do construtor (depois da inicialização dos antepassados)?

--

Em alguns casos, o código com chamadas virtuais no construtor pode ser bastante útil. Um exemplo recente: eu queria carregar objectos de ficheiro directamente no construtor. O plano era verificar os tipos enquanto carregava, comparando com as IDs de tipo devolvidas por funções virtuais. Isto foi uma chatice, devido à impossibilidade de fazer chamadas virtuais por parte do construtor. Resolveu o problema, mas não tão elegantemente como planeado.

Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
  • www.mql5.com
Основы языка / Объектно-ориентированное программирование / Виртуальные функции - Документация по MQL5
 
MetaDriver:
Por isso, fazer uma fábrica. O problema será resolvido.