//+------------------------------------------------------------------+
//|                                     sm3TierLondonBreakout_v2.mq4 |
//+------------------------------------------------------------------+
#property link "http://www.forexfactory.com/showthread.php?t=247220"
#property copyright "2010.08.05 SwingMan"

//source:
//+------------------------------------------------------------------+
// Thread "A Simple London Breakout V.2 " by mer071898
// http://www.forexfactory.com/showthread.php?t=247220
// code adapted: squalou
//+------------------------------------------------------------------+
// v1 - MaxBoxSize calculated with ATR(100)
// v2 - MaxBoxSize calculated as average of the BoxSizes
// v2.1 - MaxBoxSize / DailyRange
//+------------------------------------------------------------------+

#property indicator_chart_window

#define VERSION "sm3TierLondonBreakout v2.1"

extern string Info         = VERSION; // version number information
extern string StartTime    = "06:00";    // time for start of price establishment window =5:00  original / 06:00
extern string EndTime      = "09:00";    // time for end of price establishment window   =8:00  original / 09:00
extern string SessionEndTime= "00:00";   // end of daily session; tomorrow is another day!
extern color  SessionColor = Linen; // show Session periods with a different background color
extern int    NumDays      = 60;         // days back
extern int    MinBoxSizeInPips = 25;     // min tradable box size; when box is smaller than that, you should at least reduce your usual lot-size if you decide to trade it;
extern int    MaxBoxSizeInPips = 55;     // max tradable box size; don't trade when box is larger than that value =80 original
extern bool   LimitBoxToMaxSize = true; // when true, a box larger than MaxBoxSizeInPips will be limited to MaxBoxSizeInPips, and centered on the EMA(box_time_range) value.
extern double TP1Factor    = 0.618;
       double TP2Factor; // set to half-way between TP1Factor and TP3Factor;
extern double TP3Factor    = 2.000;
extern double LevelsResizeFactor = 1.0;
extern color  BoxColorOK   = LightBlue;
extern color  BoxColorNOK  = Red;
extern color  BoxColorMAX  = Orange;
extern color  LevelColor   = Black;
extern int    FibLength    = 12;
extern bool   showProfitZone = true;
extern color  ProfitColor  = LightGreen;
extern bool Show_BoxInfos = true;
extern string ____MaxLimitBoxAverage = "";
extern bool EnableMaxBoxAverage = true;
extern double Factor_BoxAverage = 0.5;
extern string ____MaxLimitWithATR = "";
extern bool EnableMaxBoxWithATR = false;
extern double Factor_ATR = 4.0;
extern int Period_ATR = 100;

extern string objPrefix    = "LB2-";  // all objects drawn by this indicator will be prefixed with this


//--------------------------------------------------------

// GLOBAL variables

double pip;
int digits;
int BarsBack;

datetime tBoxStart;
datetime tBoxEnd;
datetime tSessionStart;
datetime tSessionEnd;

double Up0,Up1,Up2,Up3;
double Down0,Down1,Down2,Down3;

int StartShift;
int EndShift;
datetime alreadyDrawn;
int limit;

//-- box size
int nBoxes;
double sumBoxSize, sumDailyRange;
double minDailyRange, maxDailyRange;
color colorInfo = Blue;
int yStep = 12;
int yInfo4 = 22; //daily range average
int yInfo1 = 34; //box average
int yInfo5 = 46; //current box
int yInfo2 = 58; //factor box average
int yInfo3 = 70; //factor ATR


//+------------------------------------------------------------------+
int init()
//+------------------------------------------------------------------+
{
   RemoveObjects(objPrefix);	
   getpip();	

   BarsBack = NumDays*(PERIOD_D1/Period());
   alreadyDrawn = 0;

   TP2Factor = (TP1Factor+TP3Factor)/2;
   
   //
   Comment (Info+" ["+StartTime+"-"+EndTime+"] end "+SessionEndTime+" min "+DoubleToStr(MinBoxSizeInPips,0)+"p,"+" max "+DoubleToStr(MaxBoxSizeInPips,0)+"p,"+DoubleToStr(TP1Factor,1)+"/"+DoubleToStr(TP3Factor,1));
   //
   if (Show_BoxInfos)
   {
      string st;
      if (EnableMaxBoxAverage)
         st = "Factor BoxAvg= " + DoubleToStr(Factor_BoxAverage,2); else
      if (EnableMaxBoxWithATR)
         st = "Factor ATR= " + DoubleToStr(Factor_ATR,1);  
      if (EnableMaxBoxAverage || EnableMaxBoxWithATR)
      {
         string objnameInfo = objPrefix + "Info2";
         drawFixedLbl(objnameInfo, st, 0, 3, yInfo2, 8, "Arial",colorInfo, false);
      }
   }

   nBoxes = 0;
   sumBoxSize = 0;
   sumDailyRange = 0;

  return(0);
}/*init*/

//+------------------------------------------------------------------+
int deinit()
//+------------------------------------------------------------------+
{
  RemoveObjects(objPrefix);	
  Comment("");
  return(0);
}/*deinit*/


//+------------------------------------------------------------------+
void start()  {
//+------------------------------------------------------------------+
  int i, counted_bars=IndicatorCounted();

  limit = MathMin(BarsBack,Bars-counted_bars-1);

  for (i=limit; i>=0; i--) {
    new_tick(i);
  } // limit loop

  return(0);
}/*start*/

//+------------------------------------------------------------------+
void new_tick(int i) // i = bar number: 0=current(last) bar
//+------------------------------------------------------------------+
{
    datetime thistime = Time[i];

    tBoxStart = StrToTime(TimeToStr(thistime,TIME_DATE) + " "  + StartTime);
    tBoxEnd   = StrToTime(TimeToStr(thistime,TIME_DATE) + " "  + EndTime);
    if (tBoxStart > tBoxEnd) tBoxStart = tBoxStart - 24*60*60; // midnight wrap fix
    if (thistime < tBoxEnd) { // consider the last PAST box
      tBoxStart = tBoxStart - 24*60*60;
      tBoxEnd   = tBoxEnd   - 24*60*60;
    }

    tSessionStart = tBoxEnd;
    tSessionEnd = StrToTime(TimeToStr(tSessionStart,TIME_DATE) + " "  + SessionEndTime);
    if (tSessionStart > tSessionEnd) tSessionEnd = tSessionEnd + 24*60*60; // midnight wrap fix

    if (TimeDayOfWeek(tBoxStart)==0) return; //don't show saturday; sunday=0~saturday=6;

    //get hi/lo
    int StartShift = iBarShift(NULL,0,tBoxStart);
    int EndShift   = iBarShift(NULL,0,tBoxEnd);
    double boxHigh = High[iHighest(NULL,0,MODE_HIGH,(StartShift-EndShift+1),EndShift)];
    double boxLow  = Low[iLowest(NULL,0,MODE_LOW,(StartShift-EndShift+1),EndShift)];
    double boxExtent      = boxHigh - boxLow;
    double boxMedianPrice = (boxHigh+boxLow)/2;

    //-- number of boxes
    if (thistime==tBoxEnd)    
      nBoxes++;

    //-- daily range ================================================
    if (i==limit)
    {
      maxDailyRange = High[i];
      minDailyRange = Low[i];
    }
    else
    {
      if (High[i]>maxDailyRange) maxDailyRange = High[i];
      if (Low[i] <minDailyRange) minDailyRange = Low[i];
    }
    
    if (thistime==tBoxEnd)
    {
      sumDailyRange += (maxDailyRange - minDailyRange)/Point;    
      
      maxDailyRange = High[i];
      minDailyRange = Low[i];
    }

    //-- box size ===================================================
    string objnameInfo, st;
    if (thistime==tBoxEnd)
    {
      //-- box
      sumBoxSize += boxExtent/Point;
      double boxAverage = sumBoxSize/nBoxes;
      double dailyRange = sumDailyRange/nBoxes;
      double boxPercent = 100*(boxAverage/dailyRange);
      double currentPercent = 100*( (boxExtent/Point)/dailyRange);
      
      if (Show_BoxInfos)
      {         
         //-- daily range from box to box
         objnameInfo = objPrefix + "Info4";
         st="DailyRangeAvg= " + DoubleToStr(dailyRange,0);                   
         drawFixedLbl(objnameInfo, st, 0, 3, yInfo4, 8, "Arial",colorInfo, false);
         
         //-- box average
         objnameInfo = objPrefix + "Info1";
         st="BoxAverage= " + DoubleToStr(boxAverage,0)+
            " (" + DoubleToStr(boxPercent,0)+"%)";
         drawFixedLbl(objnameInfo, st, 0, 3, yInfo1, 8, "Arial",colorInfo, false);
         
         //-- current box
         objnameInfo = objPrefix + "Info5";
         st="CurrentBox  = " + DoubleToStr(boxExtent/Point,0)+
            " (" + DoubleToStr(currentPercent,0)+"%)";
         drawFixedLbl(objnameInfo, st, 0, 3, yInfo5, 8, "Arial",colorInfo, false);
      }
      
      //-- ATR
      double dATR = iATR(Symbol(),Period(),Period_ATR,i);
      
      if (Show_BoxInfos)
      {
         objnameInfo = objPrefix + "Info3";
         st="ATR= " + DoubleToStr(dATR/Point,0);
         drawFixedLbl(objnameInfo, st, 0, 3, yInfo3, 8, "Arial",colorInfo, false);
      }
    }
      
    //-- BoxSize with ATR ...........................................
    if (EnableMaxBoxWithATR)
    {      
      if (thistime==tBoxEnd)    
         MaxBoxSizeInPips = MathRound(dATR*Factor_ATR / Point);
    }
    else
    
    //-- average of BoxSize .........................................
    if (EnableMaxBoxAverage)
    {
      if (thistime==tBoxEnd)
         MaxBoxSizeInPips = MathRound(boxAverage * Factor_BoxAverage) ;
    }
    

    if (boxExtent >= MaxBoxSizeInPips * pip && LimitBoxToMaxSize==true) { // box too large, but we allow to trade it at its max acceptable value
      // adjust box parameters to recenter it on the EMA(box_time_range) value
      boxMedianPrice = iMA(NULL,0,StartShift-EndShift,0,MODE_EMA,PRICE_MEDIAN,EndShift);
      boxExtent      = MaxBoxSizeInPips * pip;
      boxHigh        = boxMedianPrice + boxExtent/2;
      boxLow         = boxMedianPrice - boxExtent/2;
    }
    
    // "resize" the Box with LevelsResizeFactor before computing levels
    double extent= LevelsResizeFactor * boxExtent;
    Up0   = boxHigh;
    Up1   = Up0 + extent*TP1Factor;
    Up2   = Up0 + extent*TP2Factor;
    Up3   = Up0 + extent*TP3Factor;
    Down0 = boxLow;
    Down1 = Down0 - extent*TP1Factor;
    Down2 = Down0 - extent*TP2Factor;
    Down3 = Down0 - extent*TP3Factor;

/*
    // save price levels into system global variables, to make them available for other scripts
    GlobalVariableSet(objPrefix+Symbol()+"-BuyEntry", Up0);
    GlobalVariableSet(objPrefix+Symbol()+"-BuyTP1", Up1);
    GlobalVariableSet(objPrefix+Symbol()+"-BuyTP3", Up2);
    GlobalVariableSet(objPrefix+Symbol()+"-SellEntry", Down0);
    GlobalVariableSet(objPrefix+Symbol()+"-SellTP1", Down1);
    GlobalVariableSet(objPrefix+Symbol()+"-SellTP3", Down2);
*/

    // get TP and SL in pips
    double BuyTP1pips      = (Up1-Up0)/pip;
    double BuyTP2pips      = (Up2-Up0)/pip;
    double BuyTP3pips      = (Up3-Up0)/pip;
    double SellTP1pips     = (Down0-Down1)/pip;
    double SellTP2pips     = (Down0-Down2)/pip;
    double SellTP3pips     = (Down0-Down3)/pip;

    // show session period with a different "background" color
    drawBoxOnce (objPrefix+"Session-"+TimeToStr(tSessionStart,TIME_DATE | TIME_SECONDS),tSessionStart,0,tSessionEnd,Up0*2,SessionColor,1, STYLE_SOLID, true);

    // draw pre-breakout box blue/red once per Session:
    if (alreadyDrawn != tBoxEnd) {
      alreadyDrawn = tBoxEnd; // won't redraw until next box
    
      // draw pre-breakout box blue/red:
      string boxName = objPrefix+"Box-"+TimeToStr(Time[i],TIME_DATE)+"-"+StartTime+"-"+EndTime;      
      
      
      // "Caution!" box =============================================
      if (boxExtent <= MinBoxSizeInPips * pip) 
      { 
        drawBox (boxName,tBoxStart,boxLow,tBoxEnd,boxHigh,BoxColorNOK,1, STYLE_SOLID, true);
        DrawLbl(objPrefix+"Lbl-"+TimeToStr(Time[i],TIME_DATE)+"-"+StartTime+"-"+EndTime, "Caution! ("+DoubleToStr(boxExtent/pip,0)+"p)", tBoxStart+(tBoxEnd-tBoxStart)/2,boxLow, 12, "Arial Black", BoxColorNOK, 3);
      }
      else 
      
      // box too large: DON'T TRADE ! ===============================
      if (boxExtent >= MaxBoxSizeInPips * pip) 
      { 
        // box too large, but we allow to trade it at its max acceptable value
        if (LimitBoxToMaxSize==false) 
        { 
          drawBox (boxName,tBoxStart,boxLow,tBoxEnd,boxHigh,BoxColorNOK,1, STYLE_SOLID, true);
          DrawLbl(objPrefix+"Lbl-"+TimeToStr(Time[i],TIME_DATE)+"-"+StartTime+"-"+EndTime, "NO TRADE! ("+DoubleToStr(boxExtent/pip,0)+"p)", tBoxStart+(tBoxEnd-tBoxStart)/2,boxLow, 12, "Arial Black", LevelColor, 3);
        } 
        else 
        {
          drawBox (boxName,tBoxStart,boxLow,tBoxEnd,boxHigh,BoxColorMAX,1, STYLE_SOLID, true);
          DrawLbl(objPrefix+"Lbl-"+TimeToStr(Time[i],TIME_DATE)+"-"+StartTime+"-"+EndTime, "MAX LIMIT! ("+DoubleToStr(boxExtent/pip,0)+"p)", tBoxStart+(tBoxEnd-tBoxStart)/2,boxLow, 12, "Arial Black", LevelColor, 3);
        }
      } 
      else       
            
      // box OK =====================================================
      if (boxExtent > MinBoxSizeInPips * pip) 
      { 
        drawBox (boxName,tBoxStart,boxLow,tBoxEnd,boxHigh,BoxColorOK,1, STYLE_SOLID, true);
        DrawLbl(objPrefix+"Lbl-"+TimeToStr(Time[i],TIME_DATE)+"-"+StartTime+"-"+EndTime, 
         DoubleToStr(boxExtent/pip,0)+"p"+ " (max "+MaxBoxSizeInPips+")",                              //write MaxBoxSize
         tBoxStart+(tBoxEnd-tBoxStart)/2,boxLow, 12, "Arial Black", LevelColor, 3);
        //DrawLbl(objPrefix+"Lbl-"+TimeToStr(Time[i],TIME_DATE)+"-"+StartTime+"-"+EndTime, DoubleToStr(boxExtent/pip,0)+"p", tBoxStart+(tBoxEnd-tBoxStart)/2,boxLow, 12, "Arial Black", LevelColor, 3);
      } 
      

      // draw profit/loss boxes for the session
      if (showProfitZone) {
        drawBox (objPrefix+"BuyProfitZone-" +TimeToStr(tSessionStart,TIME_DATE),tSessionStart,Up1,tSessionEnd,Up3,ProfitColor,1, STYLE_SOLID, true);
        drawBox (objPrefix+"SellProfitZone-"+TimeToStr(tSessionStart,TIME_DATE),tSessionStart,Down1,tSessionEnd,Down3,ProfitColor,1, STYLE_SOLID, true);
      }

      // draw "fib" lines for entry+stop+TP levels:
      string objname = objPrefix+"Fibo-" + tBoxEnd;
      ObjectCreate(objname,OBJ_FIBO,0,tBoxStart,Down0,tBoxStart+FibLength*60*10,Up0);
      ObjectSet(objname,OBJPROP_RAY,false);
      ObjectSet(objname,OBJPROP_LEVELCOLOR,LevelColor); 
      ObjectSet(objname,OBJPROP_FIBOLEVELS,8);
      ObjectSet(objname,OBJPROP_LEVELSTYLE,STYLE_SOLID);
      ObjectSet(objname,OBJPROP_FIRSTLEVEL+0,0.0);
      ObjectSet(objname,OBJPROP_FIRSTLEVEL+1,1.0);
      ObjectSet(objname,OBJPROP_FIRSTLEVEL+2,-TP1Factor);
      ObjectSet(objname,OBJPROP_FIRSTLEVEL+3,-TP3Factor);
      ObjectSet(objname,OBJPROP_FIRSTLEVEL+4,1+TP1Factor);
      ObjectSet(objname,OBJPROP_FIRSTLEVEL+5,1+TP3Factor);
      ObjectSet(objname,OBJPROP_FIRSTLEVEL+6,1+TP2Factor);
      ObjectSet(objname,OBJPROP_FIRSTLEVEL+7,-TP2Factor);
      ObjectSetFiboDescription(objname,0,"Entry Buy= %$");  
      ObjectSetFiboDescription(objname,1,"Entry Sell= %$");
      ObjectSetFiboDescription(objname,2,"Buy Target 1= %$  (+"+DoubleToStr(BuyTP1pips,0)+"p)");
      ObjectSetFiboDescription(objname,3,"Buy Target 3= %$  (+"+DoubleToStr(BuyTP3pips,0)+"p)");
      ObjectSetFiboDescription(objname,4,"Sell Target 1= %$  (+"+DoubleToStr(SellTP1pips,0)+"p)");
      ObjectSetFiboDescription(objname,5,"Sell Target 3= %$  (+"+DoubleToStr(SellTP3pips,0)+"p)");
      ObjectSetFiboDescription(objname,6,"Sell Target 2= %$  (+"+DoubleToStr(BuyTP2pips,0)+"p)");
      ObjectSetFiboDescription(objname,7,"Buy Target 2= %$  (+"+DoubleToStr(SellTP2pips,0)+"p)");
    }
} /* new_tick(i) */
  
//--------------------------------------------------------------------------------------
// getpip
//--------------------------------------------------------------------------------------

void getpip()
{
   if(Digits==2 || Digits==4) pip = Point;
   else if(Digits==3 || Digits==5) pip = 10*Point;
   else if(Digits==6) pip = 100*Point;
      
	if (Digits == 3 || Digits == 2) digits = 2;
	else digits = 4;
} /* getpip*/


//--------------------------------------------------------------------------------------
// RemoveObjects
//--------------------------------------------------------------------------------------

void RemoveObjects(string Pref)
{   
   int i;
   string objname = "";

   for (i = ObjectsTotal(); i >= 0; i--) {
      objname = ObjectName(i);
      if (StringFind(objname, Pref, 0) > -1) ObjectDelete(objname);
   }
} /* RemoveObjects*/


//--------------------------------------------------------------------------------------
// drawBox
//--------------------------------------------------------------------------------------

void drawBox (
  string objname,
  datetime tStart, double vStart, 
  datetime tEnd,   double vEnd,
  color c, int width, int style, bool bg
)
{
  if (ObjectFind(objname) == -1) {
    ObjectCreate(objname, OBJ_RECTANGLE, 0, tStart,vStart,tEnd,vEnd);
  } else {
    ObjectSet(objname, OBJPROP_TIME1, tStart);
    ObjectSet(objname, OBJPROP_TIME2, tEnd);
    ObjectSet(objname, OBJPROP_PRICE1, vStart);
    ObjectSet(objname, OBJPROP_PRICE2, vEnd);
  }

  ObjectSet(objname,OBJPROP_COLOR, c);
  ObjectSet(objname, OBJPROP_BACK, bg);
  ObjectSet(objname, OBJPROP_WIDTH, width);
  ObjectSet(objname, OBJPROP_STYLE, style);
} /* drawBox */


//--------------------------------------------------------------------------------------
// drawBoxOnce: draw a Box only once; if it already exists, do nothing
//--------------------------------------------------------------------------------------

void drawBoxOnce (
  string objname,
  datetime tStart, double vStart, 
  datetime tEnd,   double vEnd,
  color c, int width, int style, bool bg
)
{
  if (ObjectFind(objname) != -1) return;
  
  ObjectCreate(objname, OBJ_RECTANGLE, 0, tStart,vStart,tEnd,vEnd);
  ObjectSet(objname,OBJPROP_COLOR, c);
  ObjectSet(objname, OBJPROP_BACK, bg);
  ObjectSet(objname, OBJPROP_WIDTH, width);
  ObjectSet(objname, OBJPROP_STYLE, style);
} /* drawBoxOnce */

//--------------------------------------------------------------------------------------
// drawFixedLbl
//--------------------------------------------------------------------------------------
void drawFixedLbl(string objname, string s, int Corner, int DX, int DY, int FSize, string Font, color c, bool bg)
{
   if (ObjectFind(objname) < 0) ObjectCreate(objname, OBJ_LABEL, 0, 0, 0);
   
   ObjectSet(objname, OBJPROP_CORNER, Corner);
   ObjectSet(objname, OBJPROP_XDISTANCE, DX);
   ObjectSet(objname, OBJPROP_YDISTANCE, DY);
   ObjectSet(objname,OBJPROP_BACK, bg);      
   ObjectSetText(objname, s, FSize, Font, c);
} /* drawFixedLbl*/

//--------------------------------------------------------------------------------------
// DrawLbl
//--------------------------------------------------------------------------------------

void DrawLbl(string objname, string s, int LTime, double LPrice, int FSize, string Font, color c, int width)
{
  if (ObjectFind(objname) < 0) {
    ObjectCreate(objname, OBJ_TEXT, 0, LTime, LPrice);
  } else {
    if (ObjectType(objname) == OBJ_TEXT) {
      ObjectSet(objname, OBJPROP_TIME1, LTime);
      ObjectSet(objname, OBJPROP_PRICE1, LPrice);
    }
  }

  ObjectSet(objname, OBJPROP_FONTSIZE, FSize);
  ObjectSetText(objname, s, FSize, Font, c);
} /* DrawLbl*/



//end


