Вопрос работы в тестере по пользовательским индикаторам с дополнительными таймсериями

 

Сразу оговорюсь - опыта пока мало, возможно просто делаю что-то не так или плохо понимаю механику системы... Пишу под МТ5.

 

Написал я свой индикатор, принципиальный момент которого - использование данных по тиковым объемам.

Соответственно, насколько мне удалось понять, тиковые объемы можно  передать в тестер только через функцию CopyTickVolume в блоке OnCalculate индикатора (никаким другим способом они в тестере не доступны.. верно, нет?).

Поскольку на каждой свече (или тике) происходит расчет данных индикатора (то бишь выполнение OnCalculate), то фактически процедура копирования "текущего куска истории" тиковых объемов повторяется огромное кол-во раз (верно, нет?).

В результате время работы тестера становится невменяемым, и прямо видно как в начале истории прогресс-бар бежит бодро, а дальше все медленнее - пока фактически не встает...

 . Можно ли как-то передавать в тестер данные для индикатора - однократно, чтобы дальше он их уже использовал? 

 

Я пока вижу вариант - в инициализации тестера получать эти данные (точно так же через CopyTickVolume), и далее встраивать полностью весь код индикатора в код тестера (в OnTick). Т.е. фактически делать отдельный программный "клон" кода индикатора (внутри кода тестера), а это фигня уже какая-то...

Либо, как вариант - в инициализации тестера закешировать значение индикатора в память (через iCustom и копирование значения из хендла в массив), и далее уже чисто по сохраненным значениям работать. Но тогда минус - получится только по закрытым свечка работать, внутри - никак.

 

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

Или я не верно понимаю как работает расчет индикатора внутри тестера? ) 

 

Посмотрите статью:

Принципы экономного пересчета индикаторов

 Основной принцип: если история уже была один раз рассчитана и не было подкачки истории - то расчёт выполняется только для текущего бара.

 
barabashkakvn:

Посмотрите статью:

Принципы экономного пересчета индикаторов

 Основной принцип: если история уже была один раз рассчитана и не было подкачки истории - то расчёт выполняется только для текущего бара.

Большое спасибо за ссылку, в целом - похоже то что нужно.

 

Если не затруднит, откомментируйте пожалуйста, правильно ли я понимаю, что:

1) в тестере эксперта, код индикатора, содержащийся в OnCalculate - вызывается каждый раз когда используется CopyBuffer от хэндла индикатора (т.е. на каждой свечке или тике - в зависимости от настроек тестера)

2) объект-экземпляр индикатора создается при вызове iCustom, и живет всё время до конца теста - т.е. вызов CopyBuffer для хэндла индикатора не приводит к переинициализации объекта индикатора, а приводит лишь к очередному вызову OnCalculate

3) при вызове OnCalculate на очередной свечке в тестере (вследствие CopyBuffer от хэндла индикатора) значение prev_calculated не устанавливается в ноль (как это происходит при реальной торговле), а просто инкрементируется

4) при использовании индикатора в тестере эксперта, использование внутри OnCalculate индикатора тиковых объемов (и прочих дополнительный таймсерий) возможно исключительно через CopyTickVolume, CopyHigh и прочих Copy (а просто брать их из входных массивов OnCalculate - нельзя)?

 ?

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

Заранее большущее спасибо! 

 
grekmipt:

Большое спасибо за ссылку, в целом - похоже то что нужно.

 

Если не затруднит, откомментируйте пожалуйста, правильно ли я понимаю, что:

3) при вызове OnCalculate на очередной свечке в тестере (вследствие CopyBuffer от хэндла индикатора) значение prev_calculated не устанавливается в ноль (как это происходит при реальной торговле), а просто инкрементируется

Добрый вечер. Откуда такая информация? Насколько мне известно, значение prev_calculated устанавливается в ноль после деинициализации (например, смене ТФ), или если вы из OnCalculate вернете значение 0. В других случаях, возвращая rates_total, ноль в prev_calculated Вы не получите.

 
Tapochun:

Добрый вечер. Откуда такая информация? Насколько мне известно, значение prev_calculated устанавливается в ноль после деинициализации (например, смене ТФ), или если вы из OnCalculate вернете значение 0. В других случаях, возвращая rates_total, ноль в prev_calculated Вы не получите.

а, да, невнимательно читал видимо - не увидел что в следующий вызов OnCalculate передается как раз результат предыдущего вызова. Спасибо за пояснение.
 
Petros:
 Тиковые данные получаются в  OnTick(), копировать их не нужно.

Нет, вы меня не поняли. У меня в индикаторе используется объем (тиковый, но это не суть). Это не тиковые данные. Это просто объем сделок. И он нужен не для эксперта  - он нужен для индикатора. Но в индикаторе - этих данных просто нет (если индикатор используется в эксперте), они отсутствуют на входе функции OnCalculate в случае когда эта функция вызывается из эксперта.

И для того чтобы код индикатора корректно рассчитывался в эксперте - нужно копировать данные функцией CopyTickVolume, иначе (если брать их из входного массива tick_volume функции OnCalculate) расчет индикатора в эксперте происходит некорректно. Это видимо какая-то особенность работы индикаторов в экспертах... Если же индикатор сам по себе (не в эксперте, а например просто на график кинуть) - то такой проблемы нет, и можно брать данные напрямую из входного массива tick_volume.

Причем, как удалось выяснить экспериментальным путем ), при использовании функции CopyTickVolume - для текущего бара объем всегда равен 1-ке, и только для предшествующих баров он заполнен корректными цифрами.

В общем, вопрос я вроде-бы решил, копирую данные в индикатор (в OnCalculate) вот таким образом:

   //подгружаем данные по объемам
   if(prev_calculated==0)
   {
      long timeseries[];
      CopyTickVolume(Symbol(),0,0,rates_total,timeseries);
      ArrayCopy(VolArr,timeseries,0,0,rates_total);
   }
   else
   {
      long timeseries[];
      CopyTickVolume(Symbol(),0,0,2,timeseries);
      VolArr[rates_total-1-1]=timeseries[0]; //перезапись объема предыдущего бара - т.к. он доступен на текущем баре
      VolArr[rates_total-1]=1;//timeseries[1]; //текущий объем всё равно всегда равен 1
   }

И тогда всё норм получается.

Так что вопрос закрыт, разобрался.