Checking for recently closed bars on multiple timeframes

 

Hi all.

 I'm working on an EA that checks the most recenltly closed bar for Pinbar geometry. The code at the bottom of the page is a cut-down version of the EA, intended to to display my issue.

 I first search for when a bar closes using code that has been on this forum many times, and this works fine.

      static datetime Time0;
      if (Time0 == iTime(NULL,1,1))
      return;
      Time0 = iTime(NULL,1,1);

 

But my issue is that I want to check for closed bars on multiple timeframes. So in the input area, I have bool variables asking if the user wants to check that specific timeframe. And the once the EA gets to OnTick, it follows the sequence:

- after each tick,

it checks if the user wants to check the M1 timeframe. If yes, it then checks to see if a new bar has been created If it has, it calls the Pin_bar function to check if the closed M1 bar is a pinbar and if so, creates an alert.

it then moves back to the main program and checks if the M5 is to be analysed. If so, it checks to see if a new bar has been created, and so on.

 

In my actual EA, I have all timeframes available for analysis, even though I'll most likely stick to M30 through to D1 for trading.

 

So my question is this - is there a smarter, more efficient way of  running though all of the timeframes to check if new bars have just been created?

 

Mark 

 

//+------------------------------------------------------------------+
//|                                                     FOR loop.mq4 |
//|                                       Copyright 2015 Mark Falzon |
//|                                             https://www.mql4.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015 Mark Falzon"
#property link      "https://www.mql4.com"
#property version   "1.00"
#property strict


input string            Variables="**********************";
input double            Tail_ratio=2; // Minimum tail (ratio)
input double            Nose_percentage=25; // Maximum nose percentage (%)
input double            Min_candle_length=1; //Minimum length of Pinbar (points)
input double            Max_candle_length=1500; //Maximum length of Pinbar (points)
input bool              M1=true; // Live trade the M1 chart
input bool              M5=true; // Live trade the M5 chart
input bool              M15=true; // Live trade the M15 chart
input bool              M30=true; // Live trade the M30 chart

double         Range, Body, Upper_Shadow, Lower_Shadow;
bool           Bull_PB=false, Bear_PB=false;
int            ObjectsDeleteAll, TF;
void           Pin_bar(int TF);


//+------------------------------------------------------------------+
//| Expert initialization function                                   | static
//+------------------------------------------------------------------+

int OnInit()
   {
   ObjectsDeleteAll();
   Alert("New Run Start Point");
   return(INIT_SUCCEEDED);
   }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+

 void OnDeinit(const int reason)
  {
//---
   
  }
  
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+

void OnTick()
   {
   if (M1==true)
      {
      static datetime Time0;
      if (Time0 == iTime(NULL,1,1))
      return;
      Time0 = iTime(NULL,1,1);
      TF=PERIOD_M1;
      Print("New "+IntegerToString(TF)+" bar");
      Pin_bar(TF);
      }
   
   if (M5==true)
      {
      static datetime Time1;
      if (Time1 == iTime(NULL,5,1))
      return;
      Time1 = iTime(NULL,5,1);
      TF=PERIOD_M5;
      Print("New "+IntegerToString(TF)+" bar");
      Pin_bar(TF);
      }
   
   if (M15==true)
      {
      static datetime Time2;
      if (Time2 == iTime(NULL,15,1))
      return;
      Time2 = iTime(NULL,15,1);
      TF=PERIOD_M15;
      Print("New "+IntegerToString(TF)+" bar");
      Pin_bar(TF);
      }

   if (M30==true)
      {
      static datetime Time3;
      if (Time3 == iTime(NULL,30,1))
      return;
      Time3 = iTime(NULL,30,1);
      TF=PERIOD_M30;
      Print("New "+IntegerToString(TF)+" bar");
      Pin_bar(TF);
      }
   }

//+------------------------------------------------------------------+
//| Pinbar check function                                            |
//+------------------------------------------------------------------+

void Pin_bar(int TF)
   {
   
//--- Establishing Range, Body, Spread, Upper Shadow and Lower Shadow

   Range=(iHigh(NULL,TF,1)-iLow(NULL,TF,1));
   Body=fabs((iClose(NULL,TF,1)-iOpen(NULL,TF,1)));
   
   if ((Range<=(Max_candle_length*(MarketInfo(Symbol(),MODE_TICKSIZE))))
   &&(Range>=(Min_candle_length*(MarketInfo(Symbol(),MODE_TICKSIZE)))))
      {
      if (iClose(NULL,TF,1)>iOpen(NULL,TF,1))
         {Upper_Shadow=(iHigh(NULL,TF,1)-iClose(NULL,TF,1));
         Lower_Shadow=(iOpen(NULL,TF,1)-iLow(NULL,TF,1));}
      else
         {Upper_Shadow=(iHigh(NULL,TF,1)-iOpen(NULL,TF,1));
         Lower_Shadow=(iClose(NULL,TF,1)-iLow(NULL,TF,1));}

//--- Check whether candle is a Bullish Pinbar

      if ((Upper_Shadow<(Range*Nose_percentage/100))&&(Lower_Shadow>(Body*Tail_ratio)))
         {
         Bull_PB=True;
         Alert("A bullish pinbar has just formed on the M"+IntegerToString(TF)+" Chart of "+Symbol());
         }
      else
         {Bull_PB=False;}

//--- Check whether candle is a Bearish Pinbar

      if ((Upper_Shadow>(Body*Tail_ratio))&&(Lower_Shadow<(Range*Nose_percentage/100)))
         {
         Bear_PB=True;
         Alert("A bearish pinbar has just formed on the M"+IntegerToString(TF)+" Chart of "+Symbol());
         }
      else
         {Bear_PB=False;}
      }
   }
 
  int timeframe=ChartPeriod(0);
  
  switch(timeframe)
   {
    case 1:
    // Do something if M1
    break;
    
    case 5:
    // Do something if M5
    break;
    
    case 15:
    // Do something if M15
    break;
    
    case 30:
    // Do something if M30
    break;
    
    case 60:
    // Do something if H1
    break;
    
    case 240:
    // Do something if H4
    break; 
   } 


i think this needs for loop i =6.

 

very crude be careful..

just to give you an idea,

//+------------------------------------------------------------------+
int OnInit()
  {
//--- 
  int bars_M1=iBars(Symbol(),PERIOD_M1);
  int bars_M5=iBars(Symbol(),PERIOD_M5);
  int bars_M15=iBars(Symbol(),PERIOD_M15);
  int bars_M30=iBars(Symbol(),PERIOD_M30);
  int bars_H1=iBars(Symbol(),PERIOD_H1);
  int bars_H4=iBars(Symbol(),PERIOD_H4);    
//---
  }
//+------------------------------------------------------------------+

  int timeframe=ChartPeriod(0);
  
  switch(timeframe)
   {
    case 1:
    if(bars_M1 != iBars(Symbol(),PERIOD_M1))
     {
      // Do something if new bar
      bars_M1=iBars(Symbol(),PERIOD_M1);// save new number of bars.
     }
    break;
    
    case 5:
    if(bars_M5 != iBars(Symbol(),PERIOD_M5))
     {
      // Do something if new bar
      bars_M5=iBars(Symbol(),PERIOD_M5);// save new number of bars.
     }
    break;
    
    case 15:
    if(bars_M15 != iBars(Symbol(),PERIOD_M15))
     {
      // Do something if new bar
      bars_M15=iBars(Symbol(),PERIOD_M15);// save new number of bars.
     }
    break;
    
    case 30:
    if(bars_M30 != iBars(Symbol(),PERIOD_M30))
     {
      // Do something if new bar
      bars_M30=iBars(Symbol(),PERIOD_M30);// save new number of bars.
     }
    break;
    
    case 60:
    if(bars_H1 != iBars(Symbol(),PERIOD_H1))
     {
      // Do something if new bar
      bars_H1=iBars(Symbol(),PERIOD_H1);// save new number of bars.
     }
    break;
    
    case 240:
    if(bars_H4 != iBars(Symbol(),PERIOD_H4))
     {
      // Do something if new bar
      bars_H4=iBars(Symbol(),PERIOD_H4);// save new number of bars.
     }
    break; 
   } 


But im not sure what u want to do exactly i think my code is wrong.

//+------------------------------------------------------------------+
int OnInit()
  {
//--- 
  int bars_M1=iBars(Symbol(),PERIOD_M1);
  int bars_M5=iBars(Symbol(),PERIOD_M5);
  int bars_M15=iBars(Symbol(),PERIOD_M15);
  int bars_M30=iBars(Symbol(),PERIOD_M30);
  int bars_H1=iBars(Symbol(),PERIOD_H1);
  int bars_H4=iBars(Symbol(),PERIOD_H4);    
//---
  }
//+------------------------------------------------------------------+


    if(bars_M1 != iBars(Symbol(),PERIOD_M1))
     {
      // Do something if new bar
      bars_M1=iBars(Symbol(),PERIOD_M1);// save new number of bars.
     }

    if(bars_M5 != iBars(Symbol(),PERIOD_M5))
     {
      // Do something if new bar
      bars_M5=iBars(Symbol(),PERIOD_M5);// save new number of bars.
     }

    if(bars_M15 != iBars(Symbol(),PERIOD_M15))
     {
      // Do something if new bar
      bars_M15=iBars(Symbol(),PERIOD_M15);// save new number of bars.
     }

    if(bars_M30 != iBars(Symbol(),PERIOD_M30))
     {
      // Do something if new bar
      bars_M30=iBars(Symbol(),PERIOD_M30);// save new number of bars.
     }

    if(bars_H1 != iBars(Symbol(),PERIOD_H1))
     {
      // Do something if new bar
      bars_H1=iBars(Symbol(),PERIOD_H1);// save new number of bars.
     }
    
    if(bars_H4 != iBars(Symbol(),PERIOD_H4))
     {
      // Do something if new bar
      bars_H4=iBars(Symbol(),PERIOD_H4);// save new number of bars.
     }


so easier but Bars is not reliable could use Time instead..

 
Marco vd Heijden:

Thanks Marco. Does 'Switch' allow for all timeframes to be checked simultaneously? I'm just reading the MQL4 book and it seems that Switch is used when there is a choice between M1 or M5 or M15, etc. If this is the case, I need my EA to do as many timeframes as the operator asks for all at the same time.

 

Mark 

 

that is impossible all at the same time.

you must mean one after the other on each tick.

 

  int i;
  int frame;


  for(i=0;i<7;i++)
   {
   if(i==0){frame=1;}if(i==1){frame=5;}if(i==2){frame=5;}if(i==3){frame=15;}if(i==4){frame=30;}if(i==5){frame=60;}if(i==6){frame=240;}
    {
     switch(frame)
      {
       case 1:
        // Do something if M1
        break;
    
       case 5:
        // Do something if M5
        break;
    
       case 15:
        // Do something if M15
        break;
    
       case 30:
        // Do something if M30
        break;
    
       case 60:
        // Do something if H1
        break;
    
       case 240:
        // Do something if H4
        break; 
      } 
    } 
  }


i don't think it is suited there must be easier way's there always is.

 

Sorry Marco - my response was just to your first comment.

 

I've read a bit on the forum about how to best check when a new bar has just started and the consensus always seems to be that using time is the most reliable.

 

Do you know if there's a better way to cycle through the chosen timeframes? Initially I had set up ENUM variables where the user selects the lowest timeframe and the highest timeframe to analyse but I couldn't find an efficient way to sysle through the times because the daily variable PERIOD_D1 has a value of 1440 so if you were to set up a FOR loop to start at LTF being PERIOD_M1 and finish at PERIOD_D1, the loop would need to run through 1 to 1440 for each tick. 

input ENUM_TIMEFRAMES   LTF=PERIOD_M1; // Lowest timeframe to analyse
input ENUM_TIMEFRAMES   HTF=PERIOD_M15; // Highest timeframe to analyse

 

Mark 

 
And yes, I meant to say one after the other but all during each tick.
 

thats why u use this line

if(i==0){frame=1;}if(i==1){frame=5;}if(i==2){frame=5;}if(i==3){frame=15;}if(i==4){frame=30;}if(i==5){frame=60;}if(i==6){frame=240;}


its only six of seven steps

 
Marco vd Heijden:

thats why u use this line


its only six of seven steps

Aha!

I see.

So do you think it would be possible to set this up with my ENUM variables so the user just selects the lowest timeframe and the  highest timeframe?

 

sure but u could write a function that checks all and then only use what is needed.

but i do not understand the target as you have one M5 bar once every 5 M1 bars and 4 M15 bars once every H1 bar so i do not understand why you want to check all timeframes for new bar since as soon as you got 15 M1 bars the M15 will also shift one it makes no sense.

 
Marco vd Heijden:

sure but u could write a function that checks all and then only use what is needed.

but i do not understand the target as you have one M5 bar once every 5 M1 bars and 4 M15 bars once every H1 bar so i do not understand why you want to check all timeframes for new bar since as soon as you got 15 M1 bars the M15 will also shift one it makes no sense.

Yes, very true.

 This would be my goal but I guess I just didn't know how to do it. I've only just got the current program to work as I'm obviously very new to this.

So your code below does this? Or would I have to set up a seperate counter? Do the bars ever get out of sync though? ie can there be times when there'll be no movement for a minute so no new M1 candle is created for that minute?

 

int i;
  int frame;


  for(i=0;i<7;i++)
   {
   if(i==0){frame=1;}if(i==1){frame=5;}if(i==2){frame=5;}if(i==3){frame=15;}if(i==4){frame=30;}if(i==5){frame=60;}if(i==6){frame=240;}
    {
     switch(frame)
      {
       case 1:
        // Do something if M1
        break;
    
       case 5:
        // Do something if M5
        break;
    
       case 15:
        // Do something if M15
        break;
    
       case 30:
        // Do something if M30
        break;
    
       case 60:
        // Do something if H1
        break;
    
       case 240:
        // Do something if H4
        break; 
      } 
    } 
  }
Reason: