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

 
Igor Makanu:

3. интересен момент анализа, что возвращает CopyClose(), у себя проверял, если нет .hst файла по запрашиваемому ТФ, то CopyClose() больше 2048 никогда не возвращает - т.е. это максимальное значение которое можно скачать? 

Нет. 2048 - это порция данных, которая закачивается с сервера при отсутствии на клиенте.

 
вSlava:

Нет. 2048 - это порция данных, которая закачивается с сервера при отсутствии на клиенте.

хм, вроде и MQL давно занимаюсь, но все таки неожиданно это для меня

ОК, вот пример из справки: https://www.mql5.com/ru/docs/series/timeseries_access

указано, что:

Следующая важная проверка — проверка типа программы, из которой вызывается функция. Напомним, что отправка запроса на обновление таймсерии с тем же периодом, что и у индикатора, вызывающего обновление, крайне нежелательна. Нежелательность запроса данных по тому же символу-периоду, что и у индикатора обусловлена тем, что обновление исторических данных производится в том же потоке, в котором работает индикатор. Поэтому велика вероятность клинча. Для проверки используем функцию MQL5InfoInteger() с модификатором MQL5_PROGRAM_TYPE.

т.е. сам пример https://www.mql5.com/ru/code/449

не годится для подгрузки исторических данных в индикаторе МТ4, а как скачать индикатором всю историю, если нет подготовленного файла .hst, т.е. индикатор сам инициализировал закачку истории по символу

как я могу узнать, что вот "выкачал" всю историю равную iBars(Symbol(),PERIOD_CURRENT);

iBars() же тоже будет выдавать некорректное значение? - истории как бы еще нет, нет и коретнго iBars()

в МТ5 вроде без проблем качается история, нужно просто подождать и проверять состояние исторических данных, а в МТ4?

PS:  в кодобазе вчера искал корректно работающие мультивалютные индикаторы под МТ4, но коды не являются предметом подражания, во многих примерах кодобазы, вообще подкачка истории в индикаторе просто отсутствует

Документация по MQL5: Доступ к таймсериям и индикаторам / Организация доступа к данным
Документация по MQL5: Доступ к таймсериям и индикаторам / Организация доступа к данным
  • www.mql5.com
Прежде чем ценовые данные будут доступны в терминале MetaTrader 5, их необходимо получить и обработать. Для получения данных требуется подключение к торговому серверу MetaTrader 5. Данные поступают с сервера по запросу терминала в виде экономно упакованных блоков минутных баров. Механизм обращения к серверу за данными не зависит от того, каким...
 

В четвёрке "зажимали клавишу home". Другого способа нет. Если вы давно изучаете тему, то должны помнить фразу "кирпич на клавиатуре"

https://www.mql5.com/ru/code/9968

https://www.mql5.com/ru/code/9153

https://www.mql5.com/ru/code/9888

ZG_All_Quotings 3.2
ZG_All_Quotings 3.2
  • www.mql5.com
Скайп-чат поддержки продукта: Последние версии библиотек, скриптов и приложений: Сей скрипт продолжение темы закачек котировок обновлением графика. Решил не обновлять старую версию, а выложить заново. Это принципиально новый скрипт. Удалось добиться максимальной надёжности его работы за счёт переноса функций WinAPI в DLL. Скрипт, как и...
 
Igor Makanu:

Можете мой бесплатный загрузчик посмотреть.

 
Alexey Kozitsyn:

Можете мой бесплатный загрузчик посмотреть.

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

Slava:

В четвёрке "зажимали клавишу home". Другого способа нет. Если вы давно изучаете тему, то должны помнить фразу "кирпич на клавиатуре"

https://www.mql5.com/ru/code/9968

https://www.mql5.com/ru/code/9153

https://www.mql5.com/ru/code/9888

да, я знаю все эти коды, ранее пользовался, я несколько лет вообще не занимался MQL, с этого года восстанавливаю знания, очень удивило, что разработчики сделали максимальную совместимость между МТ5 и МТ4, сильно подняли производительность MQL4 - хотя ранее была информация, что МТ4 как проект больше не будет развиваться, будут только исправляться баги

и вот была надежда, что я не нашел информации об автоматической подгрузке истории в индикаторе МТ4

в принципе, если гарантированно хочется скачать всю историю в МТ4 и без дополнительных проверок, то проще код хренфикс использовать - записать в .hst файл бар datetime t=0;

 
Igor Makanu:

ну и как Вы мне предлагает посмотреть Ваш код?

Думал Вам просто нужно историю автоматом прогрузить...

 

К моему большому сожалению, вынужден еще раз вернуться к теме с получением данных старших ТФ в МТ4. На этот раз в связи с тем, что предложенные здесь методики оказались не рабочими.

Вот используемый код:

#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;
//--- Флаг работоспособности индикатора
bool _isWorking=true;
//--- Флаг соединения с торговым сервером (для таймера, получаем в OnCalculate())
bool _isConnected=false;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Сбрасываем время открытия текущего часа, дня и недели
   _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();
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Проверяем связь с сервером
   if(!IsConnected())                              // Если не удалось установить связь с сервером
     {
      //--- Сбрасываем флаг соединения с сервером
      _isConnected=false;
      //--- Выходим
      return( 0 );
     }
//--- Проверяем первый запуск индикатора
   if(prev_calculated<=0)
     {
      //--- Проверяем, записано ли время открытия текущей недели
      if(!CheckCurrentWeekOpenTime())                              // Если время не записано
         return(0);                                                // Выходим
      //--- Проверяем, записано ли время открытия текущего дня
      if(!CheckCurrentDayOpenTime())                              // Если время не записано
         return(0);                                                // Выходим
      //--- Проверяем, записано ли время открытия текущего часа
      if(!CheckCurrentHourOpenTime())                              // Если время не записано
         return(0);                                                // Выходим
      //--- Устанавливаем флаг соединения с сервером для запуска таймера
      _isConnected=true;
     }
//---
   return( rates_total );
  }
//+------------------------------------------------------------------+
//| Проверяем, записано ли время открытия текущей недели             |
//+------------------------------------------------------------------+
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 );
  }
//+------------------------------------------------------------------+

В нем реализована подкачка данных так, как мне советовали:

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

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

Slava, 2018.09.27 06:20

Многократно обсуждалось. 12 страниц на запрос "ошибка 4066"

И Вам правильно посоветовали в OnInit отправить запрос, а в OnCalculate анализировать.

Миллисекундный таймер зачем? Вы своими действиями мешаете клиентскому терминалу нормально подняться. Это не виндовые сообщения мешают вашему таймеру, а ваш таймер мешает всем. Ещё раз: ИНДИКАТОРЫ В КЛИЕНТСКОМ ТЕРМИНАЛЕ MT4 РАБОТАЮТ В ИНТЕРФЕЙСНОМ ПОТОКЕ.

Реализация именно такая: в OnInit() происходит первый запрос данных. Далее, ждем установление связи с торговым сервером, затем в OnCalculate()! получаем данные старших ТФ. Получаем результат на первом запуске сегодня:

2018.10.04 09:10:56.266 test_isNewDayInOnCalculate EURGBP.e,M1: OnTimer: Данные старших ТФ загружены!
2018.10.04 09:10:56.237 test_isNewDayInOnCalculate EURGBP.e,M1: test_isNewDayInOnCalculate.mq4: Актуальное время открытия текущего часа = 2018.10.03 09:00. Ошибка #0
2018.10.04 09:10:56.237 test_isNewDayInOnCalculate EURGBP.e,M1: test_isNewDayInOnCalculate.mq4: Время открытия текущего часа = 2018.10.03 09:00. Ошибка #0
2018.10.04 09:10:56.237 test_isNewDayInOnCalculate EURGBP.e,M1: test_isNewDayInOnCalculate.mq4: Актуальное время открытия текущего дня = 2018.10.03 00:00. Ошибка #0
2018.10.04 09:10:56.237 test_isNewDayInOnCalculate EURGBP.e,M1: test_isNewDayInOnCalculate.mq4: Время открытия текущего дня = 2018.10.03 00:00. Ошибка #0
2018.10.04 09:10:56.237 test_isNewDayInOnCalculate EURGBP.e,M1: test_isNewDayInOnCalculate.mq4: Актуальное время открытия текущей недели = 2018.10.01 00:00. Ошибка #0
2018.10.04 09:10:56.237 test_isNewDayInOnCalculate EURGBP.e,M1: test_isNewDayInOnCalculate.mq4: Время открытия недельного бара = 2018.09.30 00:00. Ошибка #0

