//+------------------------------------------------------------------+
//|                                                Buy Sell Pressure |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "www.forex-station.com"
#property link      "www.forex-station.com"

#property indicator_separate_window
#property indicator_buffers 7
#property strict

//
//
//

input int                 BSPLength         = 24;                // Buy/sell pressure length
input int                 MaPeriod          = 10;                // Ma smoothing period (<=1 = no smoothing)
input ENUM_MA_METHOD      MaMetod           = MODE_LWMA;         // Ma smoothing method
input bool                AutoHisto         = true;              // Automatically adjust histo width
input color               inpColorSUp       = clrMediumBlue;     // Strong bullish histo color 
input color               inpColorWUp       = clrTurquoise;      // Weak bullish histo color 
input color               inpColorSDn       = clrRed;            // Strong bearish histo color 
input color               inpColorWDn       = clrPaleVioletRed;  // Weak bearish histo color 
input int                 inpLineWidth      = 4;                 // Lines width
extern bool               AlertsOn          = false;             // Turn alerts on?
extern bool               AlertsOnCurrent   = false;             // Alerts on still opened bar?
extern bool               AlertsMessage     = true;              // Alerts should display message?
extern bool               AlertsSound       = false;             // Alerts should play a sound?
extern bool               AlertsNotify      = false;             // Alerts should send a notification?
extern bool               AlertsEmail       = false;             // Alerts should send an email?
extern string             AlertsSoundFile   = "alert2.wav";      // Sound file
extern int                btn_Subwindow         = 1;
extern ENUM_BASE_CORNER   btn_corner            = CORNER_RIGHT_LOWER;
extern string             btn_text              = "bsp";
extern string             btn_Font              = "Arial";
extern int                btn_FontSize          = 8;                        
extern color              btn_text_ON_color     = clrWhite;
extern color              btn_text_OFF_color    = clrRed;
extern color              btn_background_color  = clrDimGray;
extern color              btn_border_color      = clrDarkGray;
extern int                button_x              = 335;                                   
extern int                button_y              = 20;                                   
extern int                btn_Width             = 65;                                
extern int                btn_Height            = 20;                         

double huu[],hud[],hdd[],hdu[],val[],valda[],valdb[],valc[],slope[];
struct sGloStruct
{
   double maOp; 
   double maCl;
   double maHi;
   double maLo;
   double max; 
   double min;
   double bd;
   double bp;
   double bw; 
   double lw;
   double sp;
   double bal;
   double uw;
   int    hiswidth;
};
sGloStruct glo;

bool show_data = true;
bool recalc    = true;

string IndicatorName, IndicatorObjPrefix,buttonId;

//+------------------------------------------------------------------
//|                                                                  
//+------------------------------------------------------------------

string GenerateIndicatorName(const string target) 
{
   string name = target;
   int try = 2;
   while (WindowFind(name) != -1)
   {
      name = target + " #" + IntegerToString(try++);
   }
   return name;
}


int OnInit()
{
IndicatorName = GenerateIndicatorName(btn_text);
   IndicatorObjPrefix = "__" + IndicatorName + "__";
   IndicatorShortName(IndicatorName);
   IndicatorDigits(Digits);
   
   double valbu;
   if (GlobalVariableGet(IndicatorName + "_visibility", valbu))
      show_data = valbu != 0;
      
   if (AutoHisto)
   {
      int scale = int(ChartGetInteger(0,CHART_SCALE));
      switch(scale) 
	   {
	      case 0: glo.hiswidth =  1; break;
	      case 1: glo.hiswidth =  1; break;
		   case 2: glo.hiswidth =  2; break;
		   case 3: glo.hiswidth =  3; break;
		   case 4: glo.hiswidth =  6; break;
		   case 5: glo.hiswidth = 14; break;
	   }
	}
	
   IndicatorBuffers(9);
   SetIndexBuffer(0,huu,INDICATOR_DATA);    SetIndexStyle(0,DRAW_HISTOGRAM,EMPTY,glo.hiswidth,inpColorSUp);
   SetIndexBuffer(1,hud,INDICATOR_DATA);    SetIndexStyle(1,DRAW_HISTOGRAM,EMPTY,glo.hiswidth,inpColorWUp);
   SetIndexBuffer(2,hdd,INDICATOR_DATA);    SetIndexStyle(2,DRAW_HISTOGRAM,EMPTY,glo.hiswidth,inpColorSDn);
   SetIndexBuffer(3,hdu,INDICATOR_DATA);    SetIndexStyle(3,DRAW_HISTOGRAM,EMPTY,glo.hiswidth,inpColorWDn);
   SetIndexBuffer(4,val,INDICATOR_DATA);    SetIndexStyle(4,DRAW_LINE,EMPTY,inpLineWidth,inpColorSUp);
   SetIndexBuffer(5,valda,INDICATOR_DATA);  SetIndexStyle(5,DRAW_LINE,EMPTY,inpLineWidth,inpColorSDn);
   SetIndexBuffer(6,valdb,INDICATOR_DATA);  SetIndexStyle(6,DRAW_LINE,EMPTY,inpLineWidth,inpColorSDn);
   SetIndexBuffer(7,valc,INDICATOR_CALCULATIONS);
   SetIndexBuffer(8,slope,INDICATOR_CALCULATIONS);
   
   iEma.OnInit(BSPLength);
   
   IndicatorSetString(INDICATOR_SHORTNAME,"Net Bsp("+(string)BSPLength+")");
   
 ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, 1);
   buttonId = IndicatorObjPrefix + (btn_text);
   createButton(buttonId, btn_text, btn_Width, btn_Height, btn_Font, btn_FontSize, btn_background_color, btn_border_color, btn_text_ON_color);
   ObjectSetInteger(0, buttonId, OBJPROP_YDISTANCE, button_y);
   ObjectSetInteger(0, buttonId, OBJPROP_XDISTANCE, button_x);
   
return(INIT_SUCCEEDED);
}

//
void OnDeinit(const int reason)

 {
 
 ObjectsDeleteAll(ChartID(), IndicatorObjPrefix);
 
 
  }
//
void createButton(string buttonID,string buttonText,int width,int height,string font,int fontSize,color bgColor,color borderColor,color txtColor)
{
   //   ObjectDelete    (0,buttonID);
      ObjectCreate    (0,buttonID,OBJ_BUTTON,WindowOnDropped(),0,0);
      ObjectSetInteger(0,buttonID,OBJPROP_COLOR,txtColor);
      ObjectSetInteger(0,buttonID,OBJPROP_BGCOLOR,bgColor);
      ObjectSetInteger(0,buttonID,OBJPROP_BORDER_COLOR,borderColor);
      ObjectSetInteger(0,buttonID,OBJPROP_BORDER_TYPE,BORDER_RAISED);
      ObjectSetInteger(0,buttonID,OBJPROP_XSIZE,width);
      ObjectSetInteger(0,buttonID,OBJPROP_YSIZE,height);
      ObjectSetString (0,buttonID,OBJPROP_FONT,font);
      ObjectSetString (0,buttonID,OBJPROP_TEXT,buttonText);
      ObjectSetInteger(0,buttonID,OBJPROP_FONTSIZE,fontSize);
      ObjectSetInteger(0,buttonID,OBJPROP_SELECTABLE,0);
      ObjectSetInteger(0,buttonID,OBJPROP_CORNER,btn_corner);
      ObjectSetInteger(0,buttonID,OBJPROP_HIDDEN,1);
      ObjectSetInteger(0,buttonID,OBJPROP_XDISTANCE,9999);
      ObjectSetInteger(0,buttonID,OBJPROP_YDISTANCE,9999);
}
//+------------------------------------------------------------------+
void handleButtonClicks()
{
   if (ObjectGetInteger(0, buttonId, OBJPROP_STATE))
   {
      ObjectSetInteger(0, buttonId, OBJPROP_STATE, false);
      show_data = !show_data;
      GlobalVariableSet(IndicatorName + "_visibility", show_data ? 1.0 : 0.0);
      recalc = true;
     // start();
   }
}
void OnChartEvent(const int id, 
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
   handleButtonClicks();
   if (id==CHARTEVENT_OBJECT_CLICK && ObjectGet(sparam,OBJPROP_TYPE)==OBJ_BUTTON)
   
   for (int banzai=0; banzai<indicator_buffers; banzai++)
     SetIndexStyle(0,DRAW_HISTOGRAM);
     SetIndexStyle(1,DRAW_HISTOGRAM);
     SetIndexStyle(2,DRAW_HISTOGRAM);
     SetIndexStyle(3,DRAW_HISTOGRAM);
     SetIndexStyle(4,DRAW_LINE);
     SetIndexStyle(5,DRAW_LINE);
     SetIndexStyle(6,DRAW_LINE);
     
   if (show_data)
   {
   ObjectSetInteger(ChartID(),buttonId,OBJPROP_COLOR,btn_text_ON_color);
     
      }
      else
      {
        ObjectSetInteger(ChartID(),buttonId,OBJPROP_COLOR,btn_text_OFF_color);
        for (int tp=0; tp<indicator_buffers; tp++)
            SetIndexStyle(tp,DRAW_NONE);
      }     
   
}
//

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[])
{
   int i,r,limit=fmin(rates_total-prev_calculated+1,rates_total-1);
   if(ChartGetInteger(0,CHART_SCALE) != glo.hiswidth) OnInit(); 
         
   //
   //
   //
   
   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);
   
   //
   //
   //
   if (valc[limit]==-1) iCleanPoint(limit,rates_total,valda,valdb); 
   for(i=limit, r=rates_total-limit-1; i>=0; i--,r++)
   {
      glo.maOp = iMA(NULL,0,MaPeriod,0,(int)MaMetod,PRICE_OPEN ,i); // smoothing
      glo.maCl = iMA(NULL,0,MaPeriod,0,(int)MaMetod,PRICE_CLOSE,i); // smoothing
      glo.maLo = iMA(NULL,0,MaPeriod,0,(int)MaMetod,PRICE_LOW  ,i); // smoothing
      glo.maHi = iMA(NULL,0,MaPeriod,0,(int)MaMetod,PRICE_HIGH ,i); // smoothing
      
      wrk[r].haOp = (r>0) ? (wrk[r-1].haOp+wrk[r-1].haCl)*0.5 : (glo.maOp+glo.maCl)*0.5;
      wrk[r].haCl = (glo.maOp+glo.maHi+glo.maLo+glo.maCl)*0.25;
      wrk[r].haHi = fmax(glo.maHi,fmax(wrk[r].haOp,wrk[r].haCl));
      wrk[r].haLo = fmin(glo.maLo,fmin(wrk[r].haOp,wrk[r].haCl));
      
      glo.max = (r>0) ? fmax(wrk[r].haHi,wrk[r-1].haCl) : 0;
      glo.min = (r>0) ? fmin(wrk[r].haLo,wrk[r-1].haCl) : 0;
      glo.bd  = fabs(wrk[r].haCl-wrk[r].haOp);
      glo.uw  = wrk[r].haHi - fmax(wrk[r].haOp,wrk[r].haCl);
      glo.lw  = fmin(wrk[r].haOp,wrk[r].haCl)- wrk[r].haLo;
      glo.bp  = wrk[r].haCl - low[i]  - glo.lw; //buying_pressure
      glo.sp  = high[i] - wrk[r].haCl - glo.uw; //selling_pressure
      glo.bal = glo.sp-glo.bp;
      val[i]  = iEma.OnCalculate(glo.bal,r,rates_total);
      valc[i] = (r>0) ? (val[i]>0) ? (val[i]>val[i+1]) ? 0 : 1 : (val[i]<val[i+1]) ? 2 : 3 : 0;
      slope[i] = (r>0) ?  (val[i]>val[i+1]) ? 1 : (val[i]<val[i+1]) ? -1  : slope[i+1] : 0;
      huu[i] = (valc[i]== 0) ? val[i] : EMPTY_VALUE;
      hud[i] = (valc[i]== 1) ? val[i] : EMPTY_VALUE; 
      hdd[i] = (valc[i]== 2) ? val[i] : EMPTY_VALUE;
      hdu[i] = (valc[i]== 3) ? val[i] : EMPTY_VALUE; 
      valda[i] = valdb[i] = EMPTY_VALUE; if (slope[i] == -1) iPlotPoint(i,rates_total,valda,valdb,val); 
                                         
       
   }
   
 if (AlertsOn)
      {
         int whichBar = 1; if (AlertsOnCurrent) whichBar = 0; 
         if (slope[whichBar] != slope[whichBar+1])
         {
            if (slope[whichBar] == 1)                          doAlert(" up");
            if (slope[whichBar] ==-1)                          doAlert(" down");       
              
         }         
      }      
return(rates_total);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------

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;

void iCleanPoint(int i, int bars, double& first[], double& second[])
{
   if (i>=bars-3) return;
   if ((second[i]  != EMPTY_VALUE) && (second[i+1] != EMPTY_VALUE))
        second[i+1] = EMPTY_VALUE;
   else
      if ((first[i]  != EMPTY_VALUE) && (first[i+1] != EMPTY_VALUE) && (first[i+2] == EMPTY_VALUE))
           first[i+1] = EMPTY_VALUE;
}
void iPlotPoint(int i, int bars, double& first[], double& second[], double& from[])
{
   if (i>=bars-2) return;
   if (first[i+1] == EMPTY_VALUE)
      if (first[i+2] == EMPTY_VALUE)
            { first[i]  = from[i]; first[i+1]  = from[i+1]; second[i] = EMPTY_VALUE; }
      else  { second[i] = from[i]; second[i+1] = from[i+1]; first[i]  = EMPTY_VALUE; }
   else     { first[i]  = from[i];                          second[i] = EMPTY_VALUE; }
}

string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,15,30,60,240,1440,10080,43200};

string timeFrameToString(int tf)
{
   for (int i=ArraySize(iTfTable)-1; i>=0; i--) 
         if (tf==iTfTable[i]) return(sTfTable[i]);
                              return("");
}

void doAlert(string doWhat)
{
   static string   previousAlert="nothing";
   static datetime previousTime;
   
      if (previousAlert != doWhat || previousTime != Time[0]) 
      {
          previousAlert  = doWhat;
          previousTime   = Time[0];

          //
          //
          //
          //
          //

          string message = timeFrameToString(_Period)+" "+_Symbol+" at "+TimeToStr(TimeLocal(),TIME_SECONDS)+" Net Bsp : "+doWhat;
             if (AlertsMessage) Alert(message);
             if (AlertsNotify)  SendNotification(message);
             if (AlertsEmail)   SendMail(_Symbol+" Net Bsp  ",message);
             if (AlertsSound)   PlaySound(AlertsSoundFile);
      }
}

/*
// Heikin Ashi smoothing {
// average price of the current bar
   heikin_ashi_close = (open+high+low+close) / 4
// the midpoint of the previous bar
heikin_ashi_open = (open(1)+close(1)) / 2
heikin_ashi_high = math.max(high, open, close)
heikin_ashi_low = math.min(low, open, close)
//}

// Inputs and Formula {
ln = input(24, "BSP Average")
high_ = math.max(heikin_ashi_high, heikin_ashi_close(1))
low_ = math.min(heikin_ashi_low, heikin_ashi_close(1))
bd = math.abs(heikin_ashi_close - heikin_ashi_open)
uw = heikin_ashi_high - math.max(heikin_ashi_open, heikin_ashi_close)
lw = math.min(heikin_ashi_open, heikin_ashi_close) - heikin_ashi_low
bp = heikin_ashi_close - low_ - lw //buying_pressure
sp = high_ - heikin_ashi_close - uw //selling_pressure
bal = bp - sp
bsp = ta.ema(bal, ln)
//}
*/