Скачать MetaTrader 5
Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий
Есть свободные компьютеры? Подключи их к MQL5 Cloud Network и заработай!
ivan
505
ivan 2014.07.07 16:05 

Я вижу, что иногда, в короткое время после смены таймфрейма, Time[0] меняется. Причём 100% до появления нового нулевого бара (например, переключаем на 15-минутки. до наступления нового 15-минутного бара еще далеко). То есть, при смене таймфрейма, история, соответствующая новому периоду, подгружается или пересчитывается, причем таким образом, что Time[0] не является временем открытия текущего бара, а просто является первым элементом массива. И только спустя непродолжительное время Time[0] "стабилизируется" и  становится настоящим временем открытия текущего бара. Это очень неудобно, например, если программа хочет засечь бар, на котором она начала работать на новом таймфрейме - как его засекать-то, если начальные значения времени неадекватны? Кто-нибудь сталкивался с подобным? Код не выкладываю, т.к., во-первых, он элементарен, а во-вторых, проблема возникает спорадически, видимо, в зависимости от подгрузки истории при переключении таймфрейма. 

Если описанная проблема полностью исключена по построению mt4, буду признателен, если это подтвердит кто-то из модераторов.

 

Vitalie Postolache
10993
Vitalie Postolache 2014.07.07 18:45  
iTime(NULL,timeframe,0) будет правильней, если не хочется таких выкрутасов, всегда показывает время открытия свечи именно того ТФ, который нужен, неважно на какой ТФ перескочил график.
ivan
505
ivan 2014.07.08 08:48  

Спасибо, но это тоже не работает: смотрите, прилагаю простейший код - индикатор - он делает 2 вещи:

1. Записывает время первого тика time0 (в момент инициализации индикатора на любом таймфрейме)

2. Вычисляет и отображает  комментарием сдвиг найденного времени TheShift=iBarShift(NULL,0,time0,false); опция false означает, насколько я понимаю, что будет найден бар, время начала которого наиболее близко к time0. 

В норме, при переключении на новый таймфрейм должно быть TheShift=0 или 1 и только спустя много времени TheShift=2,3 и т.д. когда начнут приходить новые бары. Но я вижу, что TheShift может скакнуть и на 25 и на 88, и т.д. 

Такая вот .. вещь.

 

//+------------------------------------------------------------------+
//|                                          TimeFrameSwitchTest.mq4 |
//|                                                          qomment |
//|                             https://www.mql5.com/ru/users/qomment |
//+------------------------------------------------------------------+
#property copyright "qomment"
#property link      "https://www.mql5.com/ru/users/qomment"
#property version   "1.00"
#property strict
#property indicator_chart_window

int OnCalculateCounter=0; // считаем тики
datetime time0; // время первого тика
bool time0switch=0; // переключатель
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   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[])
  {
  
  if(!time0switch)
  {
  ResetLastError();
  time0=iTime(NULL,0,0);
  if(!GetLastError())
  time0switch=1;  
  }
  
  if(time0switch)
  {
  int TheShift=iBarShift(NULL,0,time0,false);
  if(TheShift!=-1)
  Comment("TimeFrame=",Period()," OnCalculateCounter=",OnCalculateCounter," TheShift=",TheShift);
  }

  OnCalculateCounter++;
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {

  }
//+------------------------------------------------------------------+
keekkenen
1128
keekkenen 2014.07.08 10:40  

TheShift всегда будет 0, потому что в time0 будет всегда (в момент вычисления TheShift) время текущего бара

 iBarShift будет возвращать 0, т.к. бар со временем time0 всегда будет находиться и это 0-й бар

Ihor Herasko
8424
Ihor Herasko 2014.07.08 10:58  
qomment:

1. Записывает время первого тика time0 (в момент инициализации индикатора на любом таймфрейме) 

Нужно брать не любой таймфрейм, а один конкретный, т. е. в iTime должен быть не 0 на месте таймфрейма, а константное значение, используемое при работе индикатора на любом таймфрейме.
ivan
505
ivan 2014.07.08 10:59  
keekkenen:

TheShift всегда будет 0, потому что в time0 будет всегда (в момент вычисления TheShift) время текущего бара

 iBarShift будет возвращать 0, т.к. бар со временем time0 всегда будет находиться и это 0-й бар


Нет. В том то и дело. Попробуйте код и убедитесь. Только проблема будет возникать не всегда, скажем в 5% случаев, так что надо активно попереключать фреймы и т.д. 
ivan
505
ivan 2014.07.08 11:01  
Scriptong:
Нужно брать не любой таймфрейм, а один конкретный, т. е. в iTime должен быть не 0 на месте таймфрейма, а константное значение, используемое при работе индикатора на любом таймфрейме.


А что, при вызове iBarShift(NULL,0,time0,false) он не в конкретном таймфрейме считает??? посмотрите код.
Ihor Herasko
8424
Ihor Herasko 2014.07.08 11:20  
qomment:

А что, при вызове iBarShift(NULL,0,time0,false) он не в конкретном таймфрейме считает??? посмотрите код.


В своем сообщении я не упоминал iBarShift. Речь шла о функции iTime. В приведенном коде этой функции передается 0 - текущий таймфрейм. Именно в этом и проблема - нужно использовать заранее определенный таймфрейм. Причем получить значение нужно именно после подкачки данных. Проверяется это так:

input ENUM_TIMEFRAMES i_tf = PERIOD_H1;


datetime time;
int error = ERR_HISTORY_WILL_UPDATED;
while (error == ERR_HISTORY_WILL_UPDATED)
{
   time = iTime(NULL, i_tf, 0);
   error = GetLastError();
   Sleep(1000);
}
ivan
505
ivan 2014.07.08 12:24  
Scriptong:


В своем сообщении я не упоминал iBarShift. Речь шла о функции iTime. В приведенном коде этой функции передается 0 - текущий таймфрейм. Именно в этом и проблема - нужно использовать заранее определенный таймфрейм. Причем получить значение нужно именно после подкачки данных. Проверяется это так:

 


Большое спасибо. Насчёт iBarShift - моя неточность в ответе, я имел ввиду iTime конечно. Посмотрю Ваш вариант проверки подкачки. Правда Sleep в индикаторах не работает - надо как-то по-другому будет проверять. Кроме того, кажется, Вы согласны, что во время подкачки могут быть ошибки, то есть даже iTime(NULL, i_tf,0) может скакать? Именно в этом был мой вопрос. Получается, в любой кастомный индикатор имеет смысл вставлять такую процедуру - проверку подкачки данных при переключении таймфрейма. 

Ihor Herasko
8424
Ihor Herasko 2014.07.08 12:47  
qomment:


Большое спасибо. Насчёт iBarShift - моя неточность в ответе, я имел ввиду iTime конечно. Посмотрю Ваш вариант проверки подкачки. Правда Sleep в индикаторах не работает - надо как-то по-другому будет проверять. Кроме того, кажется, Вы согласны, что во время подкачки могут быть ошибки, то есть даже iTime(NULL, i_tf,0) может скакать? Именно в этом был мой вопрос. Получается, в любой кастомный индикатор имеет смысл вставлять такую процедуру - проверку подкачки данных при переключении таймфрейма. 

 


Факт подкачки данных никем не оспаривался - в МТ4 история по таймфреймам закачивается асинхронно. Это в МТ5 все строится на минутных данных. Было предложено несколько вариантов решения проблемы. 

В индикаторе функция Sleep, да, не поможет. Там приходится разделять приведенную функцию на две части: 

int OnInit()
{
   ...
   iTime(NULL, i_tf, 0);                              // Запуск процесса обновления нужного таймфрейма
   ...
}

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[])
{
   datetime time = iTime(NULL, i_tf, 0);
   if (GetLastError() == ERR_HISTORY_WILL_UPDATED)                    // Расчет значений индикатора не запускает до тех пор, пока не будет окончен процесс подкачки истории
      return prev_calculated;
   ...
   return rates_total;
}
ivan
505
ivan 2014.07.08 14:38  
Scriptong:


Факт подкачки данных никем не оспаривался - в МТ4 история по таймфреймам закачивается асинхронно. Это в МТ5 все строится на минутных данных. Было предложено несколько вариантов решения проблемы. 

В индикаторе функция Sleep, да, не поможет. Там приходится разделять приведенную функцию на две части: 

 

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

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

Еще вопрос и заранее еще большее спасибо - в чём разница между iTime(NULL,0,0) и iTime(NULL, i_tf,0) если i_tf соответствует текущему таймфрейму? По идее никакой (если верить официальному хелпу). Кроме того, если определять  i_tf руками, то пропадает смысл переключения таймфремов в терминале - программа просто будет работать на текущем таймфрейме и всё. 

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