//+------------------------------------------------------------------+
//|                                               Market Profile.mq4 |
//|                                 Copyright © 2011, Carlos Cardenas|
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2011, Carlos Cardenas"
#property link      ""

#property indicator_chart_window
//+------------------------------------------------------------------+
//| Variables de entrada                                             |
//+------------------------------------------------------------------+
extern string FechaInicial            = "2011.11.11";
extern string HoraInicioDia           = "00:00"     ;
extern string HoraFinDia              = "22:30"     ;
extern int    Periodo_Open_Range      = 1           ;
extern int    Periodo_Initial_Balance = 60          ;
extern int    Periodo_Bracket         = 1           ;
extern double Value_Area              = 70          ;
extern int    colorgrafico            = 6           ;

//+------------------------------------------------------------------+
//| Variables de control Market Profile                              |
//+------------------------------------------------------------------+
datetime HoraInicio;
datetime HoraFin;

double tabladeprecios[4001,2];
int    tabladepuntos[4001,1200];

double Precio_POC=0;
double valortick;
double digitos;
double max=0;
double min=0;

int    numerodebraket;
int    POC=0;
int    periodo,mapa;
int    Numero_Elementos=0;

//+------------------------------------------------------------------+
int init()
  {
        
   GlobalVariableSet("DiaActual",0);    
   GlobalVariableSet("Bracket",0);   
   GlobalVariableSet("Findia",0);   
   GlobalVariableSet("BarraInicioDia",1);
   GlobalVariableSet("Total_Tpos",0);
       
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   	ObjectsDeleteAll(0, OBJ_RECTANGLE);
   	GlobalVariableDel("Bracket");
   	GlobalVariableDel("DiaActual");
   	GlobalVariableDel("FinDia");
   	GlobalVariableDel("BarraInicioDia");
   	GlobalVariableDel("Total_Tpos");
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   int    counted_bars=IndicatorCounted();
   
  
   if (Digits == 5) { valortick = NormalizeDouble(MarketInfo(Symbol(),MODE_TICKSIZE),Digits) * 10; digitos=4;}
	else if (Digits == 3) {valortick = NormalizeDouble(MarketInfo(Symbol(),MODE_TICKSIZE),Digits); digitos = 3;}
	else {digitos = Digits; valortick = NormalizeDouble(MarketInfo(Symbol(),MODE_TICKSIZE),Digits);}
   
   int barra = 0;
   datetime tiempo_barra = iTime(Symbol(),1,barra);
   
   while ((tiempo_barra >  StrToTime(FechaInicial)) && GlobalVariableGet("DiaActual") == 0) {
      barra++;
      tiempo_barra = iTime(Symbol(),1,barra);}
   
   
   while ((tiempo_barra <  iTime(Symbol(),1,0)) && GlobalVariableGet("DiaActual") == 0) {
   
      tiempo_barra = iTime(Symbol(),1,barra);
      HoraInicioDia = TimeToStr(StrToTime(HoraInicioDia) - ((TimeDayOfYear(StrToTime(HoraInicioDia)) - TimeDayOfYear(tiempo_barra)) * 86400));
      HoraFinDia    = TimeToStr(StrToTime(HoraFinDia) - (TimeDayOfYear(StrToTime(HoraFinDia)) - TimeDayOfYear(tiempo_barra)) * 86400);
      Procesa_Dia(barra);
      if (barra == 1) {GlobalVariableSet("DiaActual",1);}
      barra--; }   
   
   if (GlobalVariableGet("DiaActual") == 1) {Procesa_Dia(0);}
         
   return(0);
  }
//+------------------------------------------------------------------+
void Procesa_Dia(int barra)
{
   
   datetime tiempo = iTime(Symbol(), 1,barra);
   double open   = iOpen(Symbol(), 1,barra);
   double close  = iClose(Symbol(),1,barra);
   double high   = iHigh(Symbol(), 1,barra);
   
   HoraInicio = StrToTime(HoraInicioDia);
   datetime minutos = (tiempo - HoraInicio);

   
   Calcula_Periodo();
   Procesa_Inicio_Dia(barra, open);    
   if (GlobalVariableGet("FinDia") == 0){      
      Procesa_Opening_Bell(barra,tiempo, open);   
      Procesa_Open_Range(barra, tiempo, Periodo_Open_Range, minutos);
      Procesa_Initial_Balance(barra, tiempo, Periodo_Initial_Balance, minutos);  
      Procesa_Initial_Balances(barra, tiempo, Periodo_Initial_Balance, minutos);
      Procesa_Bracket(barra+1);
      Procesa_Precio(barra, tiempo, high);
      Procesa_VA(Precio_POC);
      Procesa_Fin_Dia(barra, tiempo, close);
      
      }
}         
int Calcula_Periodo()
{
   if (Period() == PERIOD_M1)  {periodo = 1;mapa=periodo + Periodo_Bracket;}
   if (Period() == PERIOD_M5)  {periodo = 5;mapa=periodo + Periodo_Bracket;}
   if (Period() == PERIOD_M15) {periodo = 15;mapa=periodo + Periodo_Bracket - 5;}
   if (Period() == PERIOD_M30) {periodo = 30;mapa=periodo + Periodo_Bracket - 16;}
   if (Period() == PERIOD_H1)  {periodo = 60;mapa=periodo + Periodo_Bracket - 46;}
   if (Period() == PERIOD_H4)  {periodo = 120;mapa=periodo + Periodo_Bracket - 80;}
   if (Period() == PERIOD_D1)  {periodo = 120;}
   
   return(periodo);
}

bool Procesa_Inicio_Dia(int barra, double open)
{
   if (iTime(Symbol(),1,barra) ==  StrToTime(HoraInicioDia))  {
      ArrayInitialize( tabladeprecios, 0); 
      ArrayInitialize( tabladepuntos, 0);
      GlobalVariableSet("FinDia",0);
      GlobalVariableSet("Bracket",0);
      GlobalVariableSet("BarraInicioDia",barra);
      POC = 0;
      Numero_Elementos = ArrayRange(tabladeprecios, 0); 
      double precio = NormalizeDouble(open,digitos) + (MathAbs(Numero_Elementos/2) * valortick);

      for (int y=0; y < Numero_Elementos ;y++){
         tabladeprecios[y,0] = precio;
         precio -= valortick;}  }      
}

bool Procesa_Opening_Bell(int barra,datetime tiempo, double open)
{
   if (iTime(Symbol(),1,barra) ==  StrToTime(HoraInicioDia))  {
      dibujarectangulo("OpeningBell" + TimeDayOfYear(tiempo),RoyalBlue,
            iTime(Symbol(), 1,barra+(periodo*16)), open, tiempo,open-valortick );
      GlobalVariableSet("Bracket",1);}
      //Print(TimeToStr(iTime(Symbol(),1,barra)));
      //Print(HoraInicioDia);}   
}
bool Procesa_Open_Range(int barra,datetime tiempo, int periodos, int minutos)
{
   if (iTime(Symbol(),1,barra) >=  StrToTime(HoraInicioDia) &&
   iTime(Symbol(),1,barra) <  (StrToTime(HoraInicioDia) + (60 * periodos))) {
     
      max= iHigh(Symbol(),1,iHighest(NULL,1,MODE_HIGH,TimeMinute(minutos)+1,barra)) ;
      min= iLow(Symbol(),1,iLowest(NULL,1,MODE_LOW,TimeMinute(minutos)+1,barra)) ;
      dibujarectangulo("OpenRange" + TimeDayOfYear(tiempo),Blue,HoraInicio-(periodo*120), max, HoraInicio+(periodo), min);}   
}
bool Procesa_Initial_Balance(int barra, datetime tiempo, int periodos, int minutos)
{
   if (iTime(Symbol(),1,barra) >=  StrToTime(HoraInicioDia) &&
       iTime(Symbol(),1,barra) <  (StrToTime(HoraInicioDia) + (60 * periodos))) {
      
      max= iHigh(Symbol(),1,iHighest(NULL,1,MODE_HIGH,TimeMinute(minutos)+1,barra)) ;
      min= iLow(Symbol(),1,iLowest(NULL,1,MODE_LOW,TimeMinute(minutos)+1,barra)) ;
      dibujarectangulo("InitialBalance" + TimeDayOfYear(tiempo),Red,HoraInicio-(periodo*120), max, HoraInicio, min);}  
}
bool Procesa_Initial_Balances(int barra, datetime tiempo, int periodos,int minutos)
{
   if (iTime(Symbol(),1,barra) ==  (StrToTime(HoraInicioDia) + (60 * periodos)))  {
     
     double maxIb1 = iHigh(Symbol(),1,iHighest(NULL,1,MODE_HIGH,Periodo_Initial_Balance,barra)) ;
     double minIb1 = iLow(Symbol(),1,iLowest(NULL,1,MODE_LOW,Periodo_Initial_Balance,barra)) ;
     double maxIb1_5 = maxIb1 +((maxIb1 - minIb1)/2);
     double minIb1_5 =  minIb1 -((maxIb1 - minIb1)/2);
     double maxIb2 = maxIb1_5 +((maxIb1 - minIb1)/2);
     double minIb2 = minIb1_5 -((maxIb1 - minIb1)/2);
     double maxIb3 = maxIb2 +((maxIb1 - minIb1));
     double minIb3 = minIb2 -((maxIb1 - minIb1));
     
     dibujarectangulo("InitialBalance" + TimeDayOfYear(tiempo),Red,HoraInicio-(periodo*120), maxIb1, HoraInicio+(periodo), minIb1);
     dibujarectangulo("InitialBalance1.5h" + TimeDayOfYear(tiempo),Yellow,HoraInicio-(periodo*120), maxIb1_5, HoraInicio+(periodo), maxIb1);
     dibujarectangulo("InitialBalance1.5l" + TimeDayOfYear(tiempo),Yellow,HoraInicio-(periodo*120), minIb1,HoraInicio+(periodo), minIb1_5);
     dibujarectangulo("InitialBalance2h" + TimeDayOfYear(tiempo),Green,HoraInicio-(periodo*120), maxIb2, HoraInicio+(periodo),maxIb1_5);
     dibujarectangulo("InitialBalance2l" + TimeDayOfYear(tiempo),Green,HoraInicio-(periodo*120), minIb1_5, HoraInicio+(periodo), minIb2);
     dibujarectangulo("InitialBalance3h" + TimeDayOfYear(tiempo),Chocolate,HoraInicio-(periodo*120), maxIb3, HoraInicio+(periodo),maxIb2);
     dibujarectangulo("InitialBalance3l" + TimeDayOfYear(tiempo),Chocolate,HoraInicio-(periodo*120), minIb2, HoraInicio+(periodo), minIb3);
    }
}

bool Procesa_Bracket(int barra)
{
   if (GlobalVariableCheck("Bracket") ) {
      if (iTime(Symbol(),1,barra) >  (StrToTime(HoraInicioDia) + (Periodo_Bracket * GlobalVariableGet("Bracket") * 60))) {
      
      datetime dd = StrToTime(HoraInicioDia) + (Periodo_Bracket * GlobalVariableGet("Bracket") * 60);
      double x = GlobalVariableGet("Bracket");
      x++;
      GlobalVariableSet("Bracket",x);}
      //Print("Braket ",GlobalVariableGet("Bracket"));        
      //Print("dia :",TimeDayofYearOfYear(dd)," hora :",TimeHour(dd)," minuto :",TimeMinute(dd)," segundos ",TimeSeconds(dd)); }
      }
}


void Procesa_Precio(int barra, datetime tiempo,double high)
{
   double max_precio = NormalizeDouble(high,digitos);
   double min_precio = NormalizeDouble(iLow(Symbol(), 1,barra),digitos);
   int    Bracket    = GlobalVariableGet("Bracket");

   while (max_precio > min_precio)
   {

      int precio = ArrayBsearch( tabladeprecios, max_precio, Numero_Elementos, 0, MODE_DESCEND);
      int ind=0;
      int desplazamiento = 0;

      while (tabladepuntos[precio,ind] != Bracket)
      {
         if(tabladepuntos[precio,ind] == Bracket ) { break;}
         if(tabladepuntos[precio,ind] == 0 ) {
         tabladepuntos[precio,ind] = Bracket;
         tabladeprecios[precio,1] +=1;
         int tot_tpo = GlobalVariableGet("Total_Tpos") + 1;
         GlobalVariableSet("Total_Tpos",tot_tpo);
         color colorgrafico = pintacolor(((barra-1) - GlobalVariableGet("BarraInicioDia"))  );
         dibujarectangulo("Punto"+tiempo+Bracket+precio,colorgrafico,StrToTime(HoraInicioDia)+(desplazamiento*60),
                            tabladeprecios[precio,0],StrToTime(HoraInicioDia)+(desplazamiento+mapa)*60,tabladeprecios[precio,0]-valortick);
         break;}
         desplazamiento += mapa ;
         ind++;
      }
      
      max_precio -= valortick;
      
      // Comprueba el POC vara redibujarlo si ha cambiado //
      if (ind > POC) { 
          POC = ind; 
          Precio_POC = precio;
          dibujarectangulo("POC"+TimeDayOfYear(tiempo),White,StrToTime(HoraInicioDia),
              tabladeprecios[precio,0],StrToTime(HoraInicioDia)+(desplazamiento+mapa)*60,tabladeprecios[precio,0]-valortick);
          }
      

   }
    
}  
      
void Procesa_VA(int precio)
{
   
   int ind_alto=1,ind_bajo=1, vol_tpo=0;
   int tot_tpo = GlobalVariableGet("Total_Tpos") * (Value_Area / 100);

   vol_tpo += tabladeprecios[precio,1];
   
   while (tot_tpo > vol_tpo )
   {  
      if(tabladeprecios[precio-ind_bajo,1] == 0 && tabladeprecios[precio+ind_alto,1] == 0) {break;}
      if(tabladeprecios[precio+ind_alto,1] != 0) {vol_tpo += tabladeprecios[precio+ind_alto,1];ind_alto++;}
      if(tabladeprecios[precio-ind_bajo,1] != 0) {vol_tpo += tabladeprecios[precio-ind_bajo,1];ind_bajo++;}
   }
   
   dibujarectangulo("VA"+TimeDayOfYear(StrToTime(HoraInicioDia)),White,StrToTime(HoraInicioDia)-mapa,
              tabladeprecios[precio+ind_alto,0],StrToTime(HoraInicioDia)+(POC*mapa)*60,tabladeprecios[precio-ind_bajo,0]);           
   ObjectSet("VA"+TimeDayOfYear(StrToTime(HoraInicioDia)), OBJPROP_BACK, false); 
   ObjectSet("VA"+TimeDayOfYear(StrToTime(HoraInicioDia)), OBJPROP_STYLE, STYLE_DOT);  
        
}                         
bool Procesa_Fin_Dia(int barra, datetime tiempo,double close)
{
   string inicio_dia_siguiente = TimeToStr(StrToTime(HoraInicioDia) + 86400);
 
   if ((iTime(Symbol(),1,barra-1) >=  StrToTime(HoraFinDia)) && (GlobalVariableGet("FinDia") == 0))  {
      GlobalVariableSet("FinDia",1);
      GlobalVariableSet("Bracket",0);
      GlobalVariableSet("Total_Tpos",0);
      
      // Dibujamos el Settlement //
      int settlement = GlobalVariableGet("BarraInicioDia");
       dibujarectangulo("Settlement" + TimeDayOfYear(tiempo),Red,iTime(Symbol(), 1,settlement+(periodo*16)),
          close, iTime(Symbol(), 1,settlement),close-valortick ); } 
}
void dibujarectangulo(string name, color colores, datetime tiempo1,double precio1,datetime tiempo2,double precio2)
{
   ObjectDelete(name);
   ObjectCreate(name, OBJ_RECTANGLE, 0, tiempo1, precio1, tiempo2, precio2);
   ObjectSet(name, OBJPROP_COLOR, colores);
   ObjectSet(name, OBJPROP_STYLE, STYLE_SOLID);
   ObjectSet(name, OBJPROP_BACK, true);
}

color pintacolor(int barra)
{
   int colores, desplazamiento1, desplazamiento2;
   
   switch(colorgrafico)
	{
		case 0:
			colores = DarkBlue;
			desplazamiento1 = 0x020000;
			desplazamiento2 = 0x000002;
		break;
		case 1:
			colores = DarkRed;
			desplazamiento1 = 0x000002;
			desplazamiento2 = 0x020202;
		break;
		case 2:
			colores = DarkGreen;
			desplazamiento1 = 0x000200;
			desplazamiento2 = 0x020000;
		break;
		case 3:
			colores = DarkOrange;
			desplazamiento1 = 0x000200;
			desplazamiento2 = 0x020000;
		break;
		case 4:
			colores = DarkSlateGray;
			desplazamiento1 = 0x020000;
			desplazamiento2 = 0x000002;
		break;
		case 5:
			colores = DarkOrchid;
			desplazamiento1 = 0x000002;
			desplazamiento2 = 0x000200;
			break;		
		case 6:
			colores = Aquamarine;
			desplazamiento1 = 0x000002;
			desplazamiento2 = 0x000400;
		break;
		case 7:
			colores = DimGray;
			desplazamiento1 = 0x020000;
			desplazamiento2 = 0x000002;
		break;
	}
	
   colores += (barra / 15) * (desplazamiento1 /2);
   colores -= (barra / 15) * (desplazamiento2 /2);

return(colores);
}



