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

 
Taras Slobodyanik:

У вас индикатор не отслеживает обновление данных.
От брокера приходят новые бары, а вы их не проверяете.
Я добавил пару строк чтобы показать, что при проверке всё отображается верно.

Это рабочая ситуация - проверять новый бар.

Да Вы что! А с чего Вы взяли, что я обязательно должен отслеживать новые бары? Это в документации написано? В смысле, я ДОЛЖЕН получить значение функции, а потом обязательно сравнивать его с предыдущим? Есть функция, функция рассчитана на работу со старшими таймфреймами. Функция может возвращать ошибку, когда у нее нет данных или возвращать некорректное значение (равное 0 в данном случае). Все. Не должны программисты что-то городить для того, чтобы 100% получить корректное значение.

Зато смотрите, что я нашел в документации к SeriesInfoInteger():

Чтобы получить дополнительную информацию об ошибке, необходимо вызвать функцию GetLastError().

В моем коде GetLastError() видите? Вот проверка. Эта проверка должна быть необходимой и ДОСТАТОЧНОЙ! Все остальное - костыльные решения.
 
Alexey Kozitsyn:

А Вы посмотрите мой самый первый пост. Видите там ошибку 4066? Потом ошибку 0 и возврат некорректных данных. Почему же функция (в данном случае SeriesInfoInteger()) предварительно перед отправкой данных не делает проверку на актуальность? Почему она не взводит флаг ошибки? Понимаете, лучше подождать чуть дольше, пока проходят внутренние проверки, чем потом искать ошибки.

Зато после этого, мне было дано много советов, используя которые результат так и не был получен. А дело оказалось даже не в таймере.

ок, читаем справку)

SeriesInfoInteger

Возвращает информацию о состоянии исторических данных

Слово исторических что означает?
Если История загружена - ошибки нет.


Alexey Kozitsyn:

Да Вы что! А с чего Вы взяли, что я обязательно должен отслеживать новые бары? Это в документации написано? В смысле, я ДОЛЖЕН получить значение функции, а потом обязательно сравнивать его с предыдущим? Есть функция, функция рассчитана на работу со старшими таймфреймами. Функция может возвращать ошибку, когда у нее нет данных или возвращать некорректное значение (равное 0 в данном случае). Все. Не должны программисты что-то городить для того, чтобы 100% получить корректное значение.

Зато смотрите, что я нашел в документации к SeriesInfoInteger():

В моем коде GetLastError() видите? Вот проверка. Эта проверка должна быть необходимой и ДОСТАТОЧНОЙ! Все остальное - костыльные решения.

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


пс. сейчас выходные, рынок закрыт, у вас в терминале некорректные данные!
и нет ошибки!!!)

 
Taras Slobodyanik:

ок, читаем справку)

Слово исторических что означает?
Если История загружена - ошибки нет.


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

Каждый тик, пришедший в терминал - уже история. И я хочу получать актуальные ее значения или ошибку. Если Вас все устраивает - ок.

 
Alexey Kozitsyn:

Каждый тик, пришедший в терминал - уже история. И я хочу получать актуальные ее значения или ошибку. Если Вас все устраивает - ок.

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

 
Taras Slobodyanik:

Проверяйте не расчет баров, а время свечи.
Вот так будет правильно обновляться (проверил).

Тарас, вот результат Вашего кода:

2018.10.08 11:11:39.080 test_isNewDayInOnCalculate GBPUSD,M1: initialized
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: test_isNewDayInOnCalculate.mq4: Время открытия недельного бара = 2018.09.30 00:00. Ошибка #0
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: test_isNewDayInOnCalculate.mq4: Актуальное время открытия текущей недели = 2018.10.01 00:00. Ошибка #0
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: test_isNewDayInOnCalculate.mq4: Время открытия текущего дня = 2018.10.05 00:00. Ошибка #0
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: test_isNewDayInOnCalculate.mq4: Актуальное время открытия текущего дня = 2018.10.05 00:00. Ошибка #0
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: test_isNewDayInOnCalculate.mq4: Время открытия текущего часа = 2018.10.05 23:00. Ошибка #0
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: test_isNewDayInOnCalculate.mq4: Актуальное время открытия текущего часа = 2018.10.05 23:00. Ошибка #0
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: OnCalculate: Данные старших ТФ загружены!
 
