Errors, bugs, questions - page 741

 
ivandurak:

I'm not much of an explainer. Let me try again. The task is to form a portfolio of currencies, each currency with its own parameters. In an optimized portfolio a currency may not participate. I've calculated six currencies in 21 optimization steps for each currency, and the total sum is in billions.

Now the question. If we forbid a currency to trade with a flag then there is no sense to optimize its parameters, anyway they will not affect the result in any way, but the optimizer will be trying to fit parameters that do not affect the result. Like myself I know you can not, but the hope is still thriving.

Yes, all right. There will be unnecessary passes.

If TC allows you, you should optimize each pair separately.

The general optimization involves imho falling into the trap of magic hedging ))).

There is another solution.In the other direction from the proposed by me,but reduces unnecessary runs.

For example, your enumeration of parameter 100 in the interval 50-150.

This reduces the number of choices by one 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:

I'm not much of an explainer. Let me try again. The task is to form a portfolio of currencies, each currency with its own parameters. In an optimized portfolio a currency may not participate. I've calculated six currencies in 21 optimization steps for each currency, and the total sum is in billions.

Now the question. If we forbid a currency to trade with a flag then there is no sense to optimize its parameters, anyway they will not affect the result in any way, but the optimizer will be trying to fit parameters that do not affect the result. Like myself I know you can not, but the hope is still smoldering.

If I have something like Init() and Trade() for each pair + parameters have already been chosen, the only thing left is to determine the shares, then the task can be solved. Although, unfortunately, in general terms, for any number of systems - can not be solved.

So, we need to specify step "fractions of the system". For 6 systems, the number of passes is calculated by 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);     
}

It is possible to make a script for this:

input double Mult = 0.04;

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

Further, the optimized task has two parameters - Mult (not optimized) and part - from 1 to PartCount6(Mult) in steps of 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);
}

Just keep in mind that the smaller the step, the more steps in the loop you need to go through. For example, if the script which calculates the number of passes does not return a value greater than 5 minutes, it would be better to reduce the step. If you don't want to reduce the step, for example, divide the currencies in half, prooptimize each group, and then go back together "as groups". (or better yet use systems correlations and optimise in pairs - then the cycles are not so bad, but that's another story).

For other number of systems (even less, even more) - everything is the same.

 

I almost forgot - after optimisation you will need to know the fractions - so run the single pass that you like best and write it 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);
}
 

I discovered and tested this bug a year ago and even mentioned it on the forum.

As it turns out, it's still alive.

Bottom line: when a virtual function is called in the constructor, the ancestor function is called instead of the native function.

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

Prints:

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

If this is a bug, please fix it.

If it's a feature, cover it in detail in the help and explain what the benefits are.

If it is a necessary evil, please mention it in the special box in the help.

Otherwise, you won't go crazy looking for a bug in your program.

Files:
 

The ancestor constructor knows nothing about its descendants and their virtual functions.

How is an object constructed?

1. First, the constructor of the "prime mover" is called. It exposes its virtual function table. The ancestor knows nothing about the descendants following the inheritance hierarchy, and the descendants' virtual function tables do not exist yet.

2. The constructor of the next descendant in the hierarchy is called. This descendant exposes its virtual function table. The functions (including virtual functions) of the descendant are available in the descendant. But, again, this descendant knows nothing about the descendants following it in a hierarchy (as in point 1).

3. Point 2 is repeated, until the hierarchy is fulfilled.

Summary. Do not use virtual functions in constructors. And do not use it in destructors either.

 
MetaDriver:

If it's an unavoidable evil, please mention it in the help, in a special box.

It's a common practice not to call virtual functions before constructor and after destructor start.
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
  • www.mql5.com
Основы языка / Объектно-ориентированное программирование / Виртуальные функции - Документация по MQL5
 
stringo:

The ancestor constructor knows nothing about its descendants and their virtual functions.

How is an object constructed?

1. First, the constructor of the "prime mover" is called. It exposes its virtual function table. The ancestor knows nothing about the descendants following the inheritance hierarchy, and the descendants' virtual function tables do not exist yet.

2. The constructor of the next descendant in the hierarchy is called. This descendant exposes its virtual function table. The functions (including virtual functions) of the descendant are available in the descendant. But, again, this descendant knows nothing about the descendants following it in a hierarchy (as in point 1).

3. Repeat point 2, until the hierarchy is fulfilled.

Summary. Do not use virtual functions in constructors. Nor in destructors.

Ok, but still put it in a prominent place, if it's going to be like this.

In general, it's not about hierarchy of assembly (which is how I imagined it), but in what place of constructor the VMT is added. If it is added at the beginning (before the code written by user) then this problem doesn't seem to exist, and the subsequent code may already call the virtual functions. Is it impossible, undesirable or... ?

TheXpert:
It's a common practice not to call virtual functions before constructor's end and after destructor's start.

Well, I didn't know anything about that, even having some experience with other object-oriented languages. Maybe because it's not often necessary to make virtual calls inside a constructor.

 
MetaDriver:

OK. But still put it in a prominent place in the helpdesk, if that's how it's going to be.


The documentation will reflect this fact in several places
 
stringo:
In documentation this fact will be reflected in several places

OK, great.

Slava, can I ask (for general development) why you can't initialize virtual method table at the beginning of constructor (after ancestors initialization)?

--

In some cases code with virtual calls in the constructor could be quite handy. A recent example: I wanted to load objects from file right in the constructor. The plan was to check the types while loading by comparing with type IDs returned by virtual functions. Bummer came out, due to impossibility of virtual calls from the constructor. Solved the problem, but not as elegantly as planned.

Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
  • www.mql5.com
Основы языка / Объектно-ориентированное программирование / Виртуальные функции - Документация по MQL5
 
MetaDriver:
So make a factory. The problem will be solved.
Reason: