//+------------------------------------------------------------------+
//|                                                        DPO_BB.mq4|
//|                                                           Mobidik|
//|                                                              2015|
//+------------------------------------------------------------------+
#property copyright "www,forex-station.com"
#property link      "www,forex-station.com"

#property indicator_separate_window
#property indicator_buffers 8
#property indicator_color1  clrGold
#property indicator_color2  clrSilver
#property indicator_color3  C'0,92,185'
#property indicator_color4  C'0,92,185'
#property indicator_color5  C'185,19,123'
#property indicator_color6  C'185,19,123'
#property indicator_color7  clrDimGray
#property indicator_color8  clrDimGray
#property indicator_width1  1
#property indicator_width2  2
#property indicator_width3  2
#property indicator_width4  2
#property indicator_width5  2
#property indicator_width6  2
#property indicator_width7  2
#property indicator_width8  2
#property indicator_style1  2
#property strict

//
//
//

input int                DPO_Period         = 8;               // Dpo period
input ENUM_APPLIED_PRICE DPO_Price          = PRICE_CLOSE;      // Dpo price
input ENUM_MA_METHOD     DPO_Method         = MODE_SMMA;        // Dpo ma method
input int                MoboLength         = 21;               // Mobo period
enum  stdMethods
      {
         std_custSam,                                           // Custom - with sample correction
         std_custNos                                            // Custom - without sample correction
      };
input stdMethods         DeviationType      = std_custSam;      // Deviation calculation type
input double             numDevUp           = 1.2;              // Upper bands deviation
input double             numDevDn           = 1.2;              // Lower bands deviation
extern int                btn_Subwindow         = 3;
extern ENUM_BASE_CORNER   btn_corner            = CORNER_RIGHT_LOWER;
extern string             btn_text              = "mobo";
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;                               


bool show_data = true;
bool recalc    = true;

string IndicatorName, IndicatorObjPrefix,buttonId;

double dpo[],val[],valUa[],valUb[],valDa[],valDb[],upBand[],dnBand[],valc[];
struct sGlobalStruct
{
   int    shift;
};
sGlobalStruct global;

string GenerateIndicatorName(const string target) 
{
   string name = target;
   int try = 2;
   while (WindowFind(name) != -1)
   {
      name = target + " #" + IntegerToString(try++);
   }
   return name;
}

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+

int OnInit()
 {
 IndicatorName = GenerateIndicatorName(btn_text);
   IndicatorObjPrefix = "__" + IndicatorName + "__";
   IndicatorShortName(IndicatorName);
   IndicatorDigits(Digits);
   
   double valz;
   if (GlobalVariableGet(IndicatorName + "_visibility", valz))
      show_data = valz != 0;
      
  IndicatorBuffers(9);
  SetIndexBuffer(0,dpo,   INDICATOR_DATA); SetIndexStyle(0,DRAW_LINE); 
  SetIndexBuffer(1,val,   INDICATOR_DATA); SetIndexStyle(1,DRAW_LINE); 
  SetIndexBuffer(2,valUa, INDICATOR_DATA); SetIndexStyle(2,DRAW_LINE);     
  SetIndexBuffer(3,valUb, INDICATOR_DATA); SetIndexStyle(3,DRAW_LINE);    
  SetIndexBuffer(4,valDa, INDICATOR_DATA); SetIndexStyle(4,DRAW_LINE);     
  SetIndexBuffer(5,valDb, INDICATOR_DATA); SetIndexStyle(5,DRAW_LINE);   
  SetIndexBuffer(6,upBand,INDICATOR_DATA); SetIndexStyle(6,DRAW_LINE); 
  SetIndexBuffer(7,dnBand,INDICATOR_DATA); SetIndexStyle(7,DRAW_LINE); 
  SetIndexBuffer(8,valc);
   
  global.shift = DPO_Period/2+1;  
  _sma.init(MoboLength);
  
  IndicatorSetString(INDICATOR_SHORTNAME," Mobo Bands");
   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(banzai,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 banzai=0; banzai<indicator_buffers; banzai++)
            SetIndexStyle(banzai,DRAW_NONE);
      }     
   
}
//

//+------------------------------------------------------------------+
//| DPO-BB                                                           |
//+------------------------------------------------------------------+

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=rates_total-prev_calculated+1; if (i>=rates_total) i=rates_total-1;   
  
   //
   //
   //
   
   if (valc[i]== 1) iCleanPoint(i,rates_total,valUa,valUb);
   if (valc[i]==-1) iCleanPoint(i,rates_total,valDa,valDb);
   for (; i>=0 && !_StopFlag; i--)
   {
      dpo[i] = iMA(_Symbol,_Period,1,0,DPO_Method,DPO_Price,i)-iMA(_Symbol,_Period,DPO_Period,0,DPO_Method,DPO_Price,i+global.shift);
      val[i] = _sma.OnCalculate(dpo[i],rates_total-i-1,rates_total);
      double sDev  = iDeviation(dpo[i],MoboLength,DeviationType==std_custSam,i,rates_total);
         dnBand[i] = val[i] - numDevDn * sDev;
         upBand[i] = val[i] + numDevUp * sDev;
         valc[i]   = (i<rates_total-1) ? (dpo[i]>upBand[i]) ? 1 : (dpo[i]<dnBand[i]) ? -1 : valc[i+1] : 0; 
         if (valc[i]==-1) iPlotPoint(i,rates_total,valDa,valDb,val); else valDa[i] = valDb[i] = EMPTY_VALUE;
         if (valc[i]== 1) iPlotPoint(i,rates_total,valUa,valUb,val); else valUa[i] = valUb[i] = EMPTY_VALUE; 
   } 
return(rates_total);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------

class CSma
{
   private :
      struct scSmaArrayStruct
      {
         double value;
         double sum;
      };
      scSmaArrayStruct m_array[];
      int              m_arraySize;
      int              m_period;
   public :
      CSma() : m_period(1), m_arraySize(-1) {                     return; }
     ~CSma()                                { ArrayFree(m_array); return; }
     
     //
     //
     //
      
     void init(int period) 
     { 
         m_period = (period>1) ? period : 1; 
     }
     double OnCalculate(double value, int i, int bars)
     {
        if (m_arraySize<bars)
          { m_arraySize=ArrayResize(m_array,bars+500); if (m_arraySize<bars) return(0); }

         //
         //
         //

         m_array[i].value=value;
            if (i>m_period)
                   m_array[i].sum = m_array[i-1].sum + value - m_array[i-m_period].value;
            else { m_array[i].sum = 0; for(int k=0; k<m_period && i>=k; k++) m_array[i].sum += m_array[i-k].value; }
            return(m_array[i].sum / (double)m_period);
      }
};
CSma _sma;
   
//------------------------------------------------------------------
//                                                                  
//------------------------------------------------------------------

double workDev[];
double iDeviation(double value, int length, bool isSample, int i, int bars)
{
   if (ArraySize(workDev)!= bars) ArrayResize(workDev,bars); i=bars-i-1; workDev[i] = value;
                 
   //
   //
   //
   //
   //
   
      double oldMean   = value;
      double newMean   = value;
      double squares   = 0; int k;
      for (k=1; k<length && (i-k)>=0; k++)
      {
         newMean  = (workDev[i-k]-oldMean)/(k+1)+oldMean;
         squares += (workDev[i-k]-oldMean)*(workDev[i-k]-newMean);
         oldMean  = newMean;
      }
return(sqrt(squares/fmax(k-isSample,1)));
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------

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; }
}
