iBarShift() for MT5 is klunky

 

iBarShift() sometimes works, sometimes does not.

  • By "works" I mean that it returns a bar number given a specific time for historical data that I know exists on the machine.
  • By "not works" I mean that it returns -1 even though historical data exists.

I created a test script (attached). It assumes that all CADJPY D1 historical data is already on your machine.

iBarShift() sometimes returns a bar value (not -1) within 100 attempts, sometimes it does not. It almost never returns a value (not -1) on the first call.

In my investigation of this issue, I came across iBarShift - library for MetaTrader 5 by Alain. I've copied his function to the bottom of my test script (with copyright intact), but renamed it to iBarShiftAlain(). In my tests, Alain's function works every time.

So . . . there is something not quite right under the hood of MT5's iBarShift(). I'll be using Alain's version henceforth.

Files:
Test.mq5  5 kb
 
Anthony Garot: iBarShift() sometimes works, sometimes does not.
  • By "works" I mean that it returns a bar number given a specific time for historical data that I know exists on the machine.
  • By "not works" I mean that it returns -1 even though historical data exists.

I created a test script (attached). It assumes that all CADJPY D1 historical data is already on your machine.

iBarShift() sometimes returns a bar value (not -1) within 100 attempts, sometimes it does not. It almost never returns a value (not -1) on the first call.

In my investigation of this issue, I came across iBarShift - library for MetaTrader 5 by Alain. I've copied his function to the bottom of my test script (with copyright intact), but renamed it to iBarShiftAlain(). In my tests, Alain's function works every time.

So . . . there is something not quite right under the hood of MT5's iBarShift(). I'll be using Alain's version henceforth.

Totally "normal" expected behaviour from MetaQuotes software! I would be more surprised when their software worked without any bugs!

By the way, I am assuming you are using the stable 1881 build and not any of the latest bungled (oops, I mean beta) builds.

 
Anthony Garot:

iBarShift() sometimes works, sometimes does not.

  • By "works" I mean that it returns a bar number given a specific time for historical data that I know exists on the machine.
  • By "not works" I mean that it returns -1 even though historical data exists.

I created a test script (attached). It assumes that all CADJPY D1 historical data is already on your machine.

iBarShift() sometimes returns a bar value (not -1) within 100 attempts, sometimes it does not. It almost never returns a value (not -1) on the first call.

In my investigation of this issue, I came across iBarShift - library for MetaTrader 5 by Alain. I've copied his function to the bottom of my test script (with copyright intact), but renamed it to iBarShiftAlain(). In my tests, Alain's function works every time.

So . . . there is something not quite right under the hood of MT5's iBarShift(). I'll be using Alain's version henceforth.

OnInit() isn't a good place for your test code with built-in function.
 
Fernando Carreiro:

By the way, I am assuming you are using the stable 1881 build and not any of the latest bungled (oops, I mean beta) builds.

build 1940

 
Anthony Garot: build 1940

How does it stack up on build 1881?

 
Fernando Carreiro:

How does it stack up on build 1881?

Better.

The first time it comes up with garbage, but subsequent runs it gives the expected result without spinning through a lot of attempts.

first failure

 
Alain Verleyen:
OnInit() isn't a good place for your test code with built-in function.

Oh.

So, how would you go about converting a single time to an index? I want to know specifically how many bars to limit my data loading.

I used something like this, but it includes weekends:

#define HR2400 86400     // 24 * 60 * 60
#define MIDNIGHT(x) x - (int) MathMod(x,HR2400)

int maxBar = ( MIDNIGHT(TimeCurrent()) - D'2007.02.12' ) / PeriodSeconds(PERIOD_D1);

iBarShift() seems the right function to use, but I don't want to calculate it in OnCalculate() every tick.

I mean, I suppose I could just multiply maxBar (above) by 5/7ths and be done with it, but it would only be an approximation.

 
Anthony Garot:

Oh.

So, how would you go about converting a single time to an index? I want to know specifically how many bars to limit my data loading.

I used something like this, but it includes weekends:

iBarShift() seems the right function to use, but I don't want to calculate it in OnCalculate() every tick.

I mean, I suppose I could just multiply maxBar (above) by 5/7ths and be done with it, but it would only be an approximation.

OnCalculate() 

if(prev_calculated==0) 
 {
  earliestBar = iBarShift("CADJPY", PERIOD_D1, EARLIEST_TIME, false);
  if(earliestBar==-1) retturn(0);

  ...
 )
Is this working better ?
 
Alain Verleyen:
Is this working better ?

I must answer "no" and "yes" and "very interesting."

:-D

"No" : means that iBarShift() continues to give sporadic results of -1 despite all historical data loaded. This happens most frequently when I re-start Terminal then start my Test indicator. Sometimes iBarShift() will give a value after, say 10, attempts; sometimes it doesn't give a value even after a full 100 attempts.

"Yes" : mean that I can return 0 after trying for 100 attempts. This, of course, means OnCalculate() gets called again on the next tick and prev_calculated is again 0. It appears that iBarShift() does give a value (not -1) at least by this second call of OnCalculate(). So this is actually usable!

"Very Interesting" : switching to your version of iBarShift() in the above construct fails every time. :-D

I'm attaching my updated Test file for posterity.

Files:
Test.mq5  5 kb
 
Anthony Garot:

I must answer "no" and "yes" and "very interesting."

:-D

"No" : means that iBarShift() continues to give sporadic results of -1 despite all historical data loaded. This happens most frequently when I re-start Terminal then start my Test indicator. Sometimes iBarShift() will give a value after, say 10, attempts; sometimes it doesn't give a value even after a full 100 attempts.

"Yes" : mean that I can return 0 after trying for 100 attempts. This, of course, means OnCalculate() gets called again on the next tick and prev_calculated is again 0. It appears that iBarShift() does give a value (not -1) at least by this second call of OnCalculate(). So this is actually usable!

You don't need a loop at all. Such loop are a "wrong" practice, either you are not in a hurry, just return(0) in case of error and try again on next tick (like I suggested in my previous post), or you want things done ASAP, then use a timer.

"Very Interesting" : switching to your version of iBarShift() in the above construct fails every time. :-D

I'm attaching my updated Test file for posterity.

I have no idea what you mean. My function works well but is slower than the built-in function.

 
Alain Verleyen:

I have no idea what you mean. My function works well but is slower than the built-in function.

When I tested Test.mp5 before, with your function, it failed every time. But now it's working. Sorry for any confusion. Gremlins have beleaguered me today.
Reason: