Alternative to iHigh(), iLow(), etc

 

In the EAs I Have been working on recently I have been working witht several timeframes, using iHigh(), iLow(), etc, extensively throughout my code. I noticed that my EAs were running slowly in the Strategy Tester compared to the first EAs I wrote. So I started wondering why, I did a little test and compared iHigh() with High[], predictably High[] was quicker, but I didn't appreciate that it would be over 10 times quicker.

So I wondered if anyone had an alternative solution ?

I did think about writing all the values I am likely to need from other timeframes into an array and then access the array via a custom iHighArray() function call, so I would need to write the code to populate the array and then do a copy/replace of iHigh with iHighArray.

 
  1. No need to copy. In init do a group of ArrayCopySeries(Hm1) etc. and pass them to your function as Analyze(High, Low, Open, Close, Bars) or Analyze(Hm1, Lm1, Om1, Cm1, iBars())
  2. Of course that doesn't help with bar zero in the tester. I've been using
    double   GetHigh( int iBar){ // Tester Limitation: Can't look at bar zero Hi/Lo
        if (iBar > CURRENT_BAR) return( iHigh(chart.symbol, chart.period, iBar) );
        datetime time0  = GetTime(CURRENT_BAR);
        int      TF     = Period(),
                 iChart = iBarShift(chart.symbol,TF, time0),
                 iHH    = iHighest(chart.symbol,TF, MODE_HIGH,iChart+1,CURRENT_BAR);
        return( iHigh(chart.symbol, TF, iHH) );
    }
    int      GetShift(datetime T, bool E=false){
                              return(iBarShift(chart.symbol, chart.period, T, E)); }
    int      GetBars(){          return( iBars(chart.symbol, chart.period      )); }
    datetime GetTime( int iBar){ return( iTime(chart.symbol, chart.period, iBar)); }
    double   GetOpen( int iBar){ return( iOpen(chart.symbol, chart.period, iBar)); }
    double   GetClose(int iBar){ return(iClose(chart.symbol, chart.period, iBar)); }
    double   GetLow(  int iBar){ // Tester Limitation: Can't look at bar zero Hi/Lo
    
    Then I've only been using one TF.
 
WHRoeder:
  1. No need to copy. In init do a group of ArrayCopySeries(Hm1) etc. and pass them to your function as Analyze(High, Low, Open, Close, Bars) or Analyze(Hm1, Lm1, Om1, Cm1, iBars())
  2. Of course that doesn't help with bar zero in the tester. I've been using Then I've only been using one TF.

1. I assumed that the ArrayCopyXxxx() functions wouldn't help as " There is no real memory allocation for data array and nothing is copied. " so the redirect would lead me to the same data and have the same speed issue as iHigh() etc,

I'll test it though and find out. Thanks.

 
smoknfx:

i find it odd that you bring this issue up, cuz this is something that i am a real stinker about...

for starters, i would never use any of those built in functions, such iHigh() and whatever...

me personally, i dont have any way of knowing how those functions might malfunction if perhaps my terminal loses it's history or whatever?

and so my suggestion is that you might consider taking the time to write your own custom_ihigh() or whatever functions in a c compiler and compile it as a dll and that way you are in the drivers seat and you write the entire thing...

no more mysteries.

that is the difference between me and other programmers.

i dont take the easy way out.

Hi Sara


I'm not a Software Engineer or a Programmer or a coder . . . I prefer an efficient approach, why re-invent the wheel when I have one that works well enough for my needs.

 
smoknfx:


sir,

if you are interested in playing a game of semantics jumpingjacks, please understand that i have little time for such types of things.


It's not semantics, I don't have 39 years of coding experience, you are happy to spend your time coding your own time() function ( not shown or shared the reason why ), I don't have that need. I'm happy to be more efficient and rely on the existing functions where I am happy that they do what I need them to do.
 

There is no real memory allocation for data array and nothing is copied

My read is that the call simply points the array in to the history buffers of the time frame requested. It is not copying the data to a separate allocated array. So it should be identical to what happens with high[].

 
WHRoeder:

My read is that the call simply points the array in to the history buffers of the time frame requested.


if i remember correctly, changing the contents of said array will actually change the bars on your chart.

of course, tho, i could be mistaken.

note: this info might be useful to the person that wanted to import some stock information into metatrader?

i dont know 4 sure.

zero/.

 
WHRoeder:

There is no real memory allocation for data array and nothing is copied

My read is that the call simply points the array in to the history buffers of the time frame requested. It is not copying the data to a separate allocated array. So it should be identical to what happens with high[].

I finally got round to testing this . . . using ArrayCopySeries() seems to be just as fast a High[], Low[], etc. this leaves me wondering what was ever the point of iHigh(), iLow(), etc ? I guess it stems from the Windows XP era when a PCs were not overflowing with RAM and iHigh() etc allowed a user to see into the history beyond what was stored on their chart . . . I assume that for iHigh() to be so slow it must be looking at the hst files.

Thank you.

 

there are many cases in computer programming where there are more than one function call that can be used to accomplish the same thing, they just do it a little bit differently, that is all..

for example, in C language we have fprintf and we have fputc, sorta like that..

dont try to read too much into it, just pick the one that works best for you.

it is sorta like how a mechanic has a crescent wrench and a set of box wrenches and a pair of channel lock pliers in his tool box.

either tool might work and get the job done, but there are times when one tool is preferred for the particular job that we are doing.

happy coding,

zero/.

 
smoknfx:


it is sorta like how a mechanic has a crescent wrench and a set of box wrenches and a pair of channel lock pliers in his tool box.

either tool might work and get the job done, but there are times when one tool is preferred for the particular job that we are doing.


Sure I get the analogy, but in this case it is bit like comparing a spanner to a hammer when used to tighten a nut, why would anyone use the hammer if they knew the spanner existed ?
 
RaptorUK:
I finally got round to testing this . . . using ArrayCopySeries() seems to be just as fast a High[], Low[], etc.
So in that case I would combine my approach above with ArrayCopyRates()
#define ACR_TIME        0
#define ACR_OPEN        1
#define ACR_LOW         2
#define ACR_HIGH        3
#define ACR_CLOSE       4
#define ACR_VOLUME      5
#define ACR_COUNT       6
double  chart.bars[][ACR_COUNT];                                // Export to GetXX
int     init(){
    :
    int acr = ArrayCopyRates(chart.bars, chart.symbol, chart.period);
    if (acr < 0){   int gle = GetLastError();
        if (gle != ERR_HISTORY_WILL_UPDATED) DisableTrading("ACR failed: ",gle);
    }
    :
}
int      GetShift(datetime T, bool E=false){
                          return(iBarShift(chart.symbol, chart.period, T, E)); }
int      GetBars(){          return( iBars(chart.symbol, chart.period      )); }
datetime GetTime( int iBar){ return(chart.bars[iBar][ACR_TIME]);               }
double   GetOpen( int iBar){ return(chart.bars[iBar][ACR_OPEN]);               }
double   GetClose(int iBar){ return(chart.bars[iBar][ACR_CLOSE]);              }
double   GetLow(  int iBar){ // Tester Limitation: Can't look at bar zero Hi/Lo
    // for other TFs. So I only look at chart's bars for the period covered by
    // chart.period. Init() issues an Alert during testing if chart's TF is
    #define CURRENT_BAR 0   // longer than chart.period.
    if (iBar > CURRENT_BAR) return(chart.bars[iBar][ACR_LOW]);
    datetime time0  = GetTime(CURRENT_BAR);
    int      TF     = Period(),
             iChart = iBarShift(chart.symbol, TF, time0),
             iLL    = iLowest(chart.symbol, TF, MODE_LOW, iChart+1,CURRENT_BAR);
    return(Low[iLL]);
}
double   GetHigh( int iBar){ // Tester Limitation: Can't look at bar zero Hi/Lo
    if (iBar > CURRENT_BAR) return(chart.bars[iBar][ACR_HIGH]);
    datetime time0  = GetTime(CURRENT_BAR);
    int      TF     = Period(),
             iChart = iBarShift(chart.symbol,TF, time0),
             iHH    = iHighest(chart.symbol,TF, MODE_HIGH,iChart+1,CURRENT_BAR);
    return(High[iHH]);
}
double   GetPrice(int ePrice, int iPrc){
    switch(ePrice){
    case PRICE_CLOSE:       return( GetClose(iPrc) );
    case PRICE_OPEN:        return(  GetOpen(iPrc) );
    case PRICE_HIGH:        return(  GetHigh(iPrc) );
    case PRICE_LOW:         return(   GetLow(iPrc) );
    case PRICE_MEDIAN:      return( (GetHigh(iPrc) + GetLow(iPrc)       )/2. );
    case PRICE_TYPICAL:     return( (GetHigh(iPrc) + GetLow(iPrc)
                                                   + GetClose(iPrc)     )/3. );
    case PRICE_WEIGHTED:    return( (GetHigh(iPrc) + GetLow(iPrc)
                                                   + GetClose(iPrc)*2.  )/4. );
}   }
bool Analyze(){
    for(time0.srv = GetTime(CURRENT_BAR);   time0.srv == 0;
        time0.srv = GetTime(CURRENT_BAR)){
        int gle = GetLastError();   if (gle != ERR_HISTORY_WILL_UPDATED){
            EA.status = "Failed getting "+tf.text+" History:"+gle;
            return(false);                                                  }
        Sleep(15000);   RefreshRates();
    }

Reason: