Явление Христа народу - как обьяснить глюк?

 

Я и раньше замечал периодически, что с расчётом индикаторов что-то не так, а вчера вот поймал... И даже могу примерно описать, при каких условиях он возникает. Сравните третий бар на двух графиках.

Возникает примерно так: открываем МТ4, он рисует графики, подгружает историю, открываем второй график и наслаждаемся разницей. В аттаче нижний индюк. Вопрос - что я не так делаю?

Файлы:
 

Попробуй это вариант

Файлы:
 
Azzx:

Я и раньше замечал периодически, что с расчётом индикаторов что-то не так, а вчера вот поймал... И даже могу примерно описать, при каких условиях он возникает. Сравните третий бар на двух графиках.

Возникает примерно так: открываем МТ4, он рисует графики, подгружает историю, открываем второй график и наслаждаемся разницей. В аттаче нижний индюк. Вопрос - что я не так делаю?



Все так. Это умеют делать очень много индикаторов. У меня таких много. Дело в дыре в истории, возникающей при подключении к серверу. Приходит тик, запускается индикатор, история еще может быть не загружена, а индикатор считается с пропущенными барами. Где-то, в Code Base, встречались индикаторы с принудительной переинициализацией индикатора. Я тогда не понимал, какая проблема решается. На сегодня программного решения у меня нет. Руками обновляю индикаторы. Если индикаторов много и используются таймфреймы выше М1, можно перезапустить терминал.
 
Mislaid:

Все так. Это умеют делать очень много индикаторов. У меня таких много. Дело в дыре в истории, возникающей при подключении к серверу. Приходит тик, запускается индикатор, история еще может быть не загружена, а индикатор считается с пропущенными барами. Где-то, в Code Base, встречались индикаторы с принудительной переинициализацией индикатора. Я тогда не понимал, какая проблема решается. На сегодня программного решения у меня нет. Руками обновляю индикаторы. Если индикаторов много и используются таймфреймы выше М1, можно перезапустить терминал.

// Главный цикл.
int start() {
  int i = Bars - IndicatorCounted();
  if (i>1)  i=Bars-1; // Если обрабатываемый бар не нулевой или первый - полный перерасчет

  for(; i >= 0; i--) {
    double range = High[i] - Low[i];
    buf[i]=0;
    if (range>0) buf[i] = (Close[i] - Low[i]) / range - 0.5;
  }
  
  return(0);
}
 
Vinin:

У Вас решение радикальное.

У меня более спорное, но, мне кажется, тоже должно работать

// Главный цикл.
int start() {
  // индикатор считается неверно на первом загружаемом баре
  // увеличение глубины пересчета на один бар должно решить проблему
  int i = Bars - IndicatorCounted() + 1;

  for(; i >= 0; i--) {
    double range = High[i] - Low[i];
    buf[i]=0;
    if (range>0) buf[i] = (Close[i] - Low[i]) / range - 0.5;
  }
  
  return(0);
}
 
)) Видимо, Виктор имел ввиду в т.ч. и мои варианты с ф-й reinit() - дополнительной переинициализацией.

А так, лаконичный вид конструкции, что была предложена выше, выглядит так:

void start() {
   // граница пересчета
   int limit=Bars-IndicatorCounted()-1;  
   if(limit>1) limit=Bars-1; 
   // цикл пересчета
   for(int i=limit; i>=0; i--) {//}
  }

Если нужна доп. реинициализация, то она вызывается по условию в секции // граница пересчета. Она нужна, в частности, если используются стат.переменные.

Дабы не усложнять main, можно перенести limit=Bars-1 (с возратом результата) в код reinit() и тогда это будет выглядеть так:

void start() {
   // граница пересчета
   int limit=Bars-IndicatorCounted()-1;  
   if(limit>1) limit=reinit(); 
   // цикл пересчета
   for(int i=limit; i>=0; i--) {//}
  }
 
Svinozavr:
)) Видимо, Виктор имел ввиду в т.ч. и мои варианты с ф-й reinit() - дополнительной переинициализацией.

А так, лаконичный вид конструкции, что была предложена выше, выглядит так:

Если нужна доп. реинициализация, то она вызывается по условию в секции // граница пересчета. Она нужна, в частности, если используются стат.переменные.

Дабы не усложнять main, можно перенести limit=Bars-1 (с возратом результата) в код reinit() и тогда это будет выглядеть так:





Маленькая поправка

void start() {
   // граница пересчета
   int limit=Bars-IndicatorCounted();  // Единицу отнимать не надо. 
   if(limit>1) limit=Bars-1; 
   // цикл пересчета
   for(int i=limit; i>=0; i--) {//}
  }
Иначе не всегда будет рассчитываться первый бар. Недавно столкнулся с этим
 

самый надежный вариант - рассчитать самостоятельно какое должно быть время у нулевого бара и в старте ничего не делать пока Time[0] не станет равным рассчитанному (т.е. пока не приедет самая последняя котировка).

к сожалению здесь есть грабли и большие. локальное время своей машинки мы знаем. а вот серверное - нет. точнее не время а таймзоны чтобы по ней зная свое локальное время вычислить что сейчас должно быть на сервере. Проблема была поднята здесь https://www.mql5.com/ru/forum/123222, но поскольку разработчики уже забили на четверку ответ их был таков:

stringo:

К сожалению, мы не добавим новую функциональность в четвёрку.

поэтому вам придется ручками задавать эту самую таймзону и считать какое должно быть Time[0] вручную для каждого своего счета.
 
Vinin:


Маленькая поправка

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

Что-то я не догоняю - это как же? К тому же при нулевом значении IndicatorCounted() будет выход индекса за границы пересчитываемых ценовых массивов.

===

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

Есть еще один тонкий момент в штатном без пропусков рабочем режиме (когда пересчитываются только 0-й и 1 бары). Он также связана с использованием статики. Алгоритм может быть построен так,что посчитанная ранее стат переменная по приходу нового бара будет пересчитана заново, и, если ее значение зависит от триггера, то может возникнуть ошибка - значение это переменной будет др., чем при первом вычислении. Это тоже нужно учитывать. Вообще, подводных камней много.

 

А... Может ты имел ввиду принудительный пересчет 0-го и 1- баров на каждом тике, а не только по приходу первого тика нового бара?

Ну... м.б. И скважность загрузки ЦП нормализуется. Но тогда конструкция будет выглядеть несколько иначе. Но это тоже не снимает нектр. проблем - напр., как в посте выше.

 
Vinin:

Попробуй это вариант


Ок, попробую подловить. Решение сильно "радикально", имхо. Но интересно - поможет ли? Я так понимаю, IndicatorCounted() в случае "догона" котировок возвращает (может, не всегда) неправильное значение. По идее ведь он должен захватывать и этот бар тоже. А если обновляться должно 2 бара (а он вернёт 1, т.е.) - то фокус, по идее, не сработает... :(