//+------------------------------------------------------------------+
//|                                                 AS-Pip Chart.mq4 |
//|                              Copyright © 2011, Amir Sherafatmand |
//|                                                                  |
//+------------------------------------------------------------------+
#property  copyright "Copyright © 2011, Amir Sherafatmand"

#property indicator_chart_window

#property indicator_buffers 6

#property  indicator_color1  Black
#property  indicator_color2  Black
#property  indicator_color3  Red
#property  indicator_color4  Lime
#property  indicator_color5  Red
#property  indicator_color6  Lime

#property indicator_width1 14
#property indicator_width2 14
#property indicator_width3 1
#property indicator_width4 1
#property indicator_width5 2
#property indicator_width6 2

double Buffer1[];
double Buffer2[];
double Buffer3[];
double Buffer4[];
double Buffer5[];
double Buffer6[];

int objUniqueId = 0;
int timeUniqueId = 0;
string objectName = "";

extern int Pips_Grid = 25;
extern bool Draw_Grid = false;
extern bool Hide_Original_Chart = true;
extern string Timeframe_Source = "M5";
extern int Active_Start_Hour = 5;
extern int Active_End_Hour = 19;

int timeFrame = 5;

int lastTime = NULL;

bool jpy = false;

int init()
{
   if(StringSubstr(Symbol(),3,3) == "JPY")jpy = true;
   
   if(Timeframe_Source == "M1")timeFrame = PERIOD_M1;
   else if(Timeframe_Source == "M5")timeFrame = PERIOD_M5;
   else if(Timeframe_Source == "M15")timeFrame = PERIOD_M15;
   else if(Timeframe_Source == "M30")timeFrame = PERIOD_M30;
   else if(Timeframe_Source == "H1")timeFrame = PERIOD_H1;
   else if(Timeframe_Source == "H4")timeFrame = PERIOD_H4;
   else if(Timeframe_Source == "D1")timeFrame = PERIOD_D1;
   else Alert("Timeframe must be either M1, M5, M15, M30, H1, H4, or D1. Higher timeframes are used for higher pips grid.");
   
   if(Pips_Grid % 100 != 0 && 100 % Pips_Grid != 0)
   {
      Pips_Grid = 25;
      Alert("Pips_Grid available sequence: 1, 2, 4, 5, 10, 20, 25, 50, 100, 200, 300...");
   }
   
   SetIndexBuffer(0,Buffer1);
   SetIndexBuffer(1,Buffer2);
   SetIndexBuffer(2,Buffer3);
   SetIndexBuffer(3,Buffer4);
   SetIndexBuffer(4,Buffer5);
   SetIndexBuffer(5,Buffer6);

   SetIndexStyle(0, DRAW_HISTOGRAM, STYLE_SOLID);
   SetIndexStyle(1, DRAW_HISTOGRAM, STYLE_SOLID);
   SetIndexStyle(2, DRAW_HISTOGRAM, STYLE_SOLID);
   SetIndexStyle(3, DRAW_HISTOGRAM, STYLE_SOLID);
   SetIndexStyle(4, DRAW_HISTOGRAM, STYLE_SOLID);
   SetIndexStyle(5, DRAW_HISTOGRAM, STYLE_SOLID);

   SetIndexEmptyValue(0,0);
   SetIndexEmptyValue(1,0);
   SetIndexEmptyValue(2,0);
   SetIndexEmptyValue(3,0);
   SetIndexEmptyValue(4,0);
   SetIndexEmptyValue(5,0);
   
   IndicatorShortName("Pip Chart");
   
   return(0);
}

int deinit()
{
   for(int i = 0; i <= objUniqueId; i++)
   {
      ObjectDelete("OBJ" + i);
   }
   for(i = 0; i < timeUniqueId; i++)
   {
      ObjectDelete("OBJTIME" + i);
   }
   ObjectDelete("ZCURRENTPRICE");
}

int start()
{
   ArrayInitialize(Buffer1,0);
   ArrayInitialize(Buffer2,0);
   ArrayInitialize(Buffer3,0);
   ArrayInitialize(Buffer4,0);
   ArrayInitialize(Buffer5,0);
   ArrayInitialize(Buffer6,0);
   
   //GET THE NUMBER OF BARS TO GO BACK IN HISTORY
   int lastBar = iBars(Symbol(),timeFrame)-1;
   if(lastBar > 10000)lastBar = 10000;
   
   //GET THE CLOSEST PHSYCOLOGICAL LEVEL AND HIGHEST/LOWEST OF ALL TIME TO DRAW PIPS GRID
   double phsycologicalLevel = NormalizeDouble(iClose(Symbol(),timeFrame,lastBar),2);
   if(jpy)phsycologicalLevel = NormalizeDouble(iClose(Symbol(),timeFrame,lastBar),0);
   double highest = iHigh(Symbol(),PERIOD_MN1,iHighest(Symbol(),PERIOD_MN1,MODE_HIGH,iBars(Symbol(),PERIOD_MN1)-1,0));
   double lowest = iLow(Symbol(),PERIOD_MN1,iLowest(Symbol(),PERIOD_MN1,MODE_LOW,iBars(Symbol(),PERIOD_MN1)-1,0));
   
   //DRAW THE PIPS GRID
   if(Draw_Grid)
   {
      objUniqueId = 0;
      for(double grid = phsycologicalLevel; grid <= highest; grid += Pips_Grid * Pip())
      {
         objectName = "OBJ" + objUniqueId;objUniqueId++;
         ObjectCreate(objectName, OBJ_HLINE, 0, 0, 0);
         ObjectSet(objectName, OBJPROP_PRICE1, grid);
         ObjectSet(objectName, OBJPROP_COLOR, 0x461919);
         ObjectSet(objectName, OBJPROP_BACK, false);
         ObjectSet(objectName, OBJPROP_STYLE, STYLE_SOLID);
         ObjectSet(objectName, OBJPROP_WIDTH, 1);
      }
      for(grid = phsycologicalLevel - Pips_Grid * Pip(); grid >= lowest; grid -= Pips_Grid * Pip())
      {
         objectName = "OBJ" + objUniqueId;objUniqueId++;
         ObjectCreate(objectName, OBJ_HLINE, 0, 0, 0);
         ObjectSet(objectName, OBJPROP_PRICE1, grid);
         ObjectSet(objectName, OBJPROP_COLOR, 0x461919);
         ObjectSet(objectName, OBJPROP_BACK, false);
         ObjectSet(objectName, OBJPROP_STYLE, STYLE_SOLID);
         ObjectSet(objectName, OBJPROP_WIDTH, 1);
      }
   }
   
   //UPDATE CURRENT PRICE
   ObjectCreate("ZCURRENTPRICE", OBJ_HLINE, 0, 0, 0);
   ObjectSet("ZCURRENTPRICE", OBJPROP_PRICE1, iClose(Symbol(),timeFrame,0));
   ObjectSet("ZCURRENTPRICE", OBJPROP_COLOR, 0xFFFFFF);
   ObjectSet("ZCURRENTPRICE", OBJPROP_BACK, false);
   ObjectSet("ZCURRENTPRICE", OBJPROP_STYLE, STYLE_SOLID);
   ObjectSet("ZCURRENTPRICE", OBJPROP_WIDTH, 1);

   //DELETE TIME SEPARATORS SO THEY CAN BE REDRAWN
   for(int i = 0; i < timeUniqueId; i++)
   {
      ObjectDelete("OBJTIME" + i);
   }
   timeUniqueId = 0;
   lastTime = 0;
   
   //FIND PHSYCOLOGICAL LEVELS ABOVE AND BELOW THE CURRENT CLOSE
   double lastPhsycologicalLevel = NULL;
   double firstPhsycologicalLevelUP = NULL;
   double firstPhsycologicalLevelDOWN = NULL;
   if(iClose(Symbol(),timeFrame,lastBar) - phsycologicalLevel < 0)
   {
      double prevPhsycologicalLevel = phsycologicalLevel;
      for(double pl = phsycologicalLevel; pl >= iClose(Symbol(),timeFrame,lastBar);)
      {
         pl -= Pips_Grid * Pip();
         
         if(pl < iClose(Symbol(),timeFrame,lastBar))
         {
            firstPhsycologicalLevelUP = prevPhsycologicalLevel;
            firstPhsycologicalLevelDOWN = pl;
            break;
         }
         prevPhsycologicalLevel = pl;
      }
   }
   if(iClose(Symbol(),timeFrame,lastBar) - phsycologicalLevel > 0)
   {
      prevPhsycologicalLevel = phsycologicalLevel;
      for(pl = phsycologicalLevel; pl <= iClose(Symbol(),timeFrame,lastBar);)
      {
         pl += Pips_Grid * Pip();
         
         if(pl > iClose(Symbol(),timeFrame,lastBar))
         {
            firstPhsycologicalLevelDOWN = prevPhsycologicalLevel;
            firstPhsycologicalLevelUP = pl;
            break;
         }
         prevPhsycologicalLevel = pl;
      }
   }
   
   //HIDE THE ORIGINAL BARS/CANDLES
   if(Hide_Original_Chart)
   {
      for(i = lastBar; i >= 0; i--) 
      {
         Buffer1[i] = iHigh(Symbol(),Period(),i) + 0.0002;
         Buffer2[i] = iLow(Symbol(),Period(),i) - 0.0002;
      }
   }
   
   //CYCLE ALL BARS AVAILABLE IN THIS TIMEFRAME SELECTED
   int reverseBarCounter = lastBar;
   int previousPos = 0;
   double BarOpenBuffer[10000];
   double BarCloseBuffer[10000];
   double BarOpenPosBuffer[10000];
   double BarClosePosBuffer[10000];
   for(i = lastBar; i >= 0; i--)
   {
      if(lastPhsycologicalLevel == NULL)
      {
         if(iClose(Symbol(),timeFrame,i) > iOpen(Symbol(),timeFrame,i))
         {
            if(iHigh(Symbol(),timeFrame,i) > firstPhsycologicalLevelUP)
            {
               lastPhsycologicalLevel = firstPhsycologicalLevelUP;
               previousPos = i;
            }
            else if(iLow(Symbol(),timeFrame,i) < firstPhsycologicalLevelDOWN)
            {
               lastPhsycologicalLevel = firstPhsycologicalLevelDOWN;
               previousPos = i;
            }
         }
         if(iClose(Symbol(),timeFrame,i) < iOpen(Symbol(),timeFrame,i))
         {
            if(iLow(Symbol(),timeFrame,i) < firstPhsycologicalLevelDOWN)
            {
               lastPhsycologicalLevel = firstPhsycologicalLevelDOWN;
               previousPos = i;
            }
            else if(iHigh(Symbol(),timeFrame,i) > firstPhsycologicalLevelUP)
            {
               lastPhsycologicalLevel = firstPhsycologicalLevelUP;
               previousPos = i;
            }
         }
      }
      if(lastPhsycologicalLevel != NULL)
      {
         double phsycologicalLevelUP = lastPhsycologicalLevel + (Pips_Grid * Pip());
         double phsycologicalLevelDOWN = lastPhsycologicalLevel - (Pips_Grid * Pip());

         if(iClose(Symbol(),timeFrame,i) > iOpen(Symbol(),timeFrame,i))
         {
            bool stop = false;
            for(;!stop;)
            {
               stop = true;
               if(iHigh(Symbol(),timeFrame,i) > phsycologicalLevelUP)
               {
                  //BULLISH BAR
                  BarOpenBuffer[reverseBarCounter] = lastPhsycologicalLevel;
                  BarCloseBuffer[reverseBarCounter] = phsycologicalLevelUP;
                  BarOpenPosBuffer[reverseBarCounter] = previousPos;
                  BarClosePosBuffer[reverseBarCounter] = i;
                  
                  previousPos = i;
                  
                  lastPhsycologicalLevel = phsycologicalLevelUP;
                  reverseBarCounter--;
            
                  phsycologicalLevelUP = lastPhsycologicalLevel + (Pips_Grid * Pip());
                  phsycologicalLevelDOWN = lastPhsycologicalLevel - (Pips_Grid * Pip());
               
                  stop = false;
               }
            }
            stop = false;
            for(;!stop;)
            {
               stop = true;
               if(iLow(Symbol(),timeFrame,i) < phsycologicalLevelDOWN)
               {
                  //BEARISH BAR
                  BarOpenBuffer[reverseBarCounter] = lastPhsycologicalLevel;
                  BarCloseBuffer[reverseBarCounter] = phsycologicalLevelDOWN;
                  BarOpenPosBuffer[reverseBarCounter] = previousPos;
                  BarClosePosBuffer[reverseBarCounter] = i;
                  
                  previousPos = i;
                  
                  lastPhsycologicalLevel = phsycologicalLevelDOWN;
                  reverseBarCounter--;
            
                  phsycologicalLevelUP = lastPhsycologicalLevel + (Pips_Grid * Pip());
                  phsycologicalLevelDOWN = lastPhsycologicalLevel - (Pips_Grid * Pip());
               
                  stop = false;
               }
            }
         }
         if(iClose(Symbol(),timeFrame,i) < iOpen(Symbol(),timeFrame,i))
         {
            stop = false;
            for(;!stop;)
            {
               stop = true;
               if(iLow(Symbol(),timeFrame,i) < phsycologicalLevelDOWN)
               {
                  //BEARISH BAR
                  BarOpenBuffer[reverseBarCounter] = lastPhsycologicalLevel;
                  BarCloseBuffer[reverseBarCounter] = phsycologicalLevelDOWN;
                  BarOpenPosBuffer[reverseBarCounter] = previousPos;
                  BarClosePosBuffer[reverseBarCounter] = i;
                  
                  previousPos = i;
                  
                  lastPhsycologicalLevel = phsycologicalLevelDOWN;
                  reverseBarCounter--;
            
                  phsycologicalLevelUP = lastPhsycologicalLevel + (Pips_Grid * Pip());
                  phsycologicalLevelDOWN = lastPhsycologicalLevel - (Pips_Grid * Pip());
               
                  stop = false;
               }
            }
            stop = false;
            for(;!stop;)
            {
               stop = true;
               if(iHigh(Symbol(),timeFrame,i) > phsycologicalLevelUP)
               {
                  //BULLISH BAR
                  BarOpenBuffer[reverseBarCounter] = lastPhsycologicalLevel;
                  BarCloseBuffer[reverseBarCounter] = phsycologicalLevelUP;
                  BarOpenPosBuffer[reverseBarCounter] = previousPos;
                  BarClosePosBuffer[reverseBarCounter] = i;
                  
                  previousPos = i;
                  
                  lastPhsycologicalLevel = phsycologicalLevelUP;
                  reverseBarCounter--;
            
                  phsycologicalLevelUP = lastPhsycologicalLevel + (Pips_Grid * Pip());
                  phsycologicalLevelDOWN = lastPhsycologicalLevel - (Pips_Grid * Pip());
               
                  stop = false;
               }
            }
         }
      }
   }
   BarOpenBuffer[reverseBarCounter] = BarCloseBuffer[reverseBarCounter+1];
   BarCloseBuffer[reverseBarCounter] = iClose(Symbol(),timeFrame,0);
   BarOpenPosBuffer[reverseBarCounter] = previousPos;
   BarClosePosBuffer[reverseBarCounter] = 0;
      
   //CREATE THE ACTUAL INDICATOR BUFFERS
   int actualBarCounter = lastBar - reverseBarCounter;
   for(i = lastBar; i >= reverseBarCounter; i--)
   {
      for(int i2 = BarOpenPosBuffer[i]; i2 >= BarClosePosBuffer[i]; i2--)
      {
         SetTimeSeparator(iTime(Symbol(),timeFrame,i2),iTime(Symbol(),Period(),actualBarCounter),iLow(Symbol(),timeFrame,i2));
      }
      Buffer5[actualBarCounter] = BarOpenBuffer[i];
      Buffer6[actualBarCounter] = BarCloseBuffer[i];
      Buffer3[actualBarCounter] = BarOpenBuffer[i];
      if(BarCloseBuffer[i] > BarOpenBuffer[i])Buffer4[actualBarCounter] = LowestPrice(BarClosePosBuffer[i],BarOpenPosBuffer[i]);
      if(BarCloseBuffer[i] < BarOpenBuffer[i])Buffer4[actualBarCounter] = HighestPrice(BarClosePosBuffer[i],BarOpenPosBuffer[i]);
      actualBarCounter--;
   }

   return(0);
}
void SetTimeSeparator(int timeCompare, int currentTime, double price)
{
   if(TimeHour(timeCompare) != TimeHour(lastTime) && TimeHour(timeCompare + 3600) == Active_Start_Hour)
   {
      objectName = "OBJTIME" + timeUniqueId;timeUniqueId++;
      ObjectCreate(objectName, OBJ_VLINE, 0, 0, 0);
      ObjectSet(objectName, OBJPROP_TIME1, currentTime);
      ObjectSet(objectName, OBJPROP_COLOR, 0x226622);
      ObjectSet(objectName, OBJPROP_BACK, true);
      ObjectSet(objectName, OBJPROP_STYLE, STYLE_DOT);
      ObjectSet(objectName, OBJPROP_WIDTH, 1);
      
      objectName = "OBJTIME" + timeUniqueId;timeUniqueId++;
      ObjectCreate(objectName, OBJ_TEXT, 0, currentTime, price - ((Pips_Grid * Pip()) * 6));
      ObjectSetText(objectName, GetDayOfWeek(TimeDayOfWeek(timeCompare)) + " " + TimeDay(timeCompare) + " " + GetMonth(TimeMonth(timeCompare)) + " " + TimeToStr(timeCompare,TIME_MINUTES), 8, "Tahoma", 0x226622);
      ObjectSet(objectName, OBJPROP_ANGLE, 90);
      ObjectSet(objectName, OBJPROP_BACK, false);
   }
   if(TimeHour(timeCompare) != TimeHour(lastTime) && TimeHour(timeCompare + 3600) == Active_End_Hour)
   {
      objectName = "OBJTIME" + timeUniqueId;timeUniqueId++;
      ObjectCreate(objectName, OBJ_VLINE, 0, 0, 0);
      ObjectSet(objectName, OBJPROP_TIME1, currentTime);
      ObjectSet(objectName, OBJPROP_COLOR, 0x000077);
      ObjectSet(objectName, OBJPROP_BACK, true);
      ObjectSet(objectName, OBJPROP_STYLE, STYLE_DOT);
      ObjectSet(objectName, OBJPROP_WIDTH, 1);
      
      objectName = "OBJTIME" + timeUniqueId;timeUniqueId++;
      ObjectCreate(objectName, OBJ_TEXT, 0, currentTime, price - ((Pips_Grid * Pip()) * 6));
      ObjectSetText(objectName, TimeToStr(timeCompare,TIME_MINUTES), 8, "Tahoma", 0x000077);
      ObjectSet(objectName, OBJPROP_ANGLE, -90);
      ObjectSet(objectName, OBJPROP_BACK, false);
   }
   lastTime = timeCompare;
}
double HighestPrice(int fromBar, int toBar)
{
   return (iHigh(Symbol(),timeFrame,iHighest(Symbol(),timeFrame,MODE_HIGH,(toBar - fromBar) + 1,fromBar)));
}
double LowestPrice(int fromBar, int toBar)
{
   return (iLow(Symbol(),timeFrame,iLowest(Symbol(),timeFrame,MODE_HIGH,(toBar - fromBar) + 1,fromBar)));
}
string GetMonth(int month)
{
   if(month == 1)return ("Jan");
   if(month == 2)return ("Feb");
   if(month == 3)return ("Mar");
   if(month == 4)return ("Apr");
   if(month == 5)return ("May");
   if(month == 6)return ("Jun");
   if(month == 7)return ("Jul");
   if(month == 8)return ("Aug");
   if(month == 9)return ("Sep");
   if(month == 10)return ("Oct");
   if(month == 11)return ("Nov");
   if(month == 12)return ("Dec");
   return ("N/A");
}
string GetDayOfWeek(int dayOfWeek)
{
   if(dayOfWeek == 0)return ("Sun");
   if(dayOfWeek == 1)return ("Mon");
   if(dayOfWeek == 2)return ("Tue");
   if(dayOfWeek == 3)return ("Wed");
   if(dayOfWeek == 4)return ("Thu");
   if(dayOfWeek == 5)return ("Fri");
   if(dayOfWeek == 6)return ("Sat");
   return ("N/A");
}
double Pip()
{
   if(!jpy)return (0.0001);
   if(jpy)return (0.01);
}