Alexey Kozitsyn:

Тарас, вот результат Вашего кода:

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

пс. можете вставить свою функцию проверки нового бара, будет тоже самое.

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

 
Taras Slobodyanik:

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

пс. можете вставить свою функцию проверки нового бара, будет тоже самое.

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

А вот, кстати, еще аргумент, в пользу того, что происходит ошибка. Именно ОШИБКА при расчете в индикаторе! Написал советник:

#property version   "1.00"
#property strict
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//--- Время открытия текущего часа, дня и недели
datetime _weekOpenTime = 0;
datetime _hourOpenTime = 0;
datetime _dayOpenTime=0;
//--- Вести лог журнала
const bool inpFileLog=true;
//--- Количество секунд в одном дне
const int SEC_PER_DAY=86400;
//--- Флаг работоспособности индикатора
bool _isWorking=true;
//--- Флаг соединения с торговым сервером (для таймера, получаем в OnCalculate())
bool _isConnected=false;
//---
bool _firstLaunch = true;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- Устанавливаем флаг первого запуска
   _firstLaunch = true;
//--- Сбрасываем время открытия текущего часа, дня и недели
   _weekOpenTime= 0;
   _dayOpenTime = 0;
   _hourOpenTime= 0;
//--- Устанавливаем флаг работоспособности
   _isWorking=true;
//--- Сбрасываем флаг установки соединения
   _isConnected=false;
////--- Запускаем таймер
//   if(!EventSetMillisecondTimer(20))
//     {
//      Print(__FUNCTION__,": ОШИБКА #",GetLastError(),": таймер с частотой 20 не установлен!");
//      //--- Устанавливаем флаг неработоспособности индикатора
//      _isWorking=false;
//     }
//--- Запрос данных
   SeriesInfoInteger(_Symbol,PERIOD_W1,SERIES_LASTBAR_DATE);
   SeriesInfoInteger(_Symbol,PERIOD_D1,SERIES_LASTBAR_DATE);
   SeriesInfoInteger(_Symbol,PERIOD_H1,SERIES_LASTBAR_DATE);
//---
   return( INIT_SUCCEEDED );
  }
//+------------------------------------------------------------------+
//|                                                                   |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
////--- Выключаем таймер
//   EventKillTimer();
  }
////+------------------------------------------------------------------+
////|                                                                  |
////+------------------------------------------------------------------+
//void OnTimer()
//  {
////---
//   if(!_isWorking)
//      return;
////---
//   if(!_isConnected)
//      return;
////---
//   Print(__FUNCTION__,": Данные старших ТФ загружены!");
////--- Отключаем таймер
//   EventKillTimer();
//  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Проверяем связь с сервером
   if(!IsConnected())                              // Если не удалось установить связь с сервером
     {
      //--- Сбрасываем флаг соединения с сервером
      _isConnected=false;
      //--- Выходим
      return;
     }
        //--- Проверяем первый запуск эксперта
        if( _firstLaunch )
                {
            //--- Проверяем, записано ли время открытия текущей недели
            if(!CheckCurrentWeekOpenTime())                              // Если время не записано
              return;                                                // Выходим
            //--- Проверяем, записано ли время открытия текущего дня
            if(!CheckCurrentDayOpenTime())                              // Если время не записано
              return;                                                // Выходим
            //--- Проверяем, записано ли время открытия текущего часа
            if(!CheckCurrentHourOpenTime())                              // Если время не записано
              return;                                                // Выходим
            ////--- Устанавливаем флаг соединения с сервером для запуска таймера
            //_isConnected=true;
            //---
            Print(__FUNCTION__,": Данные старших ТФ загружены!");
            //--- Сбрасываем флаг первого запуска
            _firstLaunch = false;
                }
  }
//+------------------------------------------------------------------+
//| Проверяем, записано ли время открытия текущей недели             |
//+------------------------------------------------------------------+
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);
        }
      //--- Проверяем, получено ли время открытия недельного бара
      if(weekBarOpenTime==0 || err!=0) // Если время бара не получено или история обновляется
         return(false);                              // Возвращаем ложь
      //--- Запоминаем время открытия текущей недели (время открытия недельного бара - воскресенье)
      _weekOpenTime=weekBarOpenTime+SEC_PER_DAY;
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Актуальное время открытия текущей недели = "+TimeToString(_weekOpenTime)+". Ошибка #",err);
        }
      //--- Возвращаем истину
      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();
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Время открытия текущего дня = "+TimeToString(tempDayOpenTime)+". Ошибка #",err);
        }
      //--- Проверяем, получено ли время открытия дневного бара
      if(tempDayOpenTime==0 || err!=0) // Если время бара не получено
         return(false);                                 // Возвращаем ложь
      //--- Сохраняем в глобальную переменную значение открытия текущего дня
      _dayOpenTime=tempDayOpenTime;
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Актуальное время открытия текущего дня = "+TimeToString(_dayOpenTime)+". Ошибка #",err);
        }
      //--- Возвращаем истину
      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();
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Время открытия текущего часа = "+TimeToString(tempHourOpenTime)+". Ошибка #",err);
        }
      //--- Проверяем, получено ли время открытия часового бара
      if(tempHourOpenTime==0 || err!=0) // Если время бара не получено
         return(false);                                 // Возвращаем ложь
      //---
      _hourOpenTime=tempHourOpenTime;
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Актуальное время открытия текущего часа = "+TimeToString(_hourOpenTime)+". Ошибка #",err);
        }
      //--- Возвращаем истину
      return( true );
     }
//--- Время открытия часа ранее записано. Возвращаем истину
   return( true );
  }
//+------------------------------------------------------------------+

Запускается с того же графика, что и индикатор. Посмотрим результаты:

2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: OnTick: Данные старших ТФ загружены!
2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: test_isNewDayInOnTick.mq4: Актуальное время открытия текущего часа = 2018.10.09 06:00. Ошибка #0
2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: test_isNewDayInOnTick.mq4: Время открытия текущего часа = 2018.10.09 06:00. Ошибка #0
2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: test_isNewDayInOnTick.mq4: Актуальное время открытия текущего дня = 2018.10.09 00:00. Ошибка #0
2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: test_isNewDayInOnTick.mq4: Время открытия текущего дня = 2018.10.09 00:00. Ошибка #0
2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: test_isNewDayInOnTick.mq4: Актуальное время открытия текущей недели = 2018.10.08 00:00. Ошибка #0
2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: test_isNewDayInOnTick.mq4: Время открытия недельного бара = 2018.10.07 00:00. Ошибка #0
2018.10.09 08:45:41.479 test_isNewDayInOnTick GBPUSD,M1: initialized

2018.10.09 08:45:40.822	GBPUSD,M1: CheckCurrentHourOpenTime: Время открытия текущего часа = 2018.10.08 11:00
2018.10.09 08:45:40.822	GBPUSD,M1: CheckCurrentDayOpenTime: Время открытия текущего дня = 2018.10.08 00:00
2018.10.09 08:45:40.822	GBPUSD,M1: CheckCurrentWeekOpenTime: Время открытия текущей недели = 2018.10.08 00:00
2018.10.09 08:45:40.064	GBPUSD,M1: initialized

2018.10.09 08:45:40.022 Expert Other\test_isNewDayInOnTick GBPUSD,M1: loaded successfully

Что же мы видим. Видим, что все хорошо. Все прогрузилось, и заметьте, никаких ошибок, сразу актуальные данные! Главный ВОПРОС: дак почему в эксперте данные старших ТФ можно получить нормально, а в индикаторе нужно "плясать с бубном"? Разве не должны программы работать одинаково? Почему один и тот же код в индикаторе и эксперте работает по разному?! Не должно такого быть.

 
Alexey Kozitsyn:

А вот, кстати, еще аргумент, в пользу того, что происходит ошибка. Именно ОШИБКА при расчете в индикаторе! Написал советник:

Запускается с того же графика, что и индикатор. Посмотрим результаты:

Что же мы видим. Видим, что все хорошо. Все прогрузилось, и заметьте, никаких ошибок, сразу актуальные данные! Главный ВОПРОС: дак почему в эксперте данные старших ТФ можно получить нормально, а в индикаторе нужно "плясать с бубном"? Разве не должны программы работать одинаково? Почему один и тот же код в индикаторе и эксперте работает по разному?! Не должно такого быть.

Потому что это дело терминала соединяться и что то там делать с подгрузкой проверкой и т.д., все индикаторы находятся в одном потоке, и покуда все в потоке не закончится (фактически до следующего вызова OnСalculate) ничего нового не произойдет, т.е.  находясь в этом потоке, быстрее окончания потока, вы все равно ничего не получите. Эксперт находится в своем отдельном потоке, поэтому когда он запускается, ему позволено отложить свой запуск на время обновлений данных, обновлять данные - на все остальное в терминале это не влияет. Это с рождения так и никак уже не исправить, т.к. среду metatrader4 похоронили.

 
Unicornis:

Потому что это дело терминала соединяться и что то там делать с подгрузкой проверкой и т.д., все индикаторы находятся в одном потоке, и покуда все в потоке не закончится (фактически до следующего вызова OnСalculate) ничего нового не произойдет, т.е.  находясь в этом потоке, быстрее окончания потока, вы все равно ничего не получите. Эксперт находится в своем отдельном потоке, поэтому когда он запускается, ему позволено отложить свой запуск на время обновлений данных, обновлять данные - на все остальное в терминале это не влияет. Это с рождения так и никак уже не исправить, т.к. среду metatrader4 похоронили.

Да я в курсе, что все индикаторы одного символа находятся в одном потоке, а на каждый эксперт выделяется свой поток. Но это не дело. Разработчики - они на то и разработчики, чтобы исправлять ошибки в своих творениях. Программы не должны по разному работать! Если индикаторы что-то не успели - ошибка и нет проблем. Ведь эксперт как-то сразу получил корректные данные без ошибок! Значит можно реализовать. @Slava, можете высказаться по поводу, будет ли исправлено явно ошибочное поведение? Или, хотя бы, дополнение документации (что при prev_calculated = 0 корректных данных старших ТФ не получить)?

 
Alexey Kozitsyn:

Да я в курсе, что все индикаторы одного символа находятся в одном потоке, а на каждый эксперт выделяется свой поток. Но это не дело. Разработчики - они на то и разработчики, чтобы исправлять ошибки в своих творениях. Программы не должны по разному работать! Если индикаторы что-то не успели - ошибка и нет проблем. Ведь эксперт как-то сразу получил корректные данные без ошибок! Значит можно реализовать. @Slava, можете высказаться по поводу, будет ли исправлено явно ошибочное поведение? Или, хотя бы, дополнение документации (что при prev_calculated = 0 корректных данных старших ТФ не получить)?

В документации где то было что эксперту дается целых 5 секунд перед запуском чтобы получить данные, а в это время терминал пытается выкачать данные для эксперта. Индикатору это не дано, так же индикатору не положено запрашивать обновление истории, для него это не критично, если критично - значит считайте в эксперте. Главная мысль, что в текущей реализации не возможно желаемое положение вещей. По существу, ТФ-ы это таймеры и есть периоды где эти кратные таймеры совпадают в один момент - это 100% совпадающий по времени синхронный процесс(кроме времени открытия/закрытия), т.к. первый тик минуты текущего тф совпадающей с первой минутой пятиминутки, часа и т.д. - это просто запись в несколько переменных одного и того же значения , и логично что в этих моментах можно задать набор нужных ТФ и получать все необходимые данные сразу. Почему разработчики сделали так, а не иначе, хз, возможно из-за разделения клиент-сервер это невозможно было(будет) сделать в существующей модели работы терминала, т.к. если сейчас дать возможность индикаторам возможности экспертов, то они завесят терминал. 

Можно посмотреть в конце дня, кому интересно, как работает вызов индикатора, индикатор вызывает другой индикатор, эксперт(_asktfexp) вызывает индикатор(_asktf_sample) вызывающий индикатор(_asktf). При вызове индикатора из эксперта, таймер в индикаторе не запустится, поэтому решения с таймером в индикаторе это только для случаев, когда этот индикатор только будет висеть на графике и не будет вызываться (что в общем логично).

Файлы: