Ошибки, баги, вопросы - страница 741

 
ivandurak:

фиговый из меня обьяснятель. Попробую еще раз. Стоит задача сформировать портфель валют, каждая валюта со своими параметрами. Во оптимизированном портфеле валюта может не участовать. Немного подсчетов  шесть валют по 21 шагов оптимизации по каждой валюте, в совокупности до фига счет на миллиарды. 

Теперь вопрос. Запрещаем флагом валюте торговать, то и оптимизировать ее параметры нет никакго смысла, все равно они на результат никак не повлияют, однако оптимизатор будет исправно пытаться подбирать параметры которые на результат не влияют, этот пустой прогон немного напрягает (уже третьи сутки пошли). Вроде как сам знаю что нельзя, но надежда еще теплится. 

Да,все верно.Будут лишние проходы.Но это вариант комплексного запуска оптимизации.

Если ТС позволяет ,то как уже ответили,оптимизировать каждую пару отдельно.А для себя,для галочки сделать одиночный мультивалютный прогон.

Общая оптимизация предполагает имхо попадание в ловушку волшебного хеджинга ))).

 

Есть еще одно решение.В другую сторону от предложенного мной,но снижает лишние прогоны.

К примеру ваш перебор параметра 100 в интервале 50-150.Выделите одно значение на false.

Так на одно измерение снижается количество вариантов.Генетика разруливает. 

 

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:

фиговый из меня обьяснятель. Попробую еще раз. Стоит задача сформировать портфель валют, каждая валюта со своими параметрами. Во оптимизированном портфеле валюта может не участовать. Немного подсчетов  шесть валют по 21 шагов оптимизации по каждой валюте, в совокупности до фига счет на миллиарды. 

Теперь вопрос. Запрещаем флагом валюте торговать, то и оптимизировать ее параметры нет никакго смысла, все равно они на результат никак не повлияют, однако оптимизатор будет исправно пытаться подбирать параметры которые на результат не влияют, этот пустой прогон немного напрягает (уже третьи сутки пошли). Вроде как сам знаю что нельзя, но надежда еще теплится. 

Если у вас есть что-то вроде Init() и Trade() для каждой пары + параметры уже подобраны, осталось лишь определить доли, то задача решаема. Хотя, к сожалению, в общем виде, для любого числа систем - решить не удалось.

Итак, нужно задать шаг "доли системы".  Для 6 систем, кол-во проходов вычисляется ф-ей:

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

Можно скрипт сделать для этого:

input double Mult = 0.04;

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

далее, оптимизируемая задача имеет два параметра - Mult (не оптимизируется) и part - от 1 до PartCount6(Mult) c шагом 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);
}

Только учтите, что чем меньше шаг, тем больше шагов в цикле нужно пройти. Например, если скрипт, считающий кол-во проходов, не возвращает значение более 5 минут, то лучше уменьшить шаг. Если шаг уменьшать не хотите, то, например, разделите валюты пополам, прооптимизируйте каждую группу, а потом ещё раз вместе "как группы". (а ещё лучше использовать корреляции систем и оптимизировать по-парно  - тогда и циклы не такие страшные; но это уже другая история).

Для другого кол-ва систем (хоть меньшего, хоть большего) - всё по аналогии.  

 

чуть не забыл - после оптимизации нужно ведь будет узнать доли - поэтому запускаем одиночный проход, который больше всего нравиться а в 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);
}
 

Этот баг я обнаружил и оттестировал год назад и даже упоминал о нём на форуме.

Как выяснилось, он до сих пор жив.

Суть:  при вызове в конструкторе виртуальной функции, вызывается не родная функция, а функция предка.

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

Принтует:

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

Если это баг, исправьте, пожалуйста.

Если фича, осветите её подробно в хелпе и объясните в чём преимущества.

Если неизбежное зло - тем более упомяните в хелпе в особой рамочке.

Иначе и свихнуться недолго в поисках бага у себя в программе.

Файлы:
 

Конструктор предка ничего не знает о своих потомках и их виртуальных функциях.

Как производится конструирование объекта?

1. Сначала вызывается конструктор "первоиерарха". Он выставляет свою таблицу виртуальных функций. Про потомков, следующих по иерархии наследования, предок ничего не знает, да и таблиц виртуальных функций потомков ещё пока не существует.

2. Вызывается конструктор следующего по иерархии потомка. Этот потомок выставляет свою таблицу виртуальных функций. При этом функции (в т.ч. и виртуальные) предка доступны в потомке. Но опять же этот потомок ничего не знает про следующих за ним по иерархии потомков (как в п. 1)

3. Повторяется п.2 до завершения иерархии

Резюме. Не используйте виртуальные функции в конструкторах. Да и в деструкторах тоже.

 
MetaDriver:

Если неизбежное зло - тем более упомяните в хелпе в особой рамочке.

Так это, вроде общепринятая практика не вызывать виртуальные функции до завершения конструктора и после начала деструктора.
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
  • www.mql5.com
Основы языка / Объектно-ориентированное программирование / Виртуальные функции - Документация по MQL5
 
stringo:

Конструктор предка ничего не знает о своих потомках и их виртуальных функциях.

Как производится конструирование объекта?

1. Сначала вызывается конструктор "первоиерарха". Он выставляет свою таблицу виртуальных функций. Про потомков, следующих по иерархии наследования, предок ничего не знает, да и таблиц виртуальных функций потомков ещё пока не существует.

2. Вызывается конструктор следующего по иерархии потомка. Этот потомок выставляет свою таблицу виртуальных функций. При этом функции (в т.ч. и виртуальные) предка доступны в потомке. Но опять же этот потомок ничего не знает про следующих за ним по иерархии потомков (как в п. 1)

3. Повторяется п.2 до завершения иерархии

Резюме. Не используйте виртуальные функции в конструкторах. Да и в деструкторах тоже.

Ок.  Но всё же в хелпе отметьте это на видном месте, если всё так и будет.

А вообще, дело не в иерархичности сборки (которую я себя так и представлял), а в том в каком месте конструктора добавляется VMT.  Если её добавлять в начале (до кода прописанного юзером) то этой проблемы вроде как нет, и последующий код уже может вызывать виртуальные функции.  Это невозможно, нежелательно или.. ?

TheXpert:
Так это, вроде общепринятая практика не вызывать виртуальные функции до завершения конструктора и после начала деструктора.

  Ну вот я об этом ничего не знал, даже имея кое-какой опыт на других ОО языках.  Возможно потому, что не так уж часто возникает необходимость в виртуальных вызовах внутри конструктора.

 
MetaDriver:

Ок.  Но всё же в хелпе отметьте это на видном месте, если всё так и будет.


В документации данный факт будет отражён в нескольких местах
 
stringo:
В документации данный факт будет отражён в нескольких местах

ОК, отлично.

Слава, а можно поинтересоваться (для общего развития) почему нельзя таблицу виртуальных методов инициализировать в начале конструктора (после инициализации предков) ?

--

В некоторых случаях код с виртуальными вызовоми в конструкторе мог бы быть весьма удобен. Свежий пример: хотел сделать загрузку объектов из файла прямо в конструкторе.  Планировался контроль типов прямо по ходу загрузки путём сравнения с идентификаторами типов, возвращаемыми виртуальными функциями . Вышел облом, в связи с невозможностью виртуальных вызовов из конструктора. Проблему решил, но не так элегантно как планировал.

Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
  • www.mql5.com
Основы языка / Объектно-ориентированное программирование / Виртуальные функции - Документация по MQL5
 
MetaDriver:
Так сделай фабрику. Проблема решится.
Причина обращения: