//+------------------------------------------------------------------+
//|                                                        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

double dpo[],val[],valUa[],valUb[],valDa[],valDb[],upBand[],dnBand[],valc[];
struct sGlobalStruct
{
   int    shift;
};
sGlobalStruct global;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+

int OnInit()
 {
  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");
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason) { return; }

//+------------------------------------------------------------------+
//| 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; }
}
