//+------------------------------------------------------------------+
//|                                                Buy Sell Pressure |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "www.forex-station.com"
#property link      "www.forex-station.com"

#property indicator_separate_window
#property indicator_buffers 3
#property indicator_plots   2
#property indicator_label1  "Net Buy Sell pressure"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDimGray
#property indicator_width1  2
#property indicator_label2  "Net Buy Sell pressure histogram"
#property indicator_type2   DRAW_COLOR_HISTOGRAM
#property indicator_color2  clrBlue,clrTurquoise,clrRed,clrPaleVioletRed
#property indicator_width2  2

//
//
//

input int                 BSPLength         = 24;                // Buy/sell pressure length
enum  enMaTypes
      {
         ma_sma,                                                 // Simple moving average
         ma_ema,                                                 // Exponential moving average
         ma_smma,                                                // Smoothed MA
         ma_lwma                                                 // Linear weighted MA
      };
input enMaTypes           inpMaMetod        = ma_lwma;           // Smoothing method
input int                 inpMaPeriod       = 10;                // Smoothing period

double val[],valh[],valc[];
struct sGloStruct
{
   double maOp; 
   double maCl;
   double maHi;
   double maLo;
   double max; 
   double min;
   double bw; 
   double lw;
   double bp;
   double sp;
   double bal;
   double uw;
};
sGloStruct glo;


//+------------------------------------------------------------------
//|                                                                  
//+------------------------------------------------------------------

int OnInit()
{
   SetIndexBuffer(0,val, INDICATOR_DATA);
   SetIndexBuffer(1,valh,INDICATOR_DATA);
   SetIndexBuffer(2,valc,INDICATOR_COLOR_INDEX);
   
   iEma.OnInit(BSPLength);
   
   IndicatorSetString(INDICATOR_SHORTNAME,"Net Bsp("+(string)BSPLength+")");
return(INIT_SUCCEEDED);
}

//
//
//

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
   if(Bars(_Symbol,_Period)<rates_total) return(-1);
         
   //
   //
   //
   
   struct sWorkStruct
   {
     double haCl;
     double haOp;
     double haHi;
     double haLo;
   };
   static sWorkStruct wrk[];
   static int        wrkSize = -1;
                 if (wrkSize<rates_total) wrkSize = ArrayResize(wrk,rates_total+500);
   
   //
   //
   //
   
   int i=(int)fmax(prev_calculated-1,0); for(; i<rates_total && !_StopFlag; i++)
   {
      glo.maOp = iCustomMa(inpMaMetod,open[i] ,inpMaPeriod,i,rates_total,0);
      glo.maCl = iCustomMa(inpMaMetod,close[i],inpMaPeriod,i,rates_total,1);
      glo.maLo = iCustomMa(inpMaMetod,low[i]  ,inpMaPeriod,i,rates_total,2);
      glo.maHi = iCustomMa(inpMaMetod,high[i] ,inpMaPeriod,i,rates_total,3);
      
      wrk[i].haOp = (i>0) ? (wrk[i-1].haOp+wrk[i-1].haCl)*0.5 : (glo.maOp+glo.maCl)*0.5;
      wrk[i].haCl = (glo.maOp+glo.maHi+glo.maLo+glo.maCl)*0.25;
      wrk[i].haHi = fmax(glo.maHi,fmax(wrk[i].haOp,wrk[i].haCl));
      wrk[i].haLo = fmin(glo.maLo,fmin(wrk[i].haOp,wrk[i].haCl));
      
      glo.max = (i>0) ? fmax(wrk[i].haHi,wrk[i-1].haCl) : 0;
      glo.min = (i>0) ? fmin(wrk[i].haLo,wrk[i-1].haCl) : 0;

      glo.uw  = wrk[i].haHi - fmax(wrk[i].haOp,wrk[i].haCl);
      glo.lw  = fmin(wrk[i].haOp,wrk[i].haCl)- wrk[i].haLo;
      
      glo.bp  = wrk[i].haCl - low[i]  - glo.lw; //buying_pressure
      glo.sp  = high[i] - wrk[i].haCl - glo.uw; //selling_pressure
      glo.bal = glo.sp-glo.bp;
      
      val[i]  = valh[i] = iEma.OnCalculate(glo.bal,i,rates_total);
      valc[i] =  (i>0) ? (valh[i]>0) ? (valh[i]>valh[i-1]) ? 0 : 1 : (valh[i]<valh[i-1]) ? 2 : 3 : 0; 
   }
return(rates_total);
}

//------------------------------------------------------------------
// custom functions
//------------------------------------------------------------------

#define _maInstances 4
#define _maWorkBufferx1 1*_maInstances

//
//
//

double iCustomMa(int mode,double price,double length,int r,int bars,int instanceNo=0)
  {
   switch(mode)
     {
      case ma_sma   : return(iSma(price,(int)length,r,bars,instanceNo));
      case ma_ema   : return(iEma(price,length,r,bars,instanceNo));
      case ma_smma  : return(iSmma(price,(int)length,r,bars,instanceNo));
      case ma_lwma  : return(iLwma(price,(int)length,r,bars,instanceNo));
      default       : return(price);
     }
  }
  
//
//
//

double workSma[][_maWorkBufferx1];
double iSma(double price,int period,int r,int _bars,int instanceNo=0)
  {
   if(ArrayRange(workSma,0)!=_bars) ArrayResize(workSma,_bars);

   workSma[r][instanceNo]=price;
   double avg=price; int k=1; for(; k<period && (r-k)>=0; k++) avg+=workSma[r-k][instanceNo];  avg/=(double)k;
   return(avg);
  }
  
//
//
//

double workEma[][_maWorkBufferx1];
double iEma(double price,double period,int r,int _bars,int instanceNo=0)
  {
   if(ArrayRange(workEma,0)!=_bars) ArrayResize(workEma,_bars);

   workEma[r][instanceNo]=price;
   if(r>0 && period>1)
      workEma[r][instanceNo]=workEma[r-1][instanceNo]+(2.0/(1.0+period))*(price-workEma[r-1][instanceNo]);
   return(workEma[r][instanceNo]);
  }
  
//
//
//

double workSmma[][_maWorkBufferx1];
double iSmma(double price,double period,int r,int _bars,int instanceNo=0)
  {
   if(ArrayRange(workSmma,0)!=_bars) ArrayResize(workSmma,_bars);

   workSmma[r][instanceNo]=price;
   if(r>1 && period>1)
      workSmma[r][instanceNo]=workSmma[r-1][instanceNo]+(price-workSmma[r-1][instanceNo])/period;
   return(workSmma[r][instanceNo]);
  }
  
//
//
//

double workLwma[][_maWorkBufferx1];
double iLwma(double price,double period,int r,int _bars,int instanceNo=0)
  {
   if(ArrayRange(workLwma,0)!=_bars) ArrayResize(workLwma,_bars);

   workLwma[r][instanceNo] = price; if(period<1) return(price);
   double sumw = period;
   double sum  = period*price;

   for(int k=1; k<period && (r-k)>=0; k++)
     {
      double weight = period-k;
      sumw  += weight;
      sum   += weight*workLwma[r-k][instanceNo];
     }
   return(sum/sumw);
  }

//------------------------------------------------------------------
//
//------------------------------------------------------------------

class CEma
{
   private :
         double m_alpha;
         double m_period;
         double m_array[];
         int    m_arraySize;
   public :
      CEma() : m_alpha(1), m_arraySize(-1), m_period(1) {}
     ~CEma()                                            {}
     
      //
      //
      //
     
      void OnInit(double period)
         {
            m_period = (period>1) ? period : 1;
            m_alpha  = 2.0/(1.0+m_period);
         }
      double OnCalculate(double value, int i, int bars)
         {
            if (m_arraySize<bars) m_arraySize=ArrayResize(m_array,bars+500);
            
            //
            //
            //
            
            if (i>0)
                    m_array[i] = m_array[i-1]+m_alpha*(value-m_array[i-1]); 
            else    m_array[i] = value;
            return (m_array[i]);
         }   
};
CEma iEma;
