//+------------------------------------------------------------------+
//|                                             Point of balance.mq4 |
//|                                                           mladen |
//|                                                                  |
//| Developed by Walter Downs                                        |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"

#property indicator_separate_window
#property indicator_buffers    2
#property indicator_color1     LimeGreen
#property indicator_color2     Red
#property indicator_width1     2
#property indicator_width2     2
#property indicator_level1     0.00
#property indicator_levelcolor DimGray

//
//
//
//
//

extern string TimeFrame   = "Current time frame";
extern int    Length      = 12;
extern int    Level       = 10;
extern int    Price       = PRICE_CLOSE;
extern bool   Interpolate = true;

double buffer1[];
double buffer2[];
double buffer3[];
double buffer4[];
double buffer5[];
double buffer6[];
double buffer7[];
double buffer8[];

//
//
//
//
//

string indicatorFileName;
int    timeFrame;
bool   returnBars;
bool   calculateValue;
bool   calculateBase;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int init()
{
      IndicatorBuffers(8);
         SetIndexBuffer(0, buffer1);
         SetIndexBuffer(1, buffer2);
         SetIndexBuffer(2, buffer3);
         SetIndexBuffer(3, buffer4);
         SetIndexBuffer(4, buffer5);
         SetIndexBuffer(5, buffer6);
         SetIndexBuffer(6, buffer7);
         SetIndexBuffer(7, buffer8);
         
         //
         //
         //
         //
         //
         
         indicatorFileName = WindowExpertName();
         calculateValue    = (TimeFrame=="calculateValue"); if (calculateValue) return(0);
         returnBars        = (TimeFrame=="returnBars");     if (returnBars)     return(0);
         timeFrame         = stringToTimeFrame(TimeFrame);
 
   //
   //
   //
   //
   //

   SetIndexStyle(0,DRAW_HISTOGRAM); SetIndexLabel(0,"Balance up");
   SetIndexStyle(1,DRAW_HISTOGRAM); SetIndexLabel(1,"Balance down");
   IndicatorShortName(timeFrameToString(timeFrame)+" Point of balance ("+Length+","+Level+")");
   return(0);
}
int deinit()
{
   return(0);
}


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int start()
{
   int counted_bars = IndicatorCounted();
      if(counted_bars<0) return(-1);
      if(counted_bars>0) counted_bars--;
         int limit = Bars-counted_bars;
         if (returnBars) { buffer1[0] = limit+1; return(0); }


   //
   //
   //
   //
   //
   
      if (calculateValue) { CalculateData(limit); return(0); }
   
   //
   //
   //
   //
   //
   
   if (timeFrame==Period())
   {
      for(int i = limit; i >= 0; i--)
      {
         buffer4[i] = iMA(NULL,0,1,0,MODE_SMA,Price,i);
         buffer3[i] = iCustom(NULL,0,indicatorFileName,"calculateValue",Length,Level,Price,0,i);
         buffer2[i] = EMPTY_VALUE;
         buffer1[i] = EMPTY_VALUE;

         //
         //
         //
         //
         //
               
         double average = buffer3[i]/Level;
         double hiPrice = hiValue(buffer4,i);
         double loPrice = loValue(buffer4,i);
         double value   = 0.00;

            if (hiPrice!=loPrice) value = 100*(buffer4[i] - average) / (hiPrice - loPrice);
            if (value > 0) buffer1[i] = value;
            if (value < 0) buffer2[i] = value;
                           buffer5[i] = value;
      }   
      return(0);
   }
   
   //
   //
   //
   //
   //

    limit = MathMax(limit,MathMin(Bars-1,iCustom(NULL,timeFrame,indicatorFileName,"returnBars",0,0)*timeFrame/Period()));
    for (i=limit;i>=0; i--)
    {
       int y = iBarShift(NULL,timeFrame,Time[i]);
            buffer3[i] = iCustom(NULL,timeFrame,indicatorFileName,"",Length,Level,Price,4,y);
            buffer2[i] = EMPTY_VALUE;
            buffer1[i] = EMPTY_VALUE;
            if (buffer3[i] > 0) buffer1[i] = buffer3[i];
            if (buffer3[i] < 0) buffer2[i] = buffer3[i];

          //
          //
          //
          //
          //

          if (!Interpolate || y==iBarShift(NULL,timeFrame,Time[i-1])) continue;
          datetime time = iTime(NULL,timeFrame,y);
             for(int n = 1; i+n < Bars && Time[i+n] >= time; n++) continue;	
             for(int x = 1; x < n; x++)
             {
                buffer3[i+x] = buffer3[i] + (buffer3[i+n] - buffer3[i]) * x/n;
                if (buffer1[i]!= EMPTY_VALUE) buffer1[i+x] = buffer3[i+x];
                if (buffer2[i]!= EMPTY_VALUE) buffer2[i+x] = buffer3[i+x];
             }               
    }
    return(0);
}


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

void CalculateData(int limit)
{
   int workLevel = MathMin(Level,6);

   //
   //
   //
   //
   //
   
   for(int i = limit; i >= 0; i--)
   {
      if (Level>0)
         {
            buffer8[i] = iCustom(NULL,0,indicatorFileName,"calculateValue",Length,Level-6,Price,1,i);
            buffer1[i] = iCustom(NULL,0,indicatorFileName,"calculateValue",Length,Level-6,Price,0,i);

            //
            //
            //
            //
            //
            
            if (workLevel>5) {
                  buffer7[i] = MidPoint(buffer8,i); buffer1[i] += buffer7[i]; }
            else  buffer7[i] = buffer8[i];
            if (workLevel>4) {
                  buffer6[i] = MidPoint(buffer7,i); buffer1[i] += buffer6[i]; }
            else  buffer6[i] = buffer7[i];
            if (workLevel>3) {
                  buffer5[i] = MidPoint(buffer6,i); buffer1[i] += buffer5[i]; }
            else  buffer5[i] = buffer6[i];
            if (workLevel>2) {
                  buffer4[i] = MidPoint(buffer5,i); buffer1[i] += buffer4[i]; }
            else  buffer4[i] = buffer5[i];
            if (workLevel>1) {
                  buffer3[i] = MidPoint(buffer4,i); buffer1[i] += buffer3[i]; }
            else  buffer3[i] = buffer4[i];
                  buffer2[i] = MidPoint(buffer3,i); buffer1[i] += buffer2[i];
         }
      else
         {                                 
                 buffer2[i] = iMA(NULL,0,1,0,MODE_SMA,Price,i);
                 buffer1[i] = 0.00;
         }            
   }
}



//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

double MidPoint(double& array[], int shift)
{
   double maxValue = array[shift];
   double minValue = array[shift];
 
   for (int i=1; i<Length; i++)
      {
         minValue = MathMin(minValue,array[shift+i]);
         maxValue = MathMax(maxValue,array[shift+i]);
      }
   return((maxValue+minValue)/2);
}

//
//
//
//
//

double hiValue(double& array[], int shift)
{
   double maxValue = array[shift];
   for (int i=1; i<Level; i++)
          maxValue = MathMax(maxValue,array[shift+i]);
   return(maxValue);      
}

//
//
//
//
//

double loValue(double& array[], int shift)
{
   double minValue = array[shift];
   for (int i=1; i<Level; i++)
          minValue = MathMin(minValue,array[shift+i]);
   return(minValue);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//
//

string sTfTable[] = {"M1","M5","M10","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,10,15,30,60,240,1440,10080,43200};

//
//
//
//
//

int stringToTimeFrame(string tfs)
{
   tfs = stringUpperCase(tfs);
   for (int i=ArraySize(iTfTable)-1; i>=0; i--)
         if (tfs==sTfTable[i] || tfs==""+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("");
}

//
//
//
//
//

string stringUpperCase(string str)
{
   string   s = str;

   for (int length=StringLen(str)-1; length>=0; length--)
   {
      int tchar = StringGetChar(s, length);
         if((tchar > 96 && tchar < 123) || (tchar > 223 && tchar < 256))
                     s = StringSetChar(s, length, tchar - 32);
         else if(tchar > -33 && tchar < 0)
                     s = StringSetChar(s, length, tchar + 224);
   }
return(s);
}

