[СЕРВИСДЕСК] Ошибка получения времени старшего ТФ в таймере!

Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий
Alexey Kozitsyn
8946
Alexey Kozitsyn  

Задача: при запуске индикатора получить в таймере актуальные данные: время открытия недельного, дневного и часового бара. Затем записать их в глобальные переменные для дальнейшего использования. Текущий ТФ - М1.

Реализация: Время баров получаем с помощью функции SeriesInfoInteger().

#property version   "1.00"
#property strict
#property indicator_chart_window
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//--- Время открытия текущего часа, дня и недели
datetime _weekOpenTime = 0;
datetime _hourOpenTime = 0;
datetime _dayOpenTime=0;
//--- Вести лог журнала
const bool inpFileLog=true;
//--- Количество секунд в одном дне
const int SEC_PER_DAY=86400;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Запускаем таймер
   if(!EventSetMillisecondTimer(20))
     {
      Print(__FUNCTION__,": ОШИБКА #",GetLastError(),": таймер с частотой 20 ms не установлен!");
      return( INIT_FAILED );
     }
//--- Сбрасываем время открытия текущего часа, дня и недели
   _weekOpenTime= 0;
   _dayOpenTime = 0;
   _hourOpenTime= 0;
//---
   return( INIT_SUCCEEDED );
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {

   return( rates_total );
  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Проверяем, записано ли время открытия текущей недели
   if(!CheckCurrentWeekOpenTime())                        // Если время не записано
      return;                                                // Выходим
//--- Проверяем, записано ли время открытия текущего дня
   if(!CheckCurrentDayOpenTime())                        // Если время не записано
      return;                                                // Выходим
//--- Проверяем, записано ли время открытия текущего часа
   if(!CheckCurrentHourOpenTime())                        // Если время не записано
      return;                                                // Выходим
  }
//+------------------------------------------------------------------+
//| Проверяем, записано ли время открытия текущей недели             |
//+------------------------------------------------------------------+
bool CheckCurrentWeekOpenTime()
  {
//--- Проверяем, записано ли время
   if(_weekOpenTime==0) // Если время не записано
     {
      //--- Получаем время открытия недельного бара
      ResetLastError();
      const datetime weekBarOpenTime=(datetime)SeriesInfoInteger(_Symbol,PERIOD_W1,SERIES_LASTBAR_DATE);
      const int err=GetLastError();
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Время открытия недельного бара = "+TimeToString(weekBarOpenTime)+". Ошибка #",err);
         //Print( __FILE__,": Время открытия текущей недели через iTime = "+TimeToString( weekOpenTime2 )+". Ошибка #",err2 );
        }
      //ResetLastError();
      //const datetime weekBarOpenTime2 = iTime( _Symbol, PERIOD_W1, 0 );
      //const int err2 = GetLastError();
      //--- Проверяем, получено ли время открытия недельного бара
      if(weekBarOpenTime==0 || err!=0) // Если время бара не получено или история обновляется
         return(false);                              // Возвращаем ложь
      //--- Запоминаем время открытия текущей недели (время открытия недельного бара - воскресенье)
      _weekOpenTime=weekBarOpenTime+SEC_PER_DAY;
      //const datetime weekOpenTime2 = weekBarOpenTime2+SEC_PER_DAY;
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Актуальное время открытия текущей недели = "+TimeToString(_weekOpenTime)+". Ошибка #",err);
         //Print( __FILE__,": Время открытия текущей недели через iTime = "+TimeToString( weekOpenTime2 )+". Ошибка #",err2 );
        }
      //--- Возвращаем истину
      return( true );
     }
//--- Время открытия недели ранее записано. Возвращаем истину
   return( true );
  }
//+------------------------------------------------------------------+
//| Проверяем, записано ли время открытия текущего дня                  |
//+------------------------------------------------------------------+
bool CheckCurrentDayOpenTime()
  {
//--- Проверяем, записано ли время
   if(_dayOpenTime==0) // Если время не записано
     {
      //--- Получаем время открытия дневного бара
      ResetLastError();
      const datetime tempDayOpenTime=(datetime)SeriesInfoInteger(_Symbol,PERIOD_D1,SERIES_LASTBAR_DATE);
      const int err=GetLastError();
      //ResetLastError();
      //const datetime dayOpenTime2 = iTime( _Symbol, PERIOD_D1, 0 );
      //const int err2 = GetLastError();
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Время открытия текущего дня = "+TimeToString(tempDayOpenTime)+". Ошибка #",err);
         //Print( __FILE__,": Время открытия текущего дня iTime = "+TimeToString( dayOpenTime2 )+". Err2 #",err2 );
        }
      //--- Проверяем, получено ли время открытия дневного бара
      if(tempDayOpenTime==0 || err!=0) // Если время бара не получено
         return(false);                                 // Возвращаем ложь
      //--- Сохраняем в глобальную переменную значение открытия текущего дня
      _dayOpenTime=tempDayOpenTime;
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Актуальное время открытия текущего дня = "+TimeToString(_dayOpenTime)+". Ошибка #",err);
         //Print( __FILE__,": Время открытия текущей недели через iTime = "+TimeToString( weekOpenTime2 )+". Ошибка #",err2 );
        }
      //--- Возвращаем истину
      return( true );
     }
//--- Время открытия дня ранее записано. Возвращаем истину
   return( true );
  }
//+------------------------------------------------------------------+
//| Проверяем, записано ли время открытия текущего часа              |
//+------------------------------------------------------------------+
bool CheckCurrentHourOpenTime()
  {
//--- Проверяем, записано ли время
   if(_hourOpenTime==0) // Если время не записано
     {
      //--- Получаем время открытия часового бара
      ResetLastError();
      const datetime tempHourOpenTime=(datetime)SeriesInfoInteger(_Symbol,PERIOD_H1,SERIES_LASTBAR_DATE);
      const int err=GetLastError();
      //const datetime hourOpenTime2 = iTime( _Symbol, PERIOD_H1, 0 );
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Время открытия текущего часа = "+TimeToString(tempHourOpenTime)+". Ошибка #",err);
         //Print( __FILE__,": Время открытия текущего часа iTime = "+TimeToString( hourOpenTime2 ) );
        }
      //--- Проверяем, получено ли время открытия часового бара
      if(tempHourOpenTime==0 || err!=0) // Если время бара не получено
         return(false);                                 // Возвращаем ложь
      //---
      _hourOpenTime=tempHourOpenTime;
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Актуальное время открытия текущего часа = "+TimeToString(_hourOpenTime)+". Ошибка #",err);
         //Print( __FILE__,": Время открытия текущего часа iTime = "+TimeToString( hourOpenTime2 ) );
        }
      //--- Возвращаем истину
      return( true );
     }
//--- Время открытия часа ранее записано. Возвращаем истину
   return( true );
  }

Результат: В результате, если терминал НЕ БЫЛ запущен несколько часов, например, был выключен на ночь, получаем вот такой вот результат при его первом (за день) запуске:

2018.09.21 11:11:27.306 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Актуальное время открытия текущего часа = 2018.09.20 16:00. Ошибка #0
2018.09.21 11:11:27.306 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Время открытия текущего часа = 2018.09.20 16:00. Ошибка #0
2018.09.21 11:11:27.280 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Время открытия текущего часа = 2018.09.20 16:00. Ошибка #4066
2018.09.21 11:11:27.279 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Актуальное время открытия текущего дня = 2018.09.20 00:00. Ошибка #0
2018.09.21 11:11:27.279 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Время открытия текущего дня = 2018.09.20 00:00. Ошибка #0
2018.09.21 11:11:27.265 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Время открытия текущего дня = 2018.09.20 00:00. Ошибка #4066
2018.09.21 11:11:27.264 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Актуальное время открытия текущей недели = 2018.09.17 00:00. Ошибка #0
2018.09.21 11:11:27.264 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Время открытия недельного бара = 2018.09.16 00:00. Ошибка #0
2018.09.21 11:11:27.233 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Время открытия недельного бара = 2018.09.16 00:00. Ошибка #4066
2018.09.21 11:11:27.066 test_isNewDayInTimer USDCHF.e,M1: initialized
2018.09.21 11:11:27.055 Custom indicator test_isNewDayInTimer USDCHF.e,M1: loaded successfully

Как видно, время получения данных 2018.09.21 11:11, и для этого времени мы получаем время открытия дня = 2018.09.20 (хотя должно быть 2018.09.21) и время открытия часа = 2018.09.20 16:00 (хотя должно быть 2018.09.21 11:00). Причем время, возвращенное терминалом, это не что иное как данные, на момент его закрытия в последний раз. Т.е. данные кешируются и возвращаются вне зависимости от того, что терминал был выключен. Причем я понимаю, если бы каждый раз возвращалась ошибка #4066 (запрошенные исторические данные в состоянии обновления) пока данные не будут обновлены, но нет, возвращаются именно ОШИБОЧНЫЕ данные! Эта ошибка возвращается только один раз, а далее - живите как хотите. На лицо явная ошибка кеширования. Прошу разработчиков (@Slava) обратить на нее внимание!

Повторюсь. Ошибочные данные появляются если запрашивать их в таймере!

Версия терминала: x64, 1090.

Vitaly Gorbunov
405
Vitaly Gorbunov  
Ну так ошибка 4066 типичная проблема для МТФ индюков, терминал не подкачал данные других ТФ необходима проверка на целостность данных других ТФ.
Alexey Kozitsyn
8946
Alexey Kozitsyn  
Vitaly Gorbunov:
Ну так ошибка 4066 типичная проблема для МТФ индюков, терминал не подкачал данные других ТФ необходима проверка на целостность данных других ТФ.

Посмотрите внимательнее на код и на то, что я написал прежде, чем давать советы.

В коде есть проверка на наличие ошибок и есть проверка на пустые данные. А когда функция возвращает некорректные данные без ошибки - это ошибка!

Vitaly Gorbunov
405
Vitaly Gorbunov  
Alexey Kozitsyn:

Посмотрите внимательнее на код и на то, что я написал прежде, чем давать советы.

В коде есть проверка на наличие ошибок и есть проверка на пустые данные. А когда функция возвращает некорректные данные без ошибки - это ошибка!

Возможно я что то упустил покажите где вы проверяете целостность истории например в процедуре CheckCurrentHourOpenTime()
Alexey Kozitsyn
8946
Alexey Kozitsyn  
Vitaly Gorbunov:
Возможно я что то упустил покажите где вы проверяете целостность истории например в процедуре CheckCurrentHourOpenTime()

Что Вы понимаете под целостностью истории?

Я говорю о том, что есть проверка на наличие ошибок при получении значений истории. Проверка есть в каждой функции. Вот она:

//--- Проверяем, получено ли время открытия часового бара
      if(tempHourOpenTime==0 || err!=0) // Если время бара не получено
         return(false);                                 // Возвращаем ложь

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

Суть в том, что функция SeriesInfoInteger() сначала возвращает ошибку, а на следующем запуске - НЕТ! Причем корректное значение она также не возвращает!
Vitaly Gorbunov
405
Vitaly Gorbunov  

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

Alexey Kozitsyn
8946
Alexey Kozitsyn  
Vitaly Gorbunov:

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

В смысле тут нет ошибки!? А зачем она тогда коды ошибок "левые" выдает. Говорит, что история в порядке там, где она не в порядке...

Vitaly Gorbunov
405
Vitaly Gorbunov  
Alexey Kozitsyn:

В смысле тут нет ошибки!? А зачем она тогда коды ошибок "левые" выдает. Говорит, что история в порядке там, где она не в порядке...

Ещё раз эта функция не проверяет целостность истории! Она возвращает информацию которую смогла в ней найти. В конкретном случае она нашла часовой бар который был запрошен в момент выключения терминала. Остальная история ещё не подгрузилась. 

Ihor Herasko
21742
Ihor Herasko  

Для проверки факта полной подкачки истории заданного ТФ достаточно использовать функцию:

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

Если функция возвращает false, то данные по запрошенному ТФ неполные. Иначе - полные.

Alexey Kozitsyn
8946
Alexey Kozitsyn  
Vitaly Gorbunov:

Ещё раз эта функция не проверяет целостность истории! Она возвращает информацию которую смогла в ней найти. В конкретном случае она нашла часовой бар который был запрошен в момент выключения терминала. Остальная история ещё не подгрузилась. 

Еще раз. Об этом нигде не сказано. Это во-первых. Во-вторых, зачем она вводит тогда в заблуждение сначала показывая код ошибки 4066, а потом - нет?

Alexey Kozitsyn
8946
Alexey Kozitsyn  
Ihor Herasko:

Для проверки факта полной подкачки истории заданного ТФ достаточно использовать функцию:

Если функция возвращает false, то данные по запрошенному ТФ неполные. Иначе - полные.

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

Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий