Аналог iBarShift - страница 12

 
Nikolai Semko :

Вы же говорили что все должно работать как в MQL4 .

Но этот скрипт можно запустить на MQL5 тоже

При exact=True  и будущем времени возвращать нужно -1

И еще мой скрипт нашел у вас странную ошибку:

Эта ошибка подтверждается этой проверкой:

Значит я все же был прав про с уществование нештатных ситуаций в вашем алгоритме .

Приятно, что вы наконец нашли ошибку

Я проверю, спасибо.

 

Всем добрый вечер. Возможно я чего-то недопонимаю, и все же - не совсем понятно, чем не устраивает стандартная функция, которая уже предлагалась в начале Bars(). Все время ею пользуюсь и никаких проблем. Единственное, можно столкнуться  в последующем с "array out of range" или отрицательным значением в случае использования TimeCurrent(), но тогда нужно сделать проверку соответствующую. Примеры:

//найти бар на котором продали
Bar_sell_H4=Bars(Symbol(),PERIOD_H4,P_opentime,32000000000)-1;
if(Bar_sell_H4<=0)
   {
      Bar_time_sell_H4=Time_H4[0];
   }
else
   {
      Bar_time_sell_H4=Time_H4[Bar_sell_H4];
   }
Bars_forsearch_highfr_H1=Bars(Symbol(),PERIOD_H1,TimeCurrent(),Time_M15[B_DownTrend_M15_int]);
if(Bars_forsearch_highfr_H1<=0)
   {
      high_H1_int=0;
   }
else
   {
      high_H1_int=ArrayMaximum(High_H1,0,Bars_forsearch_highfr_H1);
   }
 
Almat Kaldybay:

Всем добрый вечер. Возможно я чего-то недопонимаю, и все же - не совсем понятно, чем не устраивает стандартная функция, которая уже предлагалась в начале Bars(). Все время ею пользуюсь и никаких проблем. Единственное, можно столкнуться  в последующем с "array out of range" или отрицательным значением в случае использования TimeCurrent(), но тогда нужно сделать проверку соответствующую. Примеры:

Судя по цифре 32000000000 это тоже моё творение. UINT_MAX просто короче и солиднее выглядит. ))

Дело в том, что такой вариант правильнее, как выяснилось:

Bars(Symb,TimeFrame,time+1,UINT_MAX);

а не 

Bars(Symb,TimeFrame,time,UINT_MAX)-1;

внешней разницы почти нет. Но зато верхний вариант очень точно повторяет штатную функцию  iBarShift из MQL4

 
Nikolai Semko:

Судя по цифре 32000000000 это тоже моё творение. UINT_MAX просто короче и солиднее выглядит. ))

Дело в том, что такой вариант правильнее, как выяснилось:

а не 

внешней разницы почти нет. Но зато верхний вариант очень точно повторяет штатную функцию  iBarShift из MQL4

Так на чём остановились, что самое лёгкое, и правильное?

 
Vitaly Muzichenko:

Так на чём остановились, что самое лёгкое, и правильное?

Пока этот вариант, но я сейчас хочу его дополнить, чтобы он обходил этот баг подвисания функции Bars, по поводу которого я уже отписался в сервисдеск. 

Суть этого бага в том, что если в функции Bars  оба времени start_time и stop_time  находятся внутри одного бара или находятся в будущем (правее нулевого бара), то эта функция подвисает на более чем 10 секунд.

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

 

Я решил пойти по другому пути. 
Я не буду переделывать iBarShift, а переделаю глючную функцию Bars.

Причем  новая функция iBars будет не только обходить баг подвисания, но и будет работать быстрее оригинала Bars.

Этой функцией смогут пользоваться другие и уже имеющиеся алгоритмы будут работать быстрее.

Мне нужно только время. Смогу этим заняться не раньше чем через день.

 
Nikolai Semko:

Я решил пойти по другому пути. 
Я не буду переделывать iBarShift, а переделаю глючную функцию Bars.

Причем  новая функция iBars будет не только обходить баг подвисания, но и будет работать быстрее оригинала Bars.

Этой функцией смогут пользоваться другие и уже имеющиеся алгоритмы будут работать быстрее.

Мне нужно только время. Смогу этим заняться не раньше чем через день.

Очень хорошо! Жду с нетерпением!

 
Nikolai Semko:

Из всего анализа, который я сделал, напрашивается вывод, что вот этот полный аналог функции iBarShift:

int iBarShift(const string Symb,const ENUM_TIMEFRAMES TimeFrame,datetime time,bool exact=false)
  {
   int Res=Bars(Symb,TimeFrame,time+1,UINT_MAX);
   if(exact) if((TimeFrame!=PERIOD_MN1 || time>TimeCurrent()) && Res==Bars(Symb,TimeFrame,time-PeriodSeconds(TimeFrame)+1,UINT_MAX)) return(-1);
   return(Res);
  }

на сегодняшний день является самым корректным, и при этом самый быстрым и с самым простым и коротким алгоритмом.

красиво, но что-то смущает...

надо будет протестить )

 

функция iBars хоть и получилась весьма громоздкой, но всё равно я рекомендую её использовать вместо штатного Bars, пока MQ не исправят в нем баг с зависанием. 

Зависает iBar, когда по логике он должен возвращать 0. Возвращает он его как правило более 10 секунд. В MQL4 этого бага нет.

В большинстве задач iBars будет работать быстрее чем штатный Bars, потому как она не только обходит баг, но и старается не  использовать по возможности функции Bars и SeriesInfoInteger благодаря алгоритму сохранения предыдущих значений.

int iBars(string symbol_name,ENUM_TIMEFRAMES  timeframe,datetime start_time,datetime stop_time) // stop_time > start_time
  {
   static string LastSymb=NULL;
   static ENUM_TIMEFRAMES LastTimeFrame=0;
   static datetime LastTime=0;
   static datetime LastTime0=0;
   static int PerSec=0;
   static int PreBars=0;
   static datetime LastBAR=0;
   static datetime LastTimeCur=0;
   datetime TimeCur;
   if(stop_time<start_time) {TimeCur=stop_time; stop_time=start_time; start_time=TimeCur; }
   TimeCur=TimeCurrent();
   if(start_time>TimeCur) {LastSymb=NULL; return(0);}
   if(LastTimeFrame!=timeframe) if(timeframe==PERIOD_MN1) PerSec =2419200; else PerSec=::PeriodSeconds(timeframe);
   if(LastTimeFrame!=timeframe || LastSymb!=symbol_name || ((TimeCur-LastBAR)>=PerSec && TimeCur!=LastTimeCur))
      LastBAR=(datetime)SeriesInfoInteger(symbol_name,timeframe,SERIES_LASTBAR_DATE);

   LastTimeCur=TimeCur;
   if(PerSec==0) return(0);
   if(start_time>LastBAR)
     {LastTimeFrame=timeframe; LastSymb=symbol_name; return(0);}

   datetime t,t0=0;
   bool check=true;
   if(timeframe<PERIOD_W1) t=start_time-(start_time-1)%PerSec;
   else if(timeframe==PERIOD_W1) t=start_time-(start_time-259201)%PerSec;
   else
     {
      PerSec=2678400;
      MqlDateTime dt;
      TimeToStruct(start_time-1,dt);
      t=dt.year*12+dt.mon;
     }
   if(stop_time<=LastBAR)
     {
      if(timeframe<PERIOD_W1) t0=stop_time-(stop_time)%PerSec;
      else if(timeframe==PERIOD_W1) t0=stop_time-(stop_time-259200)%PerSec;
      else
        {
         MqlDateTime dt0;
         TimeToStruct(stop_time,dt0);
         t0=dt0.year*12+dt0.mon;
        }
      if(t0==t) {PreBars=0; check=false;}
     }
   if((LastTimeFrame!=timeframe || LastSymb!=symbol_name || t!=LastTime || t0!=LastTime0) && check)
      PreBars=Bars(symbol_name,timeframe,start_time,stop_time);
   LastTime=t; LastTime0=t0;
   LastTimeFrame=timeframe;
   LastSymb=symbol_name;
   return(PreBars);
  }

Тестировал эту функцию и вдоль и поперек. Вроде бы полностью повторяет Bars.

Возможно можно сделать более изящно. У кого есть желание - милости просим. Найдете ошибки - будем исправлять.

Итак...

Тогда полный аналог функции iBarsShift будет иметь вид:

int iBarShift(const string Symb,const ENUM_TIMEFRAMES TimeFrame,datetime time,bool exact=false)
  {
   int Res=iBars(Symb,TimeFrame,time+1,UINT_MAX);
   if(exact) if((TimeFrame!=PERIOD_MN1 || time>TimeCurrent()) && Res==iBars(Symb,TimeFrame,time-PeriodSeconds(TimeFrame)+1,UINT_MAX)) return(-1);
   return(Res);
  }

А вариант без последнего параметра exact, что используется в подавляющем большинстве случаев будет иметь такой вид:

int iBarShift1(const string Symb,const ENUM_TIMEFRAMES TimeFrame,datetime time,bool exact=false)
  {
   return(iBars(Symb,TimeFrame,time+1,UINT_MAX));
  }
// ИЛИ БОЛЕЕ СОКРАЩЕННЫЙ БЕЗ ФУНКЦИИ:

iBars(Symb,TimeFrame,time+1,UINT_MAX);
 

Индикатор, демонстрирующий быстродействия функции iBars в сравнении с встроенной Bars и функцией iBarShift от @Alain Verleyen
Время выполнения функции в микросекундах.


Файлы:
Причина обращения: