//+------------------------------------------------------------------+
//|                                                 Kase DevStop.mq4 |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"

#property indicator_chart_window
#property indicator_buffers 4
#property indicator_color1  clrRed
#property indicator_color2  clrRed
#property indicator_color3  clrRed
#property indicator_color4  clrDeepSkyBlue
#property indicator_style1  STYLE_DOT
#property indicator_style2  STYLE_DOT
#property indicator_style3  STYLE_DOT
#property indicator_width4  2
#property strict

//
//
//
//
//

extern ENUM_TIMEFRAMES TimeFrame     = PERIOD_CURRENT;    // Time frame to use
extern int             DSPeriod      = 30;          // Dev stop period
extern int             DSSlowAverage = 21;          // Dev stop slow average
extern int             DSFastAverage = 10;          // Dev stop fast average
extern double          DSStdDev1     = 0.0;         // Dev stop deviation 1
extern double          DSStdDev2     = 1.0;         // Dev stop deviation 2
extern double          DSStdDev3     = 2.2;         // Dev stop deviation 3
extern double          DSStdDev4     = 3.6;         // Dev stop deviation 4
extern int             DSPrice1      = PRICE_CLOSE; // First Dev stop price
extern int             DSPrice2      = PRICE_HIGH;  // Second Dev stop price
extern int             DSPrice3      = PRICE_LOW;   // Third Dev stop price
input bool             Interpolate   = true;        // Interpolate in mtf mode?

double devStop1[],devStop2[],devStop3[],devStop4[],wrk[][6],count[];
string indicatorFileName;
#define _mtfCall(_buff,_ind) iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,DSPeriod,DSSlowAverage,DSFastAverage,DSStdDev1,DSStdDev2,DSStdDev3,DSStdDev4,DSPrice1,DSPrice2,DSPrice3,_buff,_ind)

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int OnInit()
{
   IndicatorBuffers(5);
   SetIndexBuffer(0,devStop1); SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(1,devStop2); SetIndexStyle(1,DRAW_LINE);
   SetIndexBuffer(2,devStop3); SetIndexStyle(2,DRAW_LINE);
   SetIndexBuffer(3,devStop4); SetIndexStyle(3,DRAW_LINE);
   SetIndexBuffer(4,count);
   
   indicatorFileName = WindowExpertName();
   TimeFrame         = fmax(TimeFrame,_Period); 

   IndicatorSetString(INDICATOR_SHORTNAME,timeFrameToString(TimeFrame)+" Kase DevStop");
return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

#define _price  0
#define _price1 1
#define _price2 2
#define _price3 3
#define _range  4
#define _trend  5

//
//
//
//
//

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

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); count[0]=limit;
      if (TimeFrame!=_Period)
      {
         limit = (int)fmax(limit,fmin(rates_total-1,_mtfCall(4,0)*TimeFrame/_Period));
         for (i=limit;i>=0 && !_StopFlag; i--)
         {
            int y = iBarShift(NULL,TimeFrame,time[i]);
               devStop1[i] = _mtfCall(0,y);
               devStop2[i] = _mtfCall(1,y);
               devStop3[i] = _mtfCall(2,y);
               devStop4[i] = _mtfCall(3,y);
                     
               //
               //
               //
                     
               if (!Interpolate || (i>0 && y==iBarShift(NULL,TimeFrame,time[i-1]))) continue;
                  #define _interpolate(buff) buff[i+k] = buff[i]+(buff[i+n]-buff[i])*k/n
                  int n,k; datetime btime = iTime(NULL,TimeFrame,y);
                     for(n = 1; (i+n)<rates_total && time[i+n] >= btime; n++) continue;	
                     for(k = 1; k<n && (i+n)<rates_total && (i+k)<rates_total; k++)
                     {
                        _interpolate(devStop1);
                        _interpolate(devStop2);
                        _interpolate(devStop3);
                        _interpolate(devStop4);
                     }                                        
        }    
	return(rates_total);
	}      
   
   //
   //
   //
   
   if (ArrayRange(wrk,0) != rates_total) ArrayResize(wrk,rates_total);
 	for(i=limit, r=rates_total-limit-1; i>=0; i--,r++)
   {
      wrk[r][_price1] = iMA(NULL,0,1,0,MODE_SMA,DSPrice1,i);
      wrk[r][_price2] = iMA(NULL,0,1,0,MODE_SMA,DSPrice2,i);
      wrk[r][_price3] = iMA(NULL,0,1,0,MODE_SMA,DSPrice3,i);
      double average1 = iMA(NULL,0,DSFastAverage,0,MODE_SMA,DSPrice1,i);
      double average2 = iMA(NULL,0,DSSlowAverage,0,MODE_SMA,DSPrice1,i);
      if (i<rates_total-1)
      {
         wrk[r][_trend]  = wrk[r-1][_trend];
         wrk[r][_price]  = wrk[r-1][_price];

         if (average1>average2) wrk[r][_trend] =  1;
         if (average1<average2) wrk[r][_trend] = -1;
         if (wrk[r][_trend] != wrk[r-1][_trend])
         if (wrk[r][_trend]==1)
               wrk[r][_price] = wrk[r][_price2];
         else  wrk[r][_price] = wrk[r][_price3];

         //
         //
         //

         if (wrk[r][_trend]>0)
         {
            wrk[r][_price] = fmax(wrk[r][_price],wrk[r][_price2]);
         
            devStop1[i] = wrk[r][_price]-reversal(DSStdDev1,DSPeriod,r);
            devStop2[i] = wrk[r][_price]-reversal(DSStdDev2,DSPeriod,r);
            devStop3[i] = wrk[r][_price]-reversal(DSStdDev3,DSPeriod,r);
            devStop4[i] = wrk[r][_price]-reversal(DSStdDev4,DSPeriod,r);
         }
         if (wrk[r][_trend]<0)
         {
            wrk[r][_price] = fmin(wrk[r][_price],wrk[r][_price3]);
         
            devStop1[i] = wrk[r][_price]+reversal(DSStdDev1,DSPeriod,r);
            devStop2[i] = wrk[r][_price]+reversal(DSStdDev2,DSPeriod,r);
            devStop3[i] = wrk[r][_price]+reversal(DSStdDev3,DSPeriod,r);
            devStop4[i] = wrk[r][_price]+reversal(DSStdDev4,DSPeriod,r);
         }
      }
   }
return(rates_total);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

double reversal(double stdevMultiplier, int period, int r)
{
   int n;
   double max = MathMax(MathMax(wrk[r][_price2],wrk[r-1][_price2]),wrk[r-2][_price1]);
   double min = MathMin(MathMin(wrk[r][_price3],wrk[r-1][_price3]),wrk[r-2][_price1]);
                                wrk[r][_range] = max-min;
         
   //
   //
   //
   //
   //
      
      double avg = wrk[r][_range];
         for(n=1; n<period && (r-n)>=0; n++) avg += wrk[r-n][_range];
                                             avg /= n;

      double dev = MathPow(wrk[r][_range]-avg,2);
         for(n=1; n<period && (r-n)>=0; n++) dev += MathPow(wrk[r-n][_range]-avg,2);
                                             dev  = MathSqrt(dev/n);

   //
   //
   //
   //
   //
   
   double result = avg+(stdevMultiplier*dev);
      if (result > 0)
            return(result);
      else  return(stdevMultiplier*(wrk[r][_price2]-wrk[r][_price3]));
}

//
//
//
//
//

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("");
}