//+------------------------------------------------------------------+
//|                                             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_levelcolor DimGray
#property indicator_color1     LimeGreen
#property indicator_color2     Red
#property indicator_level1     0.00


//
//
//
//
//

extern string _           = "Parameters";
extern int    Length      = 12;
extern int    Level       = 10;
extern int    Price       = PRICE_CLOSE;
extern int    BarsToCount = 1000;

double buffer1[];
double buffer2[];
double buffer3[];
double buffer4[];
double buffer5[];
double buffer6[];
double buffer7[];
double buffer8[];

//
//
//
//
//

string IndicatorFileName;
bool   Calculating = false;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int init()
{
   Calculating = (_=="calculate");
   IndicatorFileName = WindowExpertName();
   if (BarsToCount > 0)
       BarsToCount = MathMax(BarsToCount,250);
      
      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);
      if (Calculating)  return(0);
 
   //
   //
   //
   //
   //

   SetIndexStyle(0,DRAW_SECTION); SetIndexLabel(0,"Balance up");
   SetIndexStyle(1,DRAW_SECTION); SetIndexLabel(1,"Balance down");
   IndicatorShortName("Point of balance ("+Length+","+Level+")");
   return(0);
}
int deinit()
{
   return(0);
}


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int start()
{
   int    counted_bars = IndicatorCounted();
   int    i,limit;

   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
         limit = Bars-counted_bars;
         if (BarsToCount>0) limit = MathMin(limit,BarsToCount);


   //
   //
   //
   //
   //
   
      if (Calculating) { CalculateData(limit); return(0); }
   
   //
   //
   //
   //
   //
   
   for(i = limit; i >= 0; i--)
   {
      buffer4[i] = iMA(NULL,0,1,0,MODE_SMA,Price,i);
      buffer3[i] = iCustom(NULL,0,IndicatorFileName,"calculate",Length,Level,Price,BarsToCount,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;
   }   
   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,"calculate",Length,Level-6,Price,BarsToCount,1,i);
            buffer1[i] = iCustom(NULL,0,IndicatorFileName,"calculate",Length,Level-6,Price,BarsToCount,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);
}