Оптимизация первоначального расчета индикатора

 

Есть индикатор, стоит он на М5. История загружена полная - с 1999. Индикатор тяжелый. Настолько тяжелый, что первоначальный расчет его по всем барам истории происходит долго, секунд 50. А если учесть, что советник, использующий этот индикатор, должен быть мультивалютником, то первоначальный расчет на всех парах, по идее, должен занимать минуты. Долго это, хоть и однажды.

Хочу уменьшить время первоначального расчета, оставив всю загруженную историю баров на месте. Далекие в истории бары мне рассчитывать не обязательно.

Решаю проблему так. Стандартный кусок кода, используемый при оптимизации расчетов, изменяю таким образом:

int start()
   int counted_bars = IndicatorCounted() / 10;
   int limit;
   if( counted_bars > 0 )     counted_bars --;
   limit = Bars / 10 - counted_bars;
   
   for( int i = limit; i >= 0; i -- ) 
   {
      <Расчеты>
   }
   <...>

Что происходит? На первом тике после загрузки индикатора IndicatorCounted() возвращает 0. Следовательно, limit = Bars / 10. Все расчеты производятся не на полной истории, а только на 10-й ее части, близкой к настоящему времени.

Далее, на следующих тиках, когда уже вся история подсчитана, IndicatorCounted() возвращает Bars или Bars-1, и limit снова близок к нулю.

Таким образом, убиваем двух зайцев: и история вся на месте, и первоначальный расчет не такой тяжелый, как при расчете полной истории.

Есть другие варианты?

 
Mathemat писал(а) >>

Есть индикатор, стоит он на М5. История загружена полная - с 1999. Индикатор тяжелый. Настолько тяжелый, что первоначальный расчет его по всем барам истории происходит долго, секунд 50. А если учесть, что советник, использующий этот индикатор, должен быть мультивалютником, то первоначальный расчет на всех парах, по идее, должен занимать минуты. Долго это, хоть и однажды.

Хочу уменьшить время первоначального расчета, оставив всю загруженную историю баров на месте. Далекие в истории бары мне рассчитывать не обязательно.

Решаю проблему так. Стандартный кусок кода, используемый при оптимизации расчетов, изменяю таким образом:

Что происходит? На первом тике после загрузки индикатора IndicatorCounted() возвращает 0. Следовательно, limit = Bars / 10. Все расчеты производятся не на полной истории, а только на 10-й ее части, близкой к настоящему времени.

Далее, на следующих тиках, когда уже вся история подсчитана, IndicatorCounted() возвращает Bars или Bars-1, и limit снова близок к нулю.

Таким образом, убиваем двух зайцев: и история вся на месте, и первоначальный расчет не такой тяжелый, как при расчете полной истории.

Есть другие варианты?

Мой вариант

extern int Limit=1000;

int start(){
   int i, limit, counted_bars=IndicatorCounted();

   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
   limit=Bars-counted_bars;
   if (limit>Limit && Limit>0) limit=Limit;
   for (i=limit;i>=0;i--) {


   }
}

Поменяв значение Limit на 0 получим расчет индикатора по всей истории. Также можно указать любое произвольное количество баров для расчета

 

Да, у тебя проще и понятнее. А я-то извращался...

 

Можно я сюда влезу со своим вопросом? )

 

Вопрос насчет отрисовки буферов тяжелых индикаторов и индикаторов средней тяжести. ) Что-то у меня пока руки не доходят, но наверняка кто-то уже пробовал. Ускоряется ли оптимизация параметров индикатора в советнике, если используется несколько тяжелых индикаторов, но вместо отрисовки буферов просто брать их значения, не выводя графически в окно? Если да, то насколько процентов (навскидку), или даже не стоит на этом заморачиваться?

 

А по теме, я обычно ставлю количество обсчитываемых баров 300-500 или в этом районе, вроде хватает.

 
StSpirit писал(а) >>

Можно я сюда влезу со своим вопросом? )

Вопрос насчет отрисовки буферов тяжелых индикаторов и индикаторов средней тяжести. ) Что-то у меня пока руки не доходят, но наверняка кто-то уже пробовал. Ускоряется ли оптимизация параметров индикатора в советнике, если используется несколько тяжелых индикаторов, но вместо отрисовки буферов просто брать их значения, не выводя графически в окно? Если да, то насколько процентов (навскидку), или даже не стоит на этом заморачиваться?

А по теме, я обычно ставлю количество обсчитываемых баров 300-500 или в этом районе, вроде хватает.

При тестировании и оптимизации доступна история порядка 1000 баров. Для корректно сделанного индикатора обычно ограничения в расчетах для советника особо не нужны. Выигрыш по времени будет минимальным (но только для корректно сделанных). Потому что при использовании iCustom() расчета предыдущих значений не производится, а берутся уже готовые из индикатора.

При установке советника на ДЕМО или РЕАЛ уже будет иметь знаечние. Доступной истории больше.

По поводу отрисовки - не совсем понятно.

 

вариант которым пользуюсь я.

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Red
#property indicator_width1 1

extern int  MinBars = 200;

int PreBars;
datetime BarTime;
int StartPos;
int pos;

double Bufer_0[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init() {
  SetIndexBuffer(0,Bufer_0);
  SetIndexStyle(0,DRAW_LINE);
  SetIndexEmptyValue(0,0.0);
  return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit() {
  return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator reset function                                  |
//+------------------------------------------------------------------+
int Reset() {
  if (MinBars == 0) MinBars = Bars-1;
  StartPos = MinBars;
  PreBars = 0;
  BarTime = 0;
  return(StartPos);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start() {
//  Работаем только по закончившимся барам
  if (Bars == PreBars) return(0);  
//  Проверим, достаточно ли баров на графике
  if (Bars < MinBars)  return(0);
//  Если не было докачки истории, обсчитываем только закончившийся бар
  if (Bars-PreBars == 1 && BarTime==Time[1]) StartPos = 1;
//  Иначе пересчитываем заданное в функции Reset() количество баров 
  else StartPos = Reset();
// Модифицируем контрольные переменные
  PreBars = Bars;  
  BarTime=Time[0];
// Цикл по истории
  for (pos=StartPos;pos>0;pos--) {
// Эта операция обязательна для корректного персчёта индикатора
    Bufer_0[pos-1] = 0;
// .....
  }  //  pos=StartPos;pos>0;pos--)
  return(0);
}
 
Vinin >>:

По поводу отрисовки - не совсем понятно.

Я имел ввиду заменить буферы массивами и перенести рассчет индикатора в советник, графически никак не отображать данные индикатора. Получим ли ощутимую разницу, обойдя iCustom?

 
StSpirit писал(а) >>

Я имел ввиду заменить буферы массивами и перенести рассчет индикатора в советник, графически никак не отображать данные индикатора. Получим ли ощутимую разницу, обойдя iCustom?

И да, и нет. Но в большинстве случаев особого выиграша нет. Хотя есть исключения. Все зависит от конкретной реализации. Во многих случаях проще оптимизировать индикатор для ускорения расчетов.

Перерисовывающие точно лучше расчеты переносить в советник, или же избавляться от перерисовки.

 
Vinin писал(а) >>

Мой вариант

Поменяв значение Limit на 0 получим расчет индикатора по всей истории. Также можно указать любое произвольное количество баров для расчета

Этот вариант не очень т.к. пересчитывается 0, 1 и 2 бар, ладно бог с ним с нулевым, а вот то что 1 и 2-ой пересчитывается это плохо.

 
Prival >>:

Этот вариант не очень т.к. пересчитывается 0, 1 и 2 бар, ладно бог с ним с нулевым, а вот то что 1 и 2-ой пересчитывается это плохо.

Поясните, пож. для тупых: когда пересчитывется, при Limit=0 ? И что имеется в виду под пересчетом, просто лишняя операция или возможность изменения показаний 1-го и 2-го бара ?

Важно, поскольку пользуюсь методом Vinin'а.

 
granit77 писал(а) >>

Поясните, пож. для тупых: когда пересчитывется, при Limit=0 ? И что имеется в виду под пересчетом, просто лишняя операция или возможность изменения показаний 1-го и 2-го бара ?

Важно, поскольку пользуюсь методом Vinin'а.

при любом значении Limit, пересчитывается 0 1 и 2 бар. Можете проверить просто вставьте принт

   Print("i=",i);

вот что будет в логе при приходе нового тика

2009.03.12 10:24:38 111 EURUSD,M1: i=0

2009.03.12 10:24:38 111 EURUSD,M1: i=1

2009.03.12 10:24:38 111 EURUSD,M1: i=2

2009.03.12 10:24:37 111 EURUSD,M1: i=0

2009.03.12 10:24:37 111 EURUSD,M1: i=1

2009.03.12 10:24:37 111 EURUSD,M1: i=2

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

Причина обращения: