Problem with accessing other time frames

 

I created an indicator based on a macd to show the status of the hourly MACD on lower timeframes.

So the indicator should show 2 identical bars for each hour when attatched to the 30 minute chart, 4 when attached on the 15 minute chart, 12 when attached to the 5 minute chart and 60 when attatched to the 1 minute chart.

The results were not as I expected, even though the new indicator appears to work correctly, and does match the regular macd when attached to the hourly chart, when attached to lower time frames, the macd histogram values do not match the values of the real macd on the hourly chart, Can anyone explain this ?

I coded it like this:

#property link      "https://www.mql5.com/en/users/SDC"

//---- indicator settings
#property  indicator_separate_window
#property  indicator_buffers 2
#property  indicator_color1  Silver
#property  indicator_color2  Red
#property  indicator_width1  2
//---- indicator parameters
extern int Fast=12;
extern int Slow=26;
extern int Signal=9;
extern int Shift=0;
//---- indicator buffers
double     MacdBuffer[];
double     SignalBuffer[];
int        buffers=0;

//+-----------------------------------------------------------------------+
//| Custom indicator initialization function                              |
//+-----------------------------------------------------------------------+
int init()
  {
//---- buffers mapping/drawing settings   
   buffers=0;
   init_buffer(MacdBuffer,  "MACD60",DRAW_HISTOGRAM);
   init_buffer(SignalBuffer,"Signal",DRAW_LINE,0,0,Signal);
//---- name for DataWindow and indicator subwindow label   
   IndicatorShortName("MACD60("+Fast+","+Slow+","+Signal+")");
//---- initialization done
   return(0);
  }
//+-----------------------------------------------------------------------+
//| Moving Averages Convergence/Divergence                                |
//+-----------------------------------------------------------------------+
int start()
  {
   int i,j,k,limit,mins;
   int tf=Period();
   int counted_bars=IndicatorCounted();
//---- last counted bar will be recounted
   if(counted_bars>0) counted_bars--;
   limit=Bars-counted_bars-1;
   if(limit>5000) limit=5000;
//---- macd counted in the 1-st buffer
   for(i=limit; i>=0; i--)
    {mins=StrToInteger(StringSubstr(TimeToStr(Time[i],TIME_MINUTES),3,0));
     for(j=0,k=0; j<=mins; j+=tf, k++)
      {MacdBuffer[i+k]=iMA(NULL,60,Fast,0,MODE_EMA,PRICE_CLOSE,i)
                      -iMA(NULL,60,Slow,0,MODE_EMA,PRICE_CLOSE,i);
    } }
   
//---- signal line counted in the 2-nd buffer
   for(i=0; i<limit; i++)
    SignalBuffer[i]=iMAOnArray(MacdBuffer,Bars,Signal,0,MODE_SMA,i);
//---- done
   return(0);
  }
//+-----------------------------------------------------------------------+
//| Initialize Buffers                                                    |
//+-----------------------------------------------------------------------+
void init_buffer(double array[],string label = "",int type = DRAW_NONE,
                 int style = EMPTY, int arrow = 0, int draw_begin = 0,
                 int width = EMPTY, color clr = CLR_NONE)
{
  SetIndexBuffer(buffers, array);
  SetIndexLabel(buffers, label);
  SetIndexEmptyValue(buffers, EMPTY_VALUE);
  SetIndexDrawBegin(buffers, draw_begin);
  SetIndexShift(buffers, Shift);
  SetIndexStyle(buffers, type, style, width);
  SetIndexArrow(buffers, arrow);
  buffers++;
}
//+-----------------------------------------------------------------------+

ABOVE: New indicator attatched to hourly chart with regular MACD both indicators match.

BELOW: Now the new indicator and the regular MACD on the 15 minute chart, it looks ok there are four identical bars for each hour, except the last unfinished hour, this shows the hourly MACD was down for the last three and a half hours and prior to that it was up.

This does not corrolate with the MACD on the real hourly chart as you can see in the above picture the real hourly MACD was down for the past twelve hours.

I know I have to be missing something obvious, the code is above would someone mind testing this and helping me figure out what is wrong ?

 
int counted_bars=IndicatorCounted();
for(int iChart=Bars - 1 - counted_bars; iChart >= 0; iChart--){
    int iH1 = iBarShift(NULL, PERIOD_H1, Time[iChart])
    MacdBuffer[iChart]   = iMACD(NULL, PERIOD_H1, fast, slow, signal, PRICE_CLOSE, MODE_MAIN, iH1);
    SignalBuffer[iChart] = iMACD(NULL, PERIOD_H1, fast, slow, signal, PRICE_CLOSE, MODE_SIGNAL, iH1);
}
 

Thanks WHR I might have known you would fix that in a few minutes Ive been messing with it for days lol ... so iMACD gives the correct result for accessing different timeframes but I thought iMA() would give the correct result for the other timeframe so a MACD could be built from that, why is that not the case ?

Nice how you use iBarShift I hadnt thought of using it that way

 
SDC:

BELOW: Now the new indicator and the regular MACD on the 15 minute chart, it looks ok there are four identical bars for each hour [...] I know I have to be missing something obvious, the code is above would someone mind testing this and helping me figure out what is wrong ?

What you've got is a fundamental limitation in MT4 which is very, very time-consuming to work round. Unless you go to very substantial lengths, the historic values drawn by a "multi-timeframe" indicator will not be what you would have seen at the time. Drawing on a forward basis, after the indicator has been added to the chart, will be fine but the historic values from before the indicator was added will only be valid at bar-ends on the higher timeframe.

Let's take a simple example using WHRoeder's nice concise code:

* Let's say that you are on a M15 chart and that it's currently 07:02. Time[1] is therefore 06:45, Time[2] is 06:30, Time[3] is 06:15, and Time[4] is 06:00 etc.

* For bars 1 to 4, i.e. 06:45 back to 06:00, iBarShift(NULL, PERIOD_H1, Time[iChart]) will return 1

* iMACD(...) will then calculate the value at the end of that hourly bar, i.e. the H1 MACD value at 06:59

* Therefore, you will see four identical historic values from the indicator - the stepped appearance which you are noting

* More importantly, the values shown for 06:00, 06:15 and 06:30 are not what you would have seen at the time. The indicator is drawing the hourly MACD at 06:59 against the M15 candles which end at 06:14, 06:29 and 06:44

The effect of all this is that multi-timeframe indicators often look as though they are spectacularly successful in giving trade signals, but that's because - retrospectively, on historic data - they can effectively see into the future.

The only way round this is the complicated step of doing your own MACD calculation, including a calculation of what the H1 bar would have looked like historically when not yet complete at 06:14. 06:29 and 06:44.

 

Yes I understand that limitation, usually I would create my indicators based on the Open price so when I backtest I know the results will be the same as they would have been in live trading.

I wanted to create this indicator to visually test the corrolation between timeframes on the same chart, so I needed all the bars of the same hour to reflect the hourly chart of that hour therfore making the 4 bar groups you see in the pictures.

while working on live prices I had intended the indicator should update all the bars of the last hour on each new tick so they should also finish with 4 identical bars.

The other option was to do like you said and make each bar reflect the status of the hourly chart when not yet complete, I had not considered that.

WHR's code appears to do both, it creates the 4 bar groups on the historical chart but on live prices it appears to be showing the status of the hourly bar for each 15 minute period while not yet complete. I let the indicator run for a few hours with WHR's code along side a regular macd. I highlighted the section created from live prices.

I still havent figured out why my original code didnt work correctly to build the MACD from the MA values off the hourly timeframe, using the minutes of the current bar to decide if they are in the same hour, then using the loop to find the barshifts needed so the indicator would update all the bars of the same hour.

   int i,j,k,limit,mins;
   int tf=Period();
   int counted_bars=IndicatorCounted();
   limit=Bars-counted_bars-1;

   for(i=limit; i>=0; i--)
    {mins=StrToInteger(StringSubstr(TimeToStr(Time[i],TIME_MINUTES),3,0));
     for(j=0,k=0; j<=mins; j+=tf, k++)
      {MacdBuffer[i+k]=iMA(NULL,60,Fast,0,MODE_EMA,PRICE_CLOSE,i)
                      -iMA(NULL,60,Slow,0,MODE_EMA,PRICE_CLOSE,i);
    } }
 
SDC:

WHR's code appears to do both, it creates the 4 bar groups on the historical chart but on live prices it appears to be showing the status of the hourly bar for each 15 minute period while not yet complete. I let the indicator run for a few hours with WHR's code along side a regular macd. I highlighted the section created from live prices.

The limitations only apply on historic data, not when drawing on a forward basis. Continuing the earlier example where you add the indicator at 07:02, then at 07:14 the indicator will draw a value based on the incomplete, 15-minute-old H1 bar etc. It will only continue to draw in "steps" if, at each hour-end, the indicator goes back and redraws the old values at each M15 bar-end, and updates them based on the subsequent value at the H1 bar-end.

I still havent figured out why my original code didnt work correctly to build the MACD from the MA values off the hourly timeframe

I haven't looked at it in detail - because WHRoeder's version is, frankly, a lot more elegant - but at least part of the problem seems to be that you are using i as the shift value for the iMA() function. Therefore, as far as I can see, when you are drawing the value for the M15 bar 10 bars ago, i.e. 2.5 hours ago, then you are calculating the MA for the period up to 10 hours ago.

 

Yes you are right I was using i from the 15 minute chart as the bar shift to get the values from the hourly chart, so thats the reason it wasnt working correctly thanks for pointing that out jjc, and thanks WHR for your code.

I should have used iBarShift like WHR did.

Anyways here is the indicator as I had intended it to be.

#property link      "https://www.mql5.com/en/users/sdc"

#property  indicator_separate_window
#property  indicator_buffers 2
#property  indicator_color1  Silver
#property  indicator_color2  Red
#property  indicator_width1  2

extern int Fast=12;
extern int Slow=26;
extern int Signal=9;
extern int Shift=0;

double     MacdBuffer[];
double     SignalBuffer[];
int        buffers=0;

//+-----------------------------------------------------------------------+
//| Custom indicator initialization function                              |
//+-----------------------------------------------------------------------+
int init()
  {   
   buffers=0;
   init_buffer(MacdBuffer,  "MACD60",DRAW_HISTOGRAM);
   init_buffer(SignalBuffer,"Signal",DRAW_LINE,0,0,Signal);   
   IndicatorShortName("MACD60("+Fast+","+Slow+","+Signal+")");
   return(0);
  }
//+-----------------------------------------------------------------------+
//| Moving Averages Convergence/Divergence                                |
//+-----------------------------------------------------------------------+
int start()
  {
   int i,j,k,limit,mins,iH1;
   int tf=Period();
   int counted_bars=IndicatorCounted();
   limit=Bars-counted_bars-1;
   for(i=limit; i>=0; i--)
    {mins=StrToInteger(StringSubstr(TimeToStr(Time[i],TIME_MINUTES),3,0));
     iH1 = iBarShift(NULL, PERIOD_H1, Time[i]);
     for(j=0,k=0; j<=mins; j+=tf, k++)
      {MacdBuffer[i+k]=iMA(NULL,60,Fast,0,MODE_EMA,PRICE_CLOSE,iH1)
                      -iMA(NULL,60,Slow,0,MODE_EMA,PRICE_CLOSE,iH1);
    } }
   for(i=0; i<limit; i++)
    SignalBuffer[i]=iMAOnArray(MacdBuffer,Bars,Signal,0,MODE_SMA,i);
//---- done
   return(0);
  }
//+-----------------------------------------------------------------------+
//| Initialize Buffers                                                    |
//+-----------------------------------------------------------------------+
void init_buffer(double array[],string label = "",int type = DRAW_NONE,
                 int style = EMPTY, int arrow = 0, int draw_begin = 0,
                 int width = EMPTY, color clr = CLR_NONE)
{
  SetIndexBuffer(buffers, array);
  SetIndexLabel(buffers, label);
  SetIndexEmptyValue(buffers, EMPTY_VALUE);
  SetIndexDrawBegin(buffers, draw_begin);
  SetIndexShift(buffers, Shift);
  SetIndexStyle(buffers, type, style, width);
  SetIndexArrow(buffers, arrow);
  buffers++;
}
 

Hi. I have been trying to do something similar without success and can't work out how to adapt the iBarsShift approach for mine - suggestions / help gratefully received

The basic indicator marks bars that don't touch 20 EMA (lime = low above, magenta = high below)

#property indicator_separate_window
#property indicator_buffers 2
#property indicator_color1 Lime
#property indicator_color2 Magenta
#property indicator_width1 3
#property indicator_width2 3

double PunchUp[];
double PunchDn[];

static datetime time;

int init()
  {
   SetIndexStyle(0, DRAW_HISTOGRAM);
   SetIndexBuffer(0, PunchUp);
   SetIndexStyle(1, DRAW_HISTOGRAM);
   SetIndexBuffer(1, PunchDn);
   return(0);
  }


int deinit()
  {
   return(0);
  }


int start() 
{
   if(time==Time[0])return(0);  time=Time[0];    // once per bar
   
   int limit, i, counter;
   //double Range, AvgRange;
   int counted_bars=IndicatorCounted();

   //---- check for possible errors
   if(counted_bars<0) return(-1);

   //---- last counted bar will be recounted
   if(counted_bars>0) counted_bars--;

   limit=Bars-counted_bars;
   


   for(i = 0; i < limit; i++)
   {
      
      
// determine if Low is above MA 
                                 if (Low[i+1] > iMA(NULL,0,20,0,1,0,i+1)) 
                   {
            PunchUp[i+1] = Low[i+1];
         }


// determine if High is below MA
                       if (High[i+1] < iMA(NULL,0,20,0,1,0,i+1)) 
                   {
            PunchDn[i+1] = -High[i+1];
         }
           }

   return(0);
}

I've tried to adapt based on the templates in this thread but my inexperience is showing.

  //for(i = 0; i < limit; i++)
   for(int iChart=Bars-1 - counted_bars; iChart >=0; iChart--)
   {
    int iH1 = iBarShift(NULL, PERIOD_H1, Time[iChart]);  
      
// determine if Low is above MA 
                                 if (Low[iH1+1] > iMA(NULL,0,20,0,1,0,iH1+1))
                   {
            //Print("Low[i+1] ",Low[i+1]);
            PunchUp[i+1] = Low[i+1];
         }


// determine if High is below MA
                       if (High[iH1+1] < iMA(NULL,0,20,0,1,0,iH1+1)) 
                   {
            PunchDn[i+1] = -High[i+1];
         }
 
In my previous post
int counted_bars=IndicatorCounted();
for(int iChart=Bars - 1 - counted_bars; iChart >= 0; iChart--){
   int iH1 = iBarShift(NULL, PERIOD_H1, Time[iChart]);
   MacdBuffer[iChart]   = iMACD(NULL, PERIOD_H1, fast, slow, signal, PRICE_CLOSE, MODE_MAIN, iH1);
   SignalBuffer[iChart] = iMACD(NULL, PERIOD_H1, fast, slow, signal, PRICE_CLOSE, MODE_SIGNAL, iH1);
}

This results in the loss of the staircase as SDC showed

This is because IndicatorCounted doesn't know about the longer TF. It's necessary to update all bars corresponding to same H1 value. Try changing the loop:

int counted_bars=IndicatorCounted(),
int iChart=Bars - 1 - counted_bars;
datetime dtH1 = Time[iChart] - Time[iChart] % PERIOD_H1;
for(iChart = iBarShift(NULL,0, dtH1); iChart >= 0; iChart--){
   int iH1 = iBarShift(NULL, PERIOD_H1, Time[iChart]);
   MacdBuffer[iChart]   = iMACD(NULL, PERIOD_H1, fast, slow, signal, PRICE_CLOSE, MODE_MAIN, iH1);
   SignalBuffer[iChart] = iMACD(NULL, PERIOD_H1, fast, slow, signal, PRICE_CLOSE, MODE_SIGNAL, iH1);
}
 
strathmoreraven I've tried to adapt based on the templates in this thread but my inexperience is showing.
    int iH1 = iBarShift(NULL, PERIOD_H1, Time[iChart]);  
      
// determine if Low is above MA 
                      if (Low[iH1+1] > iMA(NULL,0,20,0,1,0,iH1+1))

iH1 is the index for the H1 timeframe. Low[] and iMA(NULL,0 ...) are the current timeframe. Do not mix them. Apples and oranges.

if your test should be the previous H1 low vs H1 MA you'd need

//    if (Low[iH1+1] > iMA(NULL,0,20,0,1,0,iH1+1))
double lowH1 = iLow(NULL, PERIOD_H1, iH1+1),
       iMAH1 = iMA(NULL, PERIOD_H1, 20,0,1,0,iH1+1)
                        if (lowH1 > iMAH1)
Reason: