Значения индикаторов рассчитываются на неправильных барах.

 

Здравствуйте,

Есть советник который берет значения трех индикаторов (Moving Average, Ichimoku, Alligator) на открытии нового 30-минутного бара (сам советник тоже был установлен на 30-минутном таймфрейме). Значение Ichimoku рассчитывается на родном 30-минутном периоде, а значения Moving Average и Alligator рассчитываются на 15-минутном периоде. Для всех индикаторов shift бара равняется 1.

Код проверки открытия нового бара:

if(Time[0]!=Time_Var_GlobalEntries_LastBarTime_Check) { Time_Var_GlobalEntries_LastBarTime_Check=Time[0]; return true;}

Советник был поставлен на ночь на реальный аккаунт для тестирования. В начале теста, значения индикаторов были верны и брались от корректных баров. Например на открытии нового бара в 01:00, Ichimoku вернул корректное значение от бара с временем открытия в 00:30, а Moving Average и Alligator вернули корректные значения от бара с временем 00:45. Но после некоторого времени, индикаторы Moving Average и Alligator неожиданно стали брать значения не от первого закрытого бара, а от 3 закрытого бара (shift как будто изменился с 1 на 3). При этом Ichimoku все еще возвращал корректные значения.  Во время тестирования, я не вмешивался в работу советника. Программно, он тоже не меняет значения shift'ов для индикаторов. Более того, значения параметров, перед тем как отправить их для индикаторных функций, выводятся в журнал. Так что с этим проблем нету. 

Позже провел тестирование советника в визуальном режиме с теми же настройками и на том же периоде, что и во время <<живого>> теста. Значения индикаторов были корректны. Днем советник был снова поставлен на ту же валютную пару и с теми же настройками (ничто не было изменено) и значения индикаторов до конца live теста были правильными и брались от нужных баров.


Может ли быть причина такой ошибки в том, что я изначально не подгрузил историю 15-минутного таймфрейма (ни вручную, ни программно)? И была ли у вас когда-нибудь подобная ситуация ?

 

Снова возникла такая же ситуации, но теперь с индикатором CCI. Советник был установлен на паре GBPJPY М30. Данные индикатора рассчитывались на таймфрейме M5 c shift'oм 1. Приведу пример проверки индикатора в 10:00.

Вот корректное значение, если CCI просто поставить график:

Вот полученное значение в live режиме: "10:00:05.292 IndiMRL 0.28 GBPJPY,M30: CCI (GBPJPY,5). Indicator's value: 75.943". Это значение было взято от бара, у которого время открытия 09:25. Как будто советник сделал проверку индикатора на открытии 30-минутного бара в 09:30.


В тестере советник с теми же настройками вернул корректное значение от бара 09:55:  "2018.04.10 15:11:04.844 2018.04.10 10:00:00   IndiMRL 0.28 GBPJPY,M30: CCI (GBPJPY,5). Indicator's value: 157.976".

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

Сделаю еще пару тестов с открытием графика перед получением данных индикаторов и отпишусь о результатах здесь.

 

Тайм-серии, по которым не открыты графики, сами по себе не обновляются.

Запрашивайте с них какую-нибудь информацию периодически. Например, вызовом такой функции:

//+------------------------------------------------------------------+
//| Подгрузка истории
//+------------------------------------------------------------------+
#define REFRESH_CHART_DATA_SEC 300      // Интервал обновления тайм-серий
ENUM_TIMEFRAMES REFRESH_TFs[9] = { PERIOD_M1, PERIOD_M5, PERIOD_M15, PERIOD_M30, PERIOD_H1, PERIOD_H4, PERIOD_D1, PERIOD_W1, PERIOD_MN1 };

void RefreshChartData()
{
        if ( REFRESH_CHART_DATA_SEC <= 0 || IsTesting() ) return;

        static datetime last_check = 0;
        if ( TimeCurrent() - last_check >= REFRESH_CHART_DATA_SEC )
        {
                last_check = TimeCurrent();
                for ( int i = 0; i < 9; i ++ ) iTime( _Symbol, REFRESH_TFs[i], 0 );
        }
}
 
Andrey Khatimlianskii:

Тайм-серии, по которым не открыты графики, сами по себе не обновляются.

Запрашивайте с них какую-нибудь информацию периодически. Например, вызовом такой функции:

Cпасибо большое за ответ.

Я правильно понимаю, что все равно потребуется сделать какую-нибудь проверку на то, что последний доступный бар младшего таймфрейма не открытого графика является на самом деле последний? Так как вроде вызов какой-либо информации не гарантирует обновления тайм-серии в нужный момент. Cкажем, текущее время 10:26 и у нас только открыт график с периодом 30, а время открытия последнего доступного бара на м15 не открытого графика является 09:45, хотя по факту время отрытия последнего бара должно быть 10:15.    
 

 
Asa saas:

Cпасибо большое за ответ.

Я правильно понимаю, что все равно потребуется сделать какую-нибудь проверку на то, что последний доступный бар младшего таймфрейма не открытого графика является на самом деле последний? Так как вроде вызов какой-либо информации не гарантирует обновления тайм-серии в нужный момент. Cкажем, текущее время 10:26 и у нас только открыт график с периодом 30, а время открытия последнего доступного бара на м15 не открытого графика является 09:45, хотя по факту время отрытия последнего бара должно быть 10:15.    
 

Проверить (и запустить подкачку) можно следующим кодом:

bool IsTFDataReady(int tf)
{
   ResetLastError();
   iTime(NULL, tf, 1);
   return GetLastError() == ERR_NO_ERROR;
}

Если вернет true, то данные по указанному ТФ являются актуальными. В противном случае нужно ожидать окончания подкачки.

 
Asa saas:

Я правильно понимаю, что все равно потребуется сделать какую-нибудь проверку на то, что последний доступный бар младшего таймфрейма не открытого графика является на самом деле последний? Так как вроде вызов какой-либо информации не гарантирует обновления тайм-серии в нужный момент. Cкажем, текущее время 10:26 и у нас только открыт график с периодом 30, а время открытия последнего доступного бара на м15 не открытого графика является 09:45, хотя по факту время отрытия последнего бара должно быть 10:15.     

Я обхожусь без проверки, но можно и дописать пару строк для надежности.

 

Огромное спасибо всем за ответы! Благодаря им смог решить проблему. Тут еще оказывается, что после вызова iTime, если история все еще в процессе обновления, то GetLastError выдаст код 4066. И тут уже можно просто вызвать Sleep() и подождать пока история догрузится. Так что, теперь более осведомлен о решении подобной проблемы.

 
Asa saas:

Огромное спасибо всем за ответы! Благодаря им смог решить проблему. Тут еще оказывается, что после вызова iTime, если история все еще в процессе обновления, то GetLastError выдаст код 4066. И тут уже можно просто вызвать Sleep() и подождать пока история догрузится. Так что, теперь более осведомлен о решении подобной проблемы.

Нет, не только 4066, есть еще и другие ошибки. Именно поэтому в функции условие:

GetLastError() == ERR_NO_ERROR

а не какое-то другое. Этот вариант опробован временем.

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

 
Ihor Herasko:

Нет, не только 4066, есть еще и другие ошибки. Именно поэтому в функции условие:

а не какое-то другое. Этот вариант опробован временем.

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

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

bool Misc_Func_CheckHistoryData(string symbol,int period,int shift,bool print_log=true)
  {
   int cycle_tries=0,error=1;

   while(error!=0)
     {

      ResetLastError();
      iTime(symbol,period,shift);
      Sleep(1000); error=GetLastError();
      // если ошибка равна 4073, тогда открываем график нужной пары и таймфрейма для загрузки новой истории
      if(error==4073) { Misc_Func_LoadHistoryData(symbol,period); }
      // если ошибка равна 4066, тогда просто ждем пока процесс обновления закончится
      if(error==4066) Sleep(5000);
      // если возникла другая ошибка или было сделано 5 попыток, то выходим из цикла
      if((error!=4073 && error!=4066) || cycle_tries>=5) break;
      cycle_tries++;

     }

   return error == ERR_NO_ERROR;

  }
PS. Эти проверки делаются для советника, а не для индикатора.
 
Asa saas:

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

PS. Эти проверки делаются для советника, а не для индикатора.

Поставьте в начале OnTick():

if (!IsTFDataReady(<нужный ТФ>))
   return;

и все.

Для подгрузки истории график запрашиваемого ТФ открывать не обязательно.

 
Ihor Herasko:

Поставьте в начале OnTick():

и все.

Для подгрузки истории график запрашиваемого ТФ открывать не обязательно.

Ага, понял. Спасибо Вам за советы.

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