
#property indicator_chart_window
#property strict

extern bool    DisplayText       = false;
extern bool    FullBoxDisplay    = false;
extern bool    PartialBoxDisplay = true;
extern bool    ColorBoxBackground= true;
extern string  symbol            = "";
extern int     boxbarperiods     = 16;
extern int     boxbarmode        = MODE_EMA;
extern int     boxbaroffset      = 0;
extern string  TimeFrame         = "Current time frame";
extern int     MoveHorizontal    = 0;
extern int     MoveVertical      = 0;
extern int     Corner            = 0;
extern string  texttype          = "Arial Black";
extern int     textsize          = 11; 
extern string  linetypes         = "None";   //"ATR,ATR";
extern string  linepositions     = "1.5,-1.5";
extern string  linestyles        = "0,0";
extern string  linewidths        = "2,2";
extern string  linecolors        = "Aqua,Crimson";
int     boxstyle          = 0;
int     boxwidth          = 1;
color   boxcolor          = Yellow;
bool    boxcolorfill      = false;
extern bool    ShowGraphics      = false;      
string         buffername        = "BreakOut Box: ";
      
double   Trend[], PerCent[1], aHigh[], aLow[], aClose[];
int      Lines=-1,Style[], Width[];
double   Position[];
string   Type[], Color[];
double   AvgHighs, AvgLows, Top, Bottom, TrendHigh, TrendLow;
datetime LastTime;
string indicatorFileName;
int    timeFrame;
color  TrendColor[]={clrRed,clrCrimson,clrMaroon,clrWhite,clrGreen,clrLime,clrBlue};
string TrendText[]={"Strong Breakout DOWN","Breakout DOWN","Trending DOWN","Range Bound","Trending UP","Breakout UP","Strong Breakout UP"};

int init()
{
   indicatorFileName = WindowExpertName();
   timeFrame         = stringToTimeFrame(TimeFrame);
   
   if (symbol=="") symbol=Symbol(); 
   if(Symbol() != symbol)  FullBoxDisplay=false;
   
   IndicatorShortName("BreakOut Box"); 
   IndicatorBuffers(2);
   SetIndexStyle(0, DRAW_NONE); SetIndexBuffer(0, Trend); SetIndexLabel(0, NULL);
   SetIndexStyle(1, DRAW_NONE); SetIndexBuffer(1, PerCent); SetIndexLabel(1, NULL);
      
   if(ShowGraphics)      {
      int xpos=5;    int ypos=5;
      Create_Labels("AAA-Panel01", xpos+1,ypos- 4, "gggggg", 40, "Webdings", Black);
      Create_Labels("AAA-Panel02", xpos+1,ypos+34, "gggggg", 40, "Webdings", Black);
      Create_Labels("AAA-Panel03", xpos+6,ypos+ 1, "gggggg", 38, "Webdings", Gray);
      Create_Labels("AAA-Panel04", xpos+6,ypos+34, "gggggg", 38, "Webdings", Gray);
      }
      
   if(linetypes == "" || linetypes == "None") {Lines=-1;return(0);}
     
   Lines=sParse_Tokens(linetypes, Type);
   dParse_Tokens(linepositions, Position);
   
   iParse_Tokens(linestyles, Style);
   iParse_Tokens(linewidths, Width); 
   sParse_Tokens(linecolors, Color);
   
   Delete_Objects(buffername);  
   return(0);
}

int deinit()  {Delete_Objects(buffername); return(0);}
double sumcalc(int aboxbarsize,double& a[])
{
   double sumlength=0.; 
   int i;
   for(i=boxbaroffset;i<aboxbarsize+boxbaroffset;i++) sumlength+=a[i];
   return(sumlength/aboxbarsize);
}
int start()  { 
   if (timeFrame != Period())   {
         double dummy = iCustom(NULL,timeFrame,indicatorFileName,"",DisplayText,FullBoxDisplay,PartialBoxDisplay,ColorBoxBackground,symbol,boxbarperiods,boxbarmode,boxbaroffset,timeFrame,MoveHorizontal,MoveVertical,Corner,texttype,textsize,linetypes,linepositions,linestyles,linewidths,linecolors,ShowGraphics,0,0);                                                          
         return(0);
   }      
      if(iTime(symbol,0,0) != LastTime)         {
         ArrayCopySeries(aHigh,MODE_HIGH,symbol);
         ArrayCopySeries(aLow ,MODE_LOW ,symbol);
         ArrayCopySeries(aClose ,MODE_CLOSE ,symbol);
         AvgHighs=sumcalc(boxbarperiods,aHigh); 
         AvgLows=sumcalc(boxbarperiods,aLow);
         
         if(boxbaroffset != 0)   boxbaroffset+=1;
         Top=0.;
         Bottom=99999.;
 
         for(int i=1+boxbaroffset;i<=boxbarperiods+boxbaroffset;i++)            {
            if(aHigh[i]>Top)      Top=aHigh[i];
            if(aLow[i] <Bottom )  Bottom=aLow[i];
            }
         LastTime=iTime(symbol,0,0);
         } 
         
         TrendHigh=Top-(Top-AvgHighs)/2.;
         TrendLow=Bottom -(Bottom-AvgLows)/2.;
         double Height=Top-Bottom;
         double AvgSize=AvgHighs-AvgLows;
         Trend[0]=Determine_Trend(aClose);
         
         PerCent[0]=100.0*(aClose[boxbaroffset]-(Top+Bottom)/2.0)/((Top-Bottom)/2.0); 
         
         if(DisplayText)   {
            int trendindex=(int)(Trend[0]);
            string state = " "+DoubleToStr(PerCent[0],2)+ "%";
            Create_Labels(buffername+symbol+"TBack", 0,0, "ggggggggggggggg",textsize+3,"Webdings",C'40,50,60');
            Create_Labels(buffername+symbol+"Trend", 1,1, timeFrameToString(Period())+" "+symbol+" "+TrendText[trendindex]+state,textsize,texttype,TrendColor[trendindex]);
            //Print(symbol,"<",state,">",trendindex," ",Trend[0]," ",MoveVertical," ",aClose[0]," ",iClose(symbol,0,0)," ",Top," ",Bottom,  ":: ",rangecolor," ",TrendColor[3]," ",TrendColor[trendindex]);
         }
         
      if(PartialBoxDisplay)   {
         double x0=Time[0]+Time[0]-Time[1],
                x1=Time[0]+Time[0]-Time[2];
         double PriceMax=WindowPriceMax(0),
                PriceMin=WindowPriceMin(0);
         //Print("here 0 ",TimeToStr((datetime)x0,TIME_DATE|TIME_MINUTES)," ",TimeToStr((datetime)x1,TIME_DATE|TIME_MINUTES)," ",PriceMax," ",PriceMin);       
         if(ColorBoxBackground)  {  
            Create_Block("StrongBreakOutUp",x0,PriceMax,x1,Top,3,TrendColor[6],TrendColor[6]);
            Create_Block("BreakoutUp",x0,Top,x1,TrendHigh,3,TrendColor[5],TrendColor[5]);
            Create_Block("TrendingUp",x0,TrendHigh,x1,AvgHighs,3,TrendColor[4],TrendColor[4]);
            Create_Block("RangeBound" ,x0,AvgHighs,x1,AvgLows,3,TrendColor[3],TrendColor[3]);
            Create_Block("TrendingDown" ,x0,AvgLows,x1,TrendLow,3,TrendColor[2],TrendColor[2]);
            Create_Block("BreakOutDown" ,x0,TrendLow,x1,Bottom,3,TrendColor[1],TrendColor[1]);
            Create_Block("StrongBreakOutDown" ,x0,Bottom,x1,PriceMin,3,TrendColor[0],TrendColor[0]);
         }
         else  {
            Create_Block("StrongBreakOutUp",x0,PriceMax,x1,Top,3,TrendColor[6]);
            Create_Block("BreakoutUp",x0,Top,x1,TrendHigh,3,TrendColor[5]);
            Create_Block("TrendingUp",x0,TrendHigh,x1,AvgHighs,3,TrendColor[4]);
            Create_Block("RangeBound" ,x0,AvgHighs,x1,AvgLows,3,TrendColor[3]);
            Create_Block("TrendingDown" ,x0,AvgLows,x1,TrendLow,3,TrendColor[2]);
            Create_Block("BreakOutDown" ,x0,TrendLow,x1,Bottom,3,TrendColor[1]);
            Create_Block("StrongBreakOutDown" ,x0,Bottom,x1,PriceMin,3,TrendColor[0]);
         }
      }
        
   if(FullBoxDisplay)   {
        Create_BlockRange("Block-Range");
        Createline("Avg-High", AvgHighs,TrendColor[3],boxwidth+1);
        Createline("Avg-Low",  AvgLows,TrendColor[3],boxwidth+1);
        Createline("TrendHigh",TrendHigh,TrendColor[5],boxwidth+1);
        Createline("TrendLow", TrendLow,TrendColor[1],boxwidth+1);
   }                   
   if(ShowGraphics)      {
      Create_Labels("AAB-Panel01",  18,70, "BreakOut Box", 12, "Arial Black", White);
      Create_Labels("AAB-Panel0100",168,70, "Trend "+DoubleToStr(Trend[0],0), 12, "Arial Black", White);
      
      Create_Labels("AAB-Panel010", 15,55, "T   "+DoubleToStr(Top,Digits),    10, "Arial Black", White);
      Create_Labels("AAB-Panel011", 120,55,"B   "+DoubleToStr(Bottom,Digits), 10, "Arial Black", White);
      Create_Labels("AAB-Panel012", 215,55,"H   "+DoubleToStr(Height,Digits), 10, "Arial Black", White);
      
      Create_Labels("AAB-Panel013", 15,40, "AH "+DoubleToStr(AvgHighs,Digits), 10, "Arial Black", White);
      Create_Labels("AAB-Panel014", 105,40, "AL "+DoubleToStr(AvgLows,Digits), 10, "Arial Black", White);
      Create_Labels("AAB-Panel015", 200,40, "AS "+DoubleToStr(AvgSize,Digits), 10, "Arial Black", White);
      
      Create_Labels("AAB-Panel016", 15,25, "AM "+DoubleToStr(Height/AvgSize,Digits), 10, "Arial Black", White);
      }
   return(0);
  }
int Determine_Trend(double& aclose[])   {
   if (aclose[boxbaroffset] >= Top)                                           return(6);
   if (aclose[boxbaroffset] >= TrendHigh && aclose[boxbaroffset] < Top)       return(5);
   if (aclose[boxbaroffset] >= AvgHighs &&  aclose[boxbaroffset] < TrendHigh) return(4);
   if (aclose[boxbaroffset] <  AvgHighs &&  aclose[boxbaroffset] > AvgLows)   return(3);
   if (aclose[boxbaroffset] <= AvgLows  &&  aclose[boxbaroffset] > TrendLow)  return(2);
   if (aclose[boxbaroffset] <= TrendLow &&  aclose[boxbaroffset] > Bottom)    return(1);
   if (aclose[boxbaroffset] <= Bottom)                                        return(0);
   return(0);
}      
void  Create_BlockRange(string buffer) {  
   buffer=buffername+buffer;
   ObjectDelete(buffer);
   ObjectCreate(buffer, OBJ_RECTANGLE,  0, 0, 0, 0, 0);
   ObjectSet   (buffer, OBJPROP_STYLE,  boxstyle);
   ObjectSet   (buffer, OBJPROP_WIDTH,  boxwidth);
   ObjectSet   (buffer, OBJPROP_COLOR,  boxcolor);
   ObjectSet   (buffer, OBJPROP_BACK,   boxcolorfill);
   ObjectSet   (buffer, OBJPROP_TIME1 , Time[boxbarperiods+boxbaroffset+1]);
   ObjectSet   (buffer, OBJPROP_PRICE1, Top);
   ObjectSet   (buffer, OBJPROP_TIME2 , Time[boxbaroffset]+Time[boxbaroffset]-Time[boxbaroffset+1]);
   ObjectSet   (buffer, OBJPROP_PRICE2, Bottom);
}
void  Create_Block(string buffer, double x0, double y0,double x1, double y1, int boxWidth, color cBlock, color FillColor=clrNONE)  {
   buffer=buffername+buffer;
   ObjectDelete(buffer);
   ObjectCreate(buffer, OBJ_RECTANGLE,  0, 0, 0, 0, 0);
   ObjectSet   (buffer, OBJPROP_STYLE,  boxstyle);
   ObjectSet   (buffer, OBJPROP_WIDTH,  boxWidth);
   ObjectSet   (buffer, OBJPROP_COLOR,  cBlock);
   ObjectSet   (buffer, OBJPROP_BACK,   boxcolorfill);
   ObjectSet   (buffer, OBJPROP_TIME1 , x0);
   ObjectSet   (buffer, OBJPROP_PRICE1, y0);
   ObjectSet   (buffer, OBJPROP_TIME2 , x1);
   ObjectSet   (buffer, OBJPROP_PRICE2, y1);
   if(FillColor != clrNONE)   ObjectSetInteger(0,buffer,OBJPROP_FILL,FillColor);   
}              
color Colors(string aColor)
{
   if(aColor == "Red")     return(Red);
   if(aColor == "Green")   return(Green);
   if(aColor == "Aqua")    return(Aqua);
   if(aColor == "Lime")    return(Lime);
   if(aColor == "White")   return(White);
   if(aColor == "Yellow")  return(Yellow);
   if(aColor == "Blue")    return(Blue);
   return(White);
}
int Calculate_Position(int line)
{
   if(Type[line] == "ATR")
      {
      double atr=iATR(NULL,0,boxbarperiods,0);///(Point*100.);
      
      if(Position[line]>=0.)     return((int)(100+atr*Position[line]));
      else                       return((int)(atr*Position[line]));
      }
   if(Type[line] == "DEV")
      {
      double AvgClose=iMA(NULL,0,boxbarperiods,0,boxbarmode,PRICE_CLOSE,0)/(Point*100.);
      //double deviation = iDeviation(Close,boxbarperiods,AvgClose,1);
      //if(Position[line]>=0.)     return(100+deviation*Position[line]);
      //else                       return(deviation*Position[line]);
      } 
   return((int)Position[line]);     
}
void  Draw_Line(int line)
{
   string buffer=buffername+"Line"+(string)line;
   ObjectDelete(buffer);
   ObjectCreate(buffer, OBJ_TREND,   0, 0, 0);
   ObjectSet   (buffer, OBJPROP_STYLE,  Style[line]);
   ObjectSet   (buffer, OBJPROP_WIDTH,  Width[line]);
   ObjectSet   (buffer, OBJPROP_COLOR,  Colors(Color[line]));
   ObjectSet   (buffer, OBJPROP_RAY,    0);
   ObjectSet   (buffer, OBJPROP_BACK,   boxcolorfill);
   ObjectSet   (buffer, OBJPROP_TIME1 , Time[boxbarperiods+boxbaroffset+1]);
   
   int position=Calculate_Position(line);
   ObjectSet   (buffer, OBJPROP_PRICE1, Bottom+((Top-Bottom)/100)*position);
   ObjectSet   (buffer, OBJPROP_TIME2 , Time[boxbaroffset]+Time[boxbaroffset]-Time[boxbaroffset+1]);
   ObjectSet   (buffer, OBJPROP_PRICE2, Bottom+((Top-Bottom)/100)*position);
} 
int Count_Tokens(string Input)
{
   int cnt,pos=0;
   while(pos>-1)
      {
      pos=StringFind(Input,",",pos+1);
      if(pos>-1)      cnt+=1;  
      }
      cnt+=1;
   return(cnt);
}
int iParse_Tokens(string Input, int& Output[])
{
   int Tokens=Count_Tokens(Input); 
   if(Input=="") return(-1);
   ArrayResize(Output,Tokens);
   
   int i,start=0,stop=-1;
   for(i=0;i<Tokens-1;i++)
      {
      stop=StringFind(Input,",",stop+1);
      Output[i]=StrToInteger(StringSubstr(Input,start,stop-start));
      start=stop+1;
      }
   Output[i]=StrToInteger(StringSubstr(Input,start));
   return(Tokens);  
}   
int sParse_Tokens(string Input, string& Output[])
{
   int Tokens=Count_Tokens(Input); 
   if(Input=="") return(-1);
   ArrayResize(Output,Tokens);
   
   int i,start=0,stop=-1;
   for(i=0;i<Tokens-1;i++)
      {
      stop=StringFind(Input,",",stop+1);
      Output[i]=StringSubstr(Input,start,stop-start);
      start=stop+1;
      }
   Output[i]=StringSubstr(Input,start);
   return(Tokens);  
} 
int dParse_Tokens(string Input, double& Output[])
{
   int Tokens=Count_Tokens(Input); 
   if(Input=="") return(-1);
   ArrayResize(Output,Tokens);
   
   int i,start=0,stop=-1;
   for(i=0;i<Tokens-1;i++)
      {
      stop=StringFind(Input,",",stop+1);
      Output[i]=StrToDouble(StringSubstr(Input,start,stop-start));
      start=stop+1;
      }
   Output[i]=StrToDouble(StringSubstr(Input,start));
   return(Tokens);  
} 
double iDeviation(double& array[], double period, double ma, int i)
{
   double sum = 0.00;
      for(int k=0; k<period; k++) sum += (array[i+k]-ma)*(array[i+k]-ma);
   return(MathSqrt(sum/period));
}


 void Createline(string buffer, double start,  color aColor, int width)
   {
   buffer=buffername+buffer;
   ObjectDelete(buffer);
   ObjectCreate(buffer, OBJ_TREND,   0, 0, 0);
   ObjectSet   (buffer, OBJPROP_STYLE,  boxstyle);
   ObjectSet   (buffer, OBJPROP_WIDTH,  width);
   ObjectSet   (buffer, OBJPROP_COLOR,  aColor); 
   ObjectSet   (buffer, OBJPROP_RAY,    0);
   ObjectSet   (buffer, OBJPROP_BACK,   boxcolorfill);
   ObjectSet   (buffer, OBJPROP_TIME1 , Time[boxbarperiods+boxbaroffset+1]);
   ObjectSet   (buffer, OBJPROP_PRICE1, start);
   ObjectSet   (buffer, OBJPROP_TIME2 , Time[boxbaroffset]+Time[boxbaroffset]-Time[boxbaroffset+1]);
   ObjectSet   (buffer, OBJPROP_PRICE2, start);
   } 
   
void Create_Labels( string buffer, int x, int y,  string Text, int FontSize, string Font, color aColor ) {
   buffer=buffername+buffer;
   ObjectDelete(buffer);
   ObjectCreate( buffer, OBJ_LABEL, 0, 0, 0 );
   ObjectSet( buffer, OBJPROP_CORNER, Corner);
   ObjectSet( buffer, OBJPROP_XDISTANCE,x+MoveHorizontal);
   ObjectSet( buffer, OBJPROP_YDISTANCE,y+MoveVertical);
   ObjectSetText(buffer, Text, FontSize, Font, aColor);
 } 
    void Delete_Objects(string buffer)
{
   int total,i,buffersize;
   buffersize=StringLen(buffer);
   string name,prefix;
   total=ObjectsTotal();
   for(i=total;i>=0;i--)
      {
      name=ObjectName(i);
      prefix=StringSubstr(name,0,buffersize);
      if(prefix==buffer)         ObjectDelete(name);
      }
   GetLastError();

}       

//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//

string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,15,30,60,240,1440,10080,43200};

int stringToTimeFrame(string tfs)
{
   StringToUpper(tfs);
   for (int i=ArraySize(iTfTable)-1; i>=0; i--)
         if (tfs==sTfTable[i] || tfs==""+(string)iTfTable[i]) return(MathMax(iTfTable[i],Period()));
                                                      return(Period());
}
string timeFrameToString(int tf)
{
   for (int i=ArraySize(iTfTable)-1; i>=0; i--) 
         if (tf==iTfTable[i]) return(sTfTable[i]);
                              return("");
}