Как видно из лога, получены ошибочные значения времени часа и времени дня.

Да, могут заметить разработчики (@Slava), я не применил все советы, что мне давались. Т.е. я все равно в OnInit() запускаю быстрый таймер, хотя мне советовали изначально запускать медленный. Однако, в данном случае, это сделано специально. Если быстрый таймер запускается в интерфейсном потоке и может затормозить получение данных остальных индикаторов - то это большая беда. Нигде в документации нет предупреждений об этом, в маркет спокойно можно выложить программу с частым таймером, которая может являться своеобразным "вирусом" и привести к "поломке" остальных программ.

В связи с вышеизложенным, считаю, что необходимо либо внести ограничения на работу миллисекундного таймера, либо в документации к EventSetMillisecondTimer() указать, что нельзя запускать функцию в OnInit(), чтобы терминал смог нормально подняться на старте.

 
Сегодня на открытии дня ситуация аналогичная, ошибка повторилась. Тестовый стенд: один график, на нем три индикатора. Два не используют таймер, третий - использует. Все получили некорректные данные при загрузке. Сейчас убрал с чарта индикатор, использующий таймер, посмотрю что получится.
 

А теперь самое интересное. Код без всяких таймеров:

#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;
//--- Флаг работоспособности индикатора
bool _isWorking=true;
//--- Флаг соединения с торговым сервером (для таймера, получаем в OnCalculate())
bool _isConnected=false;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Сбрасываем время открытия текущего часа, дня и недели
   _weekOpenTime= 0;
   _dayOpenTime = 0;
   _hourOpenTime= 0;
//--- Устанавливаем флаг работоспособности
   _isWorking=true;
//--- Сбрасываем флаг установки соединения
   _isConnected=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)
  {
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Проверяем связь с сервером
   if(!IsConnected())                              // Если не удалось установить связь с сервером
     {
      //--- Сбрасываем флаг соединения с сервером
      _isConnected=false;
      //--- Выходим
      return( 0 );
     }
//--- Проверяем первый запуск индикатора
   if(prev_calculated<=0)
     {
      //--- Проверяем, записано ли время открытия текущей недели
      if(!CheckCurrentWeekOpenTime())                              // Если время не записано
         return(0);                                                // Выходим
      //--- Проверяем, записано ли время открытия текущего дня
      if(!CheckCurrentDayOpenTime())                              // Если время не записано
         return(0);                                                // Выходим
      //--- Проверяем, записано ли время открытия текущего часа
      if(!CheckCurrentHourOpenTime())                              // Если время не записано
         return(0);                                                // Выходим
      //--- Устанавливаем флаг соединения с сервером для запуска таймера
      _isConnected=true;
      //---
      Print(__FUNCTION__,": Данные старших ТФ загружены!");
     }
//---
   return( rates_total );
  }
//+------------------------------------------------------------------+
//| Проверяем, записано ли время открытия текущей недели             |
//+------------------------------------------------------------------+
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 );
  }
//+------------------------------------------------------------------+

А нужный результат все равно не получить. Разработчики (@Slava) прокомментируйте пожалуйста. Невозможно получить корректные данные при загрузке терминала с нескольких старших ТФ. Обязательное условие, чтобы терминал был выключен более часа после выключения (т.к. получаем данные бара часа). И, конечно, запуск на ТФ меньше часа.

Таймер оказался не при делах.
 
Алексей вы запрос данных старших ТФ делаете в ините. Коннекта ещё нет скорее всего там вернуло ошибку. Попробуйте сделать запрос с приходом первого тика. 
Проверить не могу я на даче а планшетку с собой не взял. 
Причина обращения: