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

 
Vitaly Gorbunov:
Приём с iBarShift позволяет выявить дыры в истории, но для этого необходимо шерстить её с каким то интервалом. Я написал для себя процедуру которая этим занимается, после этого я забыл про пропуски в МТФ программах.
Речь тут вроде не шла о выявлении "дыр".  Человеку требовалось получить последний бар в истории.  А это совсем необязательно текущий бар по времени.
 
Vitaly Gorbunov:
Данные грузятся ошибка 4066 потом уже косяк метаквотовцев скорее всего полученные данные обрабатываются для этой ситуации ошибку не придумали. А до этого момента всё логично.

Если ошибку "не придумали" это не значит, что ее нет. 

 
Alexey Navoykov:
Речь тут вроде не шла о выявлении "дыр".  Человеку требовалось получить последний бар в истории.  А это совсем необязательно текущий бар по времени.

Дело не в iBarShift(). Он ведь такие же ошибки шлет, что и iTime(), что и SeriesInfoInteger(). Костыль тут в сравнении времени, полученного при инициализации и последующем сравнении его с временем из таймера. Именно это позволило при загрузке терминала получить корректные актуальные данные, а не IBarShift().

Да, и если время 15:00:45 (например), а тика по бару 15:00 еще нет и если будет получено время открытия последнего часового бара 14:00 - все корректно, я считаю. А вот если система вернет 13:00 - вот тут уже беда.

 
Alexey Kozitsyn:

1. Игорь, Вы код смотрели? Где я что-то получаю в OnInit()?

В Вашем случае один или несколько вызовов OnTimer выполняются сразу после OnInit(). События OnCalculate() еще не было. 

2. Какие проверки? Где написано, что индикатор обязательно должен хотя бы один раз использовать OnCalculate() для корректной работы? 

Здесь требуется понимание логики работы терминала. OnInit() вызывается сразу при подключении индикатора к графику. При запуске терминала подключение индикатора к графику происходит сразу после создания окна графика. В этот момент терминал еще даже запрос на сервер не послал.

Первый OnCalculate() вызывается после считывания локально имеющихся котировок. В каких-то редких случаях бывает так, что локально ничего нет. Тогда индикаторы, обращаясь к Time[0], вылетают по ошибке выхода за пределы массива. Поэтому лучше использовать функции iTime и подобные ей.

Второй и последующие OnCalculate() происходят при подкачке истории или при реальном приходе тиков.

 
Ihor Herasko:

Первый OnCalculate() вызывается после считывания локально имеющихся котировок. В каких-то редких случаях бывает так, что локально ничего нет. Тогда индикаторы, обращаясь к Time[0], вылетают по ошибке выхода за пределы массива. Поэтому лучше использовать функции iTime и подобные ей.

наверное речь идет все таки о MQL5, там подготовка OHLC идет не так как в МТ4

я давно пишу индикаторы по шаблону:

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[])
  {
//---
   int i,limit;
   if(prev_calculated==0)
     {
      limit=rates_total-1;    //--- Первый вызов индикатора или смена таймфрейма или подгрузка данных из истории
     }
   else limit=rates_total-prev_calculated+1;
   for(i=limit;i>=0;i--)      //---- Основной цикл расчета
     {                        
     }
   return(rates_total);
  }

ни разу не было "вылета индикатора" по выходу за пределы массивов OHLC в МТ4, думаю, что МТ4 не запустит в первый раз OnCalculate() пока не будет подготовлен график, а если будет подгрузка истории, то сколько не проверял, но prev_calculated==0 , в МТ5 будет как Вы писали - нужно дополнительные проверки, что данные OHLC уже готовы

 
Ihor Herasko:

В Вашем случае один или несколько вызовов OnTimer выполняются сразу после OnInit(). События OnCalculate() еще не было. 

Здесь требуется понимание логики работы терминала. OnInit() вызывается сразу при подключении индикатора к графику. При запуске терминала подключение индикатора к графику происходит сразу после создания окна графика. В этот момент терминал еще даже запрос на сервер не послал.

Первый OnCalculate() вызывается после считывания локально имеющихся котировок. В каких-то редких случаях бывает так, что локально ничего нет. Тогда индикаторы, обращаясь к Time[0], вылетают по ошибке выхода за пределы массива. Поэтому лучше использовать функции iTime и подобные ей.

Второй и последующие OnCalculate() происходят при подкачке истории или при реальном приходе тиков.

Что Вы предлагаете для решения проблемы (есть ли она, по Вашему)? Ждать пока будет 1-2 раза вызван OnCalculate()?

 
Alexey Kozitsyn:

Что Вы предлагаете для решения проблемы (есть ли она, по Вашему)? Ждать пока будет 1-2 раза вызван OnCalculate()?

можно попробовать значение  prev_calculated==0 скопировать в переменную на глобальный уровень видимости и в OnTimer() видеть, был ли рассчитан индикатор, я вот выше писал, что ни разу в МТ4 не видел багов с некорректным расчетом OnCalculate() - он в любом случае будет рассчитан, подозреваю, что если не были готовы данные ТФ, то в return(rates_total) вернется 0, что будет в следующем вызове OnCalculate() признаком prev_calculated==0, примерно так:

void OnTimer(){
   if(Global_prev_calculated==0)return;
}
 
Igor Makanu:

можно попробовать значение  prev_calculated==0 скопировать в переменную на глобальный уровень видимости и в OnTimer() видеть, был ли рассчитан индикатор, я вот выше писал, что ни разу в МТ4 не видел багов с некорректным расчетом OnCalculate() - он в любом случае будет рассчитан, подозреваю, что если не были готовы данные ТФ, то в return(rates_total) вернется 0, что будет в следующем вызове OnCalculate() признаком prev_calculated==0

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

2018.09.21 23:45:27.128 test_isNewDayInOnCalculate_iBarShift() EURGBP.e,M1: test_isNewDayInOnCalculate_iBarShift().mq4: Актуальное время открытия бара М15 = 2018.09.21 21:30. Ошибка #0
2018.09.21 23:45:25.990 test_isNewDayInOnCalculate_iBarShift() EURGBP.e,M1: initialized
2018.09.21 23:45:25.975 Custom indicator test_isNewDayInOnCalculate_iBarShift() EURGBP.e,M1: loaded successfully

Однако, это не снимает всех вопросов:

1. Почему в документации к IsConnected() не написано, что она должна быть обязательно вызвана перед получением данных (как минимум) старшего ТФ в OnCalculate()?

2. Почему IsConnected() в OnTimer(), по сути, не работает? Ведь разве факт установления соединения с торговым сервером не должен нам говорить о том, что можно получить данные?

3. Раз мы установили соединение с торговым сервером и пытаемся получить данные в OnTimer(), разве не должны функции iTime(), iBarShift(), SeriesInfoInteger() и подобные им функции возвращать ошибки, если данные с этим самым торговым сервером, с которого они берут информацию еще не синхронизированы? А то получается ерунда какая-то, типа один раз мы тебе вернем ошибку 4066, а потом живи как хочешь с теми данными, что есть.

 
Alexey Kozitsyn:

Однако, это не снимает всех вопросов:

1. Почему в документации к IsConnected() не написано, что она должна быть обязательно вызвана перед получением данных (как минимум) старшего ТФ в OnCalculate()?

2. Почему IsConnected() в OnTimer(), по сути, не работает? Ведь разве факт установления соединения с торговым сервером не должен нам говорить о том, что можно получить данные?

3. Раз мы установили соединение с торговым сервером и пытаемся получить данные в OnTimer(), разве не должны функции iTime(), iBarShift(), SeriesInfoInteger() и подобные им функции возвращать ошибки, если данные с этим самым торговым сервером, с которого они берут информацию еще не синхронизированы? А то получается ерунда какая-то, типа один раз мы тебе вернем ошибку 4066, а потом живи как хочешь с теми данными, что есть.

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

2,3. работает, но Вы забываете что GetLastError() после вызова сбросит свое состояние, и возможно, что чтобы обновить  состояние GetLastError() нужно передать управление терминалу, возможно терминал не успевает повторно выставить состояние IsConnected() в GetLastError() перед Вашим вызовом из таймера.... думаю сама ф-ция OnTimer() не предназначена для получения данных: "Справочник MQL4 / Проверка состояния" - OnTimer()  то будет вызван, а вот переменные окружения терминала не факт, что обновлены, а вот в  OnCalculate() там гарантированно по приходу тика все данные терминал подготовит

 
Igor Makanu:

1. ну случай вызова индикатора на исторических данных никто не отменял...

2,3. работает, но Вы забываете что GetLastError() после вызова сбросит свое состояние, и возможно, что чтобы обновить  состояние GetLastError() нужно передать управление терминалу, возможно терминал не успевает повторно выставить состояние IsConnected() в GetLastError() перед Вашим вызовом из таймера.... думаю сама ф-ция OnTimer() не предназначена для получения данных: "Справочник MQL4 / Проверка состояния" - OnTimer()  то будет вызван, а вот переменные окружения терминала не факт, что обновлены, а вот в  OnCalculate() там гарантированно по приходу тика все данные терминал подготовит

1. Вы считаете, что если бар под номером 0 имеет некорректное время, остальная история будет иметь корректное?:)

2,3. Если функциям доступа к данным не хватает времени на установку какой-то осмысленной ошибки - пусть сообщит об этом как-то, но уж точно не вернув код ошибки = 0 (ошибки нет). Остальное "возможно" - лишь догадки. И без доказательств тут говорить не о чем.

ф-ция OnTimer() не предназначена для получения данных...

без комментариев.

OnTimer()  то будет вызван, а вот переменные окружения терминала не факт, что обновлены

а ошибка 4066 нам на что?
Причина обращения: