//+------------------------------------------------------------------+
//|                                             Fractal Breakout.mq4 |
//|                                                tonyc2a@yahoo.com |
//|                                                                  | 
//|                                                      Version 0.9 |
//+------------------------------------------------------------------+
/*README
   This expert determines a price envelope based on the last Up & Down Fractals on whatever time frame the 
   expert is loaded onto. A Buy is triggered when the 'LastUpFractal' is broken and a Sell is triggered when 
  the 'LastDownFractal' is broken. This code is heavily commented and should be easy enough to follow.
   To filter trades, the expert determines the ATR(5) using the time period of the chart it is loaded onto.
  If the size of the 'FractalEnvelope' (LastUpFractal minus LastDownFractal) is less than the 
 'RiskToleranceFactor' times size of the 'FractalEnvelope', then a trade is not entered. By default,
  the 'RiskToleranceFactor' is set to 2.15. The higher this number, the more trades will be entered, 
  but the lower the 'RiskToleranceFactor' the more likely a trade is to be profitable and the more 
  profitable it is likely to be. I suggest a 'RiskToleranceFactor' of no less than 1.5 and no more 
  than 3. But test this yourself and see what results you come up with. 
   Another filter used by the expert is based on the Daily ATR(3). If the Daily ATR(3) is less than 125 pips 
   an Alert is generated at every tick indicating conditions are not ideal for this strategy. To disable the 
   Alert and trade anyway the user will have to edit the code and comment-out that section of the code. 
   The exit of the trades is determined by nothing more than a Trailing Stop. The 'InitialStop' is set 30 pips 
   away from the entry price. However, in the early stages of profitability of the trade the Trailing Stop is 
   kept tight. At 5 pips profit the Stop is moved to Breakeven. At 10 pips profit the Stop is moved to +5 pips,
    at 15 pips profit it is moved to +10 pips. When the profit of the trade reaches 20 pips profit the expert 
    then begins using the PSAR as the Stop; if the PSAR is less profitable than the +10 pip Stop the old Stop 
    is used instead. Once the PSAR reaches higher profitability then the last Stop the PSAR becomes the
     Stop-determining indicator. Default values for the PSAR indicator are 0.07 and 0.2. The user can change 
     these variables without editing the code by changing the 'PSARStepArg' and 'PSARMaxArg'. 
   The expert Alerts the user when a trade has taken place and when there is potential for a trade to take, i.e.
    when the 'FractalEnvelope' is within RiskToleranceFactor'. When there is potential for a trade, an Alert 
    will be generated with every tick until that potential ceases to exist, so you can be away from your 
    computer and wait for the Alert. The idea is at this point, the user can walk over to his computer disable 
    the Alert, check current condition, see if he really wants to place a trade should the 'FractalEnvelope' be 
    broken, and finally set Stop orders at either end of the 'FractalEnvelope'. The expert currently contains
     code to place and exit orders, however I would suggest the user manually place orders as well as manage 
     them manually once placed. 
   Also, the expert automatically draws a Fibonacci Retracement between the 'LastUpFractal' and the 
   'LastDownFractal'. This is a handy tool in and of itself.
   Finally, the best intraday timeframes to use this expert on are probably the 15M and 30M time frames 
   depending on the user's particular style. 5M is probably acceptable but I would suggest lowering the 
   'RiskToleranceFactor' to at least a high of 2.00, maybe even lower. On the 1H and 4H charts, more risk is
    tolerable and profitability is greater, but fewer trades will be signaled. Again, what time frame will
     depend on the style of the user - do not try to determine what timeframe is most profitable. Use whatever 
     time frame fits your *style* best: many small moves or few large moves. Also take a look at the Daily ATR.
      During periods of lower Daily ATR you might want to adjust your time frame accordingly. Test it out and 
      see what works best. 
   The Trade Management section, i.e. the section that determines Exits is the weakest logic of the code right
    now. More work is probably needed even though the current logic works fine. The second weakest section is 
    the Trade Entry code. If you have anything to add to this code please send me an email with your ideas. 
   As far as additional ideas that might be helpful to this strategy, the use of three Open-SMA crosses to
    confirm entries might also be helpful. It seems that when the 5,8,13 SMAs based on the Open Price are 
    intertwined on the same bar as the breakout occurs, there is more likelihood of profit on a 'FractalEnvelope'
     Breakout. 

   - tonyc2a@yahoo.com 
*/
#property copyright "tonyc2a@yahoo.com"
#property link      ""

extern double TakeProfit = 50; //should set this to 50 once MQL4 bugs are fixed
extern double Lots=1;
extern double TrailingStop = 15;
extern double InitialStop = 30;
extern double PSARStepArg = 0.07;
extern double PSARMaxArg = 0.2;
extern double RiskToleranceFactor = 2.15; //higher means more risk allowed, set this to 2.15 once bugs fixed
extern int slip = 0;//exits only
extern double lp = 300;
extern double sp = 30;

//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
//---- TODO: Add your code here.

//----
   return(0);
  }
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
  {
//---- TODO: Add your code here.
   
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
  {
  double b=0; 
   double balance=0;
   double Ilo=0;
   
   balance=AccountBalance();
   b=(5*Point+iATR(NULL,0,4,1)*5.5);
//---- TODO: Add your code here.
   
   //+----Check to see if daily ATR(3) is good for this strategy-----+
  // if(iATR(Symbol(),1440,3,0)<125*Point) Alert("The 3 Day ATR for "+Symbol()+" is not ideal for this strategy.\nTo disable this warning edit the code.");//if daily ATR(3) is less than 125
   //+---------------------------------------------------------------+

   //+----Determines last up and down fractals, and draws fibo retracement between them-+
   double LastUpFractal,LastDownFractal,TimeOfLastDownFractal,TimeOfLastUpFractal;
   double yesterday_high=0;
   double yesterday_low=0;		
   
   for(int i=1;i<Bars;i++){//for loop to find last UpFractal
      if(iFractals(NULL, Period(), MODE_UPPER,i)!=0){// NULL removed Symbol() added
         LastUpFractal=iFractals(NULL, Period(), MODE_UPPER,i);
         TimeOfLastUpFractal=Time[i];
         break;
         }//end if
      }//end for
   for(int j=1;j<Bars;j++){//for loop to find last DownFractal
      if(iFractals(NULL, Period(), MODE_LOWER,j)!=0){
         LastDownFractal=iFractals(NULL, Period(), MODE_LOWER,j);
         TimeOfLastDownFractal=Time[j];
         break;
         }//end if
      }//end for
      
   ObjectDelete("Fractal Fibo Retracement");
   ObjectCreate("Fractal Fibo Retracement",OBJ_FIBO,0,TimeOfLastUpFractal,LastUpFractal,TimeOfLastDownFractal,LastDownFractal);
   
   int FractalEnvelope=MathRound((LastUpFractal-LastDownFractal)/Point);
   int CurrentATR=MathRound(iATR(Symbol(), Period(),5,0)/Point);//put this value in a int variable so it wouldn't display a bunch of zeros
   Comment("Fractal Envelope: "+FractalEnvelope+" pips\n",
           "ATR(5):              "+CurrentATR+" pips\n",
           "BuyStop:            "+LastUpFractal+"\n",
           "SellStop:             "+LastDownFractal+"\n",
            );
   //+---------------------------------------------------------------+
     
   //+----Determines if entry conditions have been met---------------+
   bool BuyTriggered=false;
   bool SellTriggered=false;
   bool FracEnvIsSmallEnough=false;
   bool FractalIsInsideEnvelope=false;
      
   if(FractalEnvelope <= (RiskToleranceFactor * iATR(Symbol(), Period(),5,0)/Point) ){//checks if envelope 
   //is smaller than RiskToleranceFactor times the ATR(5) for the period of the chart
      FracEnvIsSmallEnough=true;
      }//end if
   if(Close[0]<=LastUpFractal && Close[0]>=LastDownFractal){//determines if price is currently inside
   // FractalEnvelope
      FractalIsInsideEnvelope=true;
      }//end if
   if(FracEnvIsSmallEnough && FractalIsInsideEnvelope){//if envelope is smalle enough and price is inside
   // envelope, sends an alert to notify user
     // Alert("FractalEnvelope is "+FractalEnvelope+" pips, and is small enough to indicate trade on the "+Symbol()+" chart.");
      }//end if
      
   if(FracEnvIsSmallEnough){
      if(Open[1]<LastUpFractal || Open[1]>LastDownFractal){//checks if the last bar's open was within the
      // envelope, indicates price is moving out of envelope and not back into it
            if(Close[0]>LastUpFractal && Close[0]<LastUpFractal+(5*Point) ){//the second condition stops the 
            //alert when the price moves more than 5 pips outside the fractal price
               BuyTriggered=true;
               Alert("Buy triggered for "+Symbol()+" on the "+Period()+" minute chart.");
               }//end if
            if(Close[0]<LastDownFractal && Close[0]>LastDownFractal-(5*Point) ){//the second condition stops 
            //the alert when the price moves more than 5 pips outside the fractal price
               SellTriggered=true;
             Alert("Sell triggered for "+Symbol()+" on the "+Period()+" minute chart.");
               }//end if
      }//end if
   }//end if
   //+---------------------------------------------------------------+

   //+----Enters trade if trigger conditions are met-----------------+
   int OrderForThisSymbol=0;
   for(int x=0;x<OrdersTotal();x++){
      OrderSelect(x, SELECT_BY_POS, MODE_TRADES);
      if(OrderSymbol()==Symbol()) OrderForThisSymbol++;
      }//end for
   if(BuyTriggered && OrderForThisSymbol==0){
      //Alert("Buy order triggered for "+Symbol()+" on the "+Period()+" minute chart.");
      int BuyOrderTicket=OrderSend(Symbol(),OP_BUY,Lots,Ask,slip,Ask-(InitialStop*Point),Ask+(TakeProfit*Point),"Buy Order placed at "+CurTime(),0,0,Green);
				//OP_BUY,Lots,Ask,0,Ask-(InitialStop*Point),Ask+(TakeProfit*Point),"Buy Order placed at "+CurTime(),0,0,Green);
     //if(BuyOrderTicket==-1) Alert("Buy order failed for some reason.");
      
      
      }
   if(SellTriggered && OrderForThisSymbol==0){ 
     // Alert("Sell order triggered for "+Symbol()+" on the "+Period()+" minute chart.");
      int SellOrderTicket=OrderSend(Symbol(),OP_SELL,Lots,Bid,slip,Bid+(InitialStop*Point),Bid-(TakeProfit*Point),"Sell Order placed at "+CurTime(),0,0,Red);
								//OP_SELL,Lots,Bid,0,Bid+(InitialStop*Point),Bid-(TakeProfit*Point),"Sell Order placed at "+CurTime(),0,0,Red);
      //if(SellOrderTicket==-1) Alert("Sell order failed for some reason.");
      }
      
   //+---------------------------------------------------------------+
   
   //+----Exits trades based on given criteria, uses PSAR for stop---+
   /*if(OrdersTotal()>0){
      double CurrentPSAR=iSAR(Symbol(), Period(), PSARStepArg, PSARMaxArg, 0);
      for(int cnt=0;cnt<OrdersTotal();cnt++){
         OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
         double Plus1=OrderOpenPrice()+1*Point;
         double Plus5=OrderOpenPrice()+5*Point;
         double Plus10=OrderOpenPrice()+10*Point;
         if(OrderType()==OP_BUY && OrderSymbol()==Symbol()){
            if(OrderProfit()>=6 && OrderProfit()<=10) {  OrderModify(OrderTicket(), OrderOpenPrice(), Plus1, OrderTakeProfit(),Green);}//if profit between 6 and 10 move stoploss to breakeven
            else if(OrderProfit()>=11 && OrderProfit()<=15) { OrderModify(OrderTicket(), OrderOpenPrice(), Plus5, OrderTakeProfit(), Green); }//if profit between 11 and 15 move stoploss to +5
            else if(OrderProfit()>=16 && OrderProfit()<=20) { OrderModify(OrderTicket(), OrderOpenPrice(), Plus10, OrderTakeProfit(), Green);}//if profit between 16 and 20 move stoploss to +10
            else if(OrderProfit()>=21 && CurrentPSAR>OrderStopLoss()) OrderModify(OrderTicket(),OrderOpenPrice(),CurrentPSAR,OrderTakeProfit(),Green);//if profit greater than 20 move stoploss according to PSAR
            }//end if
         if(OrderType()==OP_SELL && OrderSymbol()==Symbol()){
            if(OrderProfit()>=5 && OrderProfit()<10) OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-(1*Point),OrderTakeProfit(),Red);//if profit between 5 and 10 move stoploss to breakeven
            if(OrderProfit()>=10 && OrderProfit()<15) OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-(5*Point),OrderTakeProfit(),Red);//if profit between 10 and 15 move stoploss to +5
            if(OrderProfit()>=15 && OrderProfit()<20) OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-(10*Point),OrderTakeProfit(),Red);//if profit between 15 and 20 move stoploss to +10
            if(OrderProfit()>=20 && CurrentPSAR>OrderStopLoss()) OrderModify(OrderTicket(),OrderOpenPrice(),CurrentPSAR,OrderTakeProfit(),Red);//if profit greater than 20 move stoploss according to PSAR
            }//end if
         }//end for   
      }//end if*/
      
      // ---------------- TRAILING STOP
if(TrailingStop>0)
{ 
     OrderSelect(0, SELECT_BY_POS, MODE_TRADES);
     if((OrderType() == OP_BUY || OrderType() == OP_BUYSTOP) && 
(OrderSymbol()==Symbol()))
         {
            if(TrailingStop>0) 
              {                
               if(Bid-OrderOpenPrice()>Point*TrailingStop)
                 {
                  if(OrderStopLoss()<Bid-Point*TrailingStop)
                    {
                     OrderModify(OrderTicket(),OrderOpenPrice(),Bid- 
Point*TrailingStop,OrderTakeProfit(),0,Aqua);
                     return(0);
                    }
                 }
              }
          }
     if((OrderType() == OP_SELL || OrderType() == OP_SELLSTOP) && 
(OrderSymbol()==Symbol()))
         {
            if(TrailingStop>0)  
              {                
               if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
                 {
                  if(OrderStopLoss()==0.0 || 
                     OrderStopLoss()>(Ask+Point*TrailingStop))
                    {
                     OrderModify(OrderTicket(),OrderOpenPrice
(),Ask+Point*TrailingStop,OrderTakeProfit(),0,Aqua);
                     return(0);
                    }
                 }
              }
          }
}   
} 
     
         
         
   //+---------------------------------------------------------------+



   //Alert("Last Up: "+LastUpFractal+"\nLast Down: "+LastDownFractal);

//----
   return(0);
  
//+------------------------------------------------------------------+