Why is my while loop not working?

 

Hi guys,

I'm trying to identify 5-candle fractal sweeps as part of my EA but I'm just getting on the strategy tester - any ideas?

void OnTick()
{
   static bool findSwing = true;
   static bool findSweep = false;
   static double swingPrice;
   static string swingTime;
   static string sweepTime;
   
   if(findSwing == true)
   {
      if(iLow(NULL,PERIOD_M15,1) > iLow(NULL,PERIOD_M15,3) && iLow(NULL,PERIOD_M15,2) > iLow(NULL,PERIOD_M15,3))
      {
         if(iLow(NULL,PERIOD_M15,4) > iLow(NULL,PERIOD_M15,3) && iLow(NULL,PERIOD_M15,5) > iLow(NULL,PERIOD_M15,3))
         {
            swingTime = TimeToStr((iTime(NULL,PERIOD_M15,3))|TIME_MINUTES);
            swingPrice = iLow(NULL,PERIOD_M15,3);
            findSwing = false;
            findSweep = true;
         }   
      } 
   }
   else if(findSweep == true)
   {
      while(findSweep == true)
      {
         if(iLow(NULL,PERIOD_M15,3) < swingPrice)
         {
            if(iLow(NULL,PERIOD_M15,1) > iLow(NULL,PERIOD_M15,3) && iLow(NULL,PERIOD_M15,2) > iLow(NULL,PERIOD_M15,3))
            {
               if(iLow(NULL,PERIOD_M15,4) > iLow(NULL,PERIOD_M15,3) && iLow(NULL,PERIOD_M15,5) > iLow(NULL,PERIOD_M15,3))
               {
                  sweepTime = TimeToStr((iTime(NULL,PERIOD_M15,3))|TIME_MINUTES);
                  Alert("Sweep of " + swingTime + " candle by " + sweepTime);
                  findSweep = false;
               }
               else
               {
                  findSweep = true;
               }
            }
            else
            {
               findSweep = true;
            }         
         }
         else
         {    
            findSweep = true;
         } 
      }
   }  
}

Is there any way to stop it freezing when it gets to the else if statement? My thinking behind the loop was that it would keep running until the low of the specified candle met the criteria

 
Harry Wright:

Hi guys,

I'm trying to identify 5-candle fractal sweeps as part of my EA but I'm just getting on the strategy tester - any ideas?

Is there any way to stop it freezing when it gets to the else if statement? My thinking behind the loop was that it would keep running until the low of the specified candle met the criteria

simulate what happens to the second loop if

iLow(NULL,PERIOD_M15,3) is bigger or equal to the swingPrice)
 
Lorentzos Roussos:

simulate what happens to the second loop if

I've tried that as shown below but still not working for some reason?

      while(findSweep == true)
      {
         if(iLow(NULL,PERIOD_M15,3) < swingPrice)
         {
            if(iLow(NULL,PERIOD_M15,1) > iLow(NULL,PERIOD_M15,3) && iLow(NULL,PERIOD_M15,2) > iLow(NULL,PERIOD_M15,3))
            {
               if(iLow(NULL,PERIOD_M15,4) > iLow(NULL,PERIOD_M15,3) && iLow(NULL,PERIOD_M15,5) > iLow(NULL,PERIOD_M15,3))
               {
                  sweepTime = TimeToStr((iTime(NULL,PERIOD_M15,3))|TIME_MINUTES);
                  Alert("Sweep of " + swingTime + " candle by " + sweepTime);
                  findSweep = false;
               }
               else
               {  
                  findSweep = true;
               }
            }
            else
            {
               findSweep = true;
            }         
         }
         else
         {
            if(iLow(NULL,PERIOD_M15,3) >= swingPrice)
            {   
               findSweep = true;
            }
         } 
      }
 
Harry Wright:

I've tried that as shown below but still not working for some reason?

i mean emulate it in your mind ,when does the while loop end if :

iLow(NULL,PERIOD_M15,3) >= swingPrice 

?

Also : 

You want to go back in time until you find this specific setup ? 

or 

This is a static check to the M15 timeframe (check when a new m15 bar forms for running this check ,and can the loops)?

 
Harry Wright:

Hi guys,

I'm trying to identify 5-candle fractal sweeps as part of my EA but I'm just getting on the strategy tester - any ideas?

Is there any way to stop it freezing when it gets to the else if statement? My thinking behind the loop was that it would keep running until the low of the specified candle met the criteria

You don't need the while statement nor the else conditions and you can use iLowest to detect the fractal: hope it helps
void OnTick()
{
   static bool findSwing = true;
   static bool findSweep = false;
   static double swingPrice;
   static string swingTime;
   static string sweepTime;
   
   if(findSwing == true)
   {
      if (iLowest(NULL,PERIOD_M15,MODE_LOW,5,1)==3) {
      //if(iLow(NULL,PERIOD_M15,1) > iLow(NULL,PERIOD_M15,3) && iLow(NULL,PERIOD_M15,2) > iLow(NULL,PERIOD_M15,3))
      //{
         //if(iLow(NULL,PERIOD_M15,4) > iLow(NULL,PERIOD_M15,3) && iLow(NULL,PERIOD_M15,5) > iLow(NULL,PERIOD_M15,3))
         //{
            swingTime = TimeToStr((iTime(NULL,PERIOD_M15,3))|TIME_MINUTES);
            swingPrice = iLow(NULL,PERIOD_M15,3);
            findSwing = false;
            findSweep = true;
         //}   
      } 
   }
   else if(findSweep == true)
   {
      //while(findSweep == true)
      //{
         if(iLow(NULL,PERIOD_M15,3) < swingPrice)
         {
            if (iLowest(NULL,PERIOD_M15,MODE_LOW,5,1)==3) {
            //if(iLow(NULL,PERIOD_M15,1) > iLow(NULL,PERIOD_M15,3) && iLow(NULL,PERIOD_M15,2) > iLow(NULL,PERIOD_M15,3))
            //{
               //if(iLow(NULL,PERIOD_M15,4) > iLow(NULL,PERIOD_M15,3) && iLow(NULL,PERIOD_M15,5) > iLow(NULL,PERIOD_M15,3))
               //{
                  sweepTime = TimeToStr((iTime(NULL,PERIOD_M15,3))|TIME_MINUTES);
                  Alert("Sweep of " + swingTime + " candle by " + sweepTime);
                  findSweep = false;
               //}
               //else
               //{
               //   findSweep = true;
               //}
            }
            //else
            //{
            //   findSweep = true;
            //}         
         }
         //else
         //{    
         //   findSweep = true;
         //} 
      //}
   }  
}
 
Lorentzos Roussos:

i mean emulate it in your mind ,when does the while loop end if :

?

Also : 

You want to go back in time until you find this specific setup ? 

or 

This is a static check to the M15 timeframe (check when a new m15 bar forms for running this check ,and can the loops)?

The intention was that it continues looping until the swing low price was breached, as the whole idea of the script is that it looks for a sweep.

So script is meant to check to see if the price is lower than the swing low, if not, wait until a new M15 bar is formed and then check again. I thought I could achieve this with a look but doesn't seem to work. Using MQL4 so Sleep() won't work in the strategy tester, otherwise I'd use that.

 
Noel Cuillandre:
You don't need the while statement nor the else conditions and you can use iLowest to detect the fractal: hope it helps

Thanks for your reply.

I've tried running that through the strategy tester but it doesn't seem to identify any swings or sweeps oddly.

My thoughts that if it doesn't find any swings or sweeps, it will simply keep rerunning until it does, and then alert.

 

But you have to find the swing low price ,you dont know for sure its on these specific bar adresses . 

Im guessing the PERIOD_M15 is irrevant too .

  • Okay so you need the while loop ,correct thinking ++
  • but you also need to provide feedback to your system ,whether or not you found a swing point 
  • and store that swing point 
  • make sure you check on every new bar 
  • and also shift the seeker as you go through the bars (what you do now is checking the same candles constantly and if there is no swing you enter an infinite loop)
  • and finally provide exit senarios from the loop.

code will follow shortly

This is for MT4 i assume (if it is so your thread will be moved by a mod to the MQL4 section ,you may think it were deleted but it will be just moved dont worry.)
 

Strategy tester processes 1 tick at a time so it will not simulate any changes for iLow etc and your loop will continue looping as it will not reach the return from OnTick.

Just check for new values every tick, do not loop and wait for changes. This is relevant whether using the tester or on a live chart.


I will move your topic to the MQL4 section.

 
   
   if(findSwing == true)
   {
      if (iLowest(NULL,PERIOD_M15,MODE_LOW,5,1)==3) {
            swingTime = TimeToStr((iTime(NULL,PERIOD_M15,3))|TIME_MINUTES);
            swingPrice = iLow(NULL,PERIOD_M15,3);
            findSwing = false;
            findSweep = true;
      } 
   }
   else if(findSweep == true) ««««« This will never execute in the same tick as above.
 

the code i mentioned . Let me know if you have any questions :

#property copyright "Mql5.com forum thread >>"
#property link      "https://www.mql5.com/en/forum/349962"
#property version   "1.00"
#property description "Telegram  : https://t.me/lorentzor\nInstagram : @rlorentzo\nTwitter : @lorentzo_r\nLinkedIn : https://www.linkedin.com/in/lorentzor\nYoutube : https://www.youtube.com/channel/UCM0Lj06cAJagFWvSpb9N5zA\nFacebook  : @LorentzoR"
/* 
ways to connect .> : 
Telegram  : https://t.me/lorentzor
Instagram : https://www.instagram.com/rlorentzo /OR/ @rlorentzo
Twitter   : https://twitter.com/lorentzo_r /OR/ @lorentzo_r
LinkedIn  : https://www.linkedin.com/in/lorentzor
Youtube   : https://www.youtube.com/channel/UCM0Lj06cAJagFWvSpb9N5zA
Facebook  : https://www.facebook.com/LorentzoR /OR/ @LorentzoR
Mql5.com  : https://www.mql5.com/en/users/lorio
*/
#property strict
input int leadIn=3;//lead in bars for swing 
input int leadOut=3;//lead out bars for swing 

/*
a swing structure , think of it as your variable which contains data for the swing 
*/
struct aSwing
{
bool set,armed,hit;
datetime time,barstamp;
double price;
aSwing(void){set=false;armed=false;hit=false;time=0;barstamp=0;price=0;}
};
/*
declaration of 2 aSwing variables HighSwing and LowSwing (like you would declare 2 ints "int h,l;"
*/
aSwing HighSwing,LowSwing;
bool SwingerBusy=false;
//variable for detecting bar change 
datetime EABarstamp=0;
int OnInit()
  {
  
  SwingerBusy=false;
  EABarstamp=0;
  //calling it on init cause market closed --- just for the example 
  //now go read the swing finder function and come back to this point 
  SwingFinder(HighSwing,LowSwing,true);
  //Print our findings 
  Print("High : found("+HighSwing.set+"),price("+DoubleToString(HighSwing.price,Digits())+"),time("+TimeToString(HighSwing.time,TIME_DATE|TIME_MINUTES)+")"); 
  Print("Low  : found("+LowSwing.set+"),price("+DoubleToString(LowSwing.price,Digits())+"),time("+TimeToString(LowSwing.time,TIME_DATE|TIME_MINUTES)+")"); 
  EABarstamp=Time[0];
  //calling it on init cause market closed --- just for the example ends here
  return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
  // <!> no overencompassing loop here ,the system executes this code at every new tick
  //-> Is our custom system busy ? 
  if(!SwingerBusy)//equivalent of if(SwingerBusy==false)
  {
  //get busy
  SwingerBusy=true;
    //if there is a new bar (or the first tick),scan for swings 
    if(Time[0]!=EABarstamp)
    {
    bool first_run=true;
    if(EABarstamp!=0){first_run=false;}
    //now go read the swing finder function and come back to this point 
    SwingFinder(HighSwing,LowSwing,first_run);
    //Print our findings 
    Print("High : found("+HighSwing.set+"),price("+DoubleToString(HighSwing.price,Digits())+"),time("+TimeToString(HighSwing.time,TIME_DATE|TIME_MINUTES)+")"); 
    Print("Low  : found("+LowSwing.set+"),price("+DoubleToString(LowSwing.price,Digits())+"),time("+TimeToString(LowSwing.time,TIME_DATE|TIME_MINUTES)+")"); 
    EABarstamp=Time[0];
    }
    //if none of our swings are set ,scan for swings ends here      
  SwingerBusy=false;
  }
  //-> Is our custom system busy ? ends here 
  }



//SWING FINDER FUNCTION
/*
the swing finder will fill up 2 "a swing" objects ,so we provide them on the call
and we expect them on declaration as references of a swing type (reference => guide on which variable to fill , think of a bridge ,sign "&") 
*/ 
void SwingFinder(aSwing &the_high_swing,aSwing &the_low_swing,bool first_run)
{
int seeker=0;//dummy value for now 
//the seeker points directly at a candidate swing point
/* 
with that arrises our first issue : 
when the ea loads we may have a somewhat complete bar -in contrast with when we know a new bar just started and we can discount it-
so we need a new indicator as well ,if this is the first scan we will start a bit to the right to accomodate the possibly formed 0 bar   
Remember seeker points directly to a candidate for a swing so 
-> if we accomodate the 0 bar we start seeking from leadOut (if leadOut is 3 the candidate is the [this][2][1][0] bar (it has 3 on the right as you see in this extremely professional schematic)
-> if we dont accomodate the 0 bar we start seeking from leadOut+1 (if leadOut is 3 the candidate is not the [this][3][2][1] ([0] started now has no highs no lows its open==close==close[1] most times)
*at this point the first_run was added in the function parameters ,first_run will indicate if this is the first bar
*/
seeker=leadOut;
//so if not the first run
if(!first_run){seeker++;}//adds one 
//all this for adding one ...
/* 
  more thoughts : 
  1.if we find a swing on bar 12 on the first run 
    then a new bar forms and we dont find a new swing on 
    the new bars alone ,there is no point in running back 
    to find a swing again .
  2.that means we need dummies ,variables, -as in dummy a replica not dummy a stupid- 
    and if we find a swing in these replicas we throw it in the referenced variables 
    that were sent in the function
  3.thats what the barstamp will be used for ,it will contain the time of the first formed bar 
    -arrising issue : if we scan the 0 bar too we do NOT send the barstamp of [0] because it must be scanned again 
     when it fully forms (closes),so barstamp always get the time of [1]
  'sco
*/ 
/*
  there is also a very real senario of older bars loading after recent bars and we will miss them in the swing check ,we 
  will do this some other time though...or someone else
*/
//'sco dummy variables 
aSwing high_candidate,low_candidate;
//loop
  //first thing needed in a loop ,a limit 
    int bars_limit=Bars;
    //thats the number of bars available ,which means the last available bar is -1
    bars_limit-=1;//so we remove it
    //but also we have a leadIn amount of x bars so the last possible bar to be a swing is also further back 
    bars_limit-=leadIn;//so we remove it
  while((!high_candidate.set||!low_candidate.set)&&seeker<=bars_limit)
  {
    //2 booleans we will check for both high and low at the same time 
     bool high_in_play=true,low_in_play=true;
    //we will loop old to new , keep reading theres an explanation below 
    int l_old=seeker+leadIn;
    int l_new=seeker-leadOut;    
    for(int l=l_old;l>=l_new;l--)
    {
    //if this is the seeker bar we dont care 
      if(l!=seeker)
      {
      //now ,is the high candidate in play and is this bars high higher than the high of the candidate(seeker) ? 
        if(high_in_play&&High[l]>High[seeker]){high_in_play=false;}//just like that ,turn it off 
      //and is the low candidate in play and is this bars low lower than the low of the candidate(seeker) ? 
        if(low_in_play&&Low[l]<Low[seeker]){low_in_play=false;}//turn it off
      //if both candidates are no longer in play >> bounce of the loop in the loop 
        if(!low_in_play&&!high_in_play){break;}
      }
    //if this is the seeker bar we dont care ends here 
    }
    //loop in the loop ends here 
      //if we dont have a high candidate and the high checks out ,pass the seeker data to it
        if(!high_candidate.set&&high_in_play){high_candidate.set=true;high_candidate.time=Time[seeker];high_candidate.price=High[seeker];}
      //if we dont have a low candidate and the low checks out   ,pass the seeker data to it 
        if(!low_candidate.set&&low_in_play){low_candidate.set=true;low_candidate.time=Time[seeker];low_candidate.price=Low[seeker];} 
    //now ,is any candidate still being "seeked" ? if so go backwards in time (seeker++) 
    seeker++;
    //there is a condition too here though , 
    /*
    have we gone into territory we have previously checked ? 
    if so there is literally no point (apart from the issue mentioned earlier with data loading)
    in running a test again 
    So how will we know we have scanned these parts ? 
    simple 
    1.this is not the first run
    2.the high and low barstamps are the same 
    3.the time of the right most bar (seeker-leadOut) is smaller or equal to these barstamps    
    */
    //so is this not the first run ?
    if(!first_run)//equivalent to first_run==false
    {
    //are barstamps okay ? 
    //remember we check the references variables which hold our data in the trading strategy 
      if(the_high_swing.barstamp==the_low_swing.barstamp)
      {
      //project our rightmost 
        int rightmost=seeker-leadOut;
      //and finally is this time <= that the time in our official barstamps ? 
        if(Time[rightmost]<=the_high_swing.barstamp){break;}//we take the high ,the stamps are the same anyway this code sends us to //B.
      }
    //are barstamps okay ? ends here 
    }
    //not first run ends here 
  }
//loop ends here 
//B.so did we catch anything ? if yes send it to the variables 
  //high swing
  if(high_candidate.set){the_high_swing=high_candidate;}
  //low swing
  if(low_candidate.set){the_low_swing=low_candidate;}
  //barstamp stuff (remember always time of [1])
  the_high_swing.barstamp=Time[1];
  the_low_swing.barstamp=Time[1];
  //done ,go back to the ontick call of this 
}
//SWING FINDER FUNCTION ENDS HERE



Reason: