#property copyright "www,forex-tsd.com"
#property link      "www,forex-tsd.com"

#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1 Gold
 
//---- input parameters
extern string    ____0____   = "Period of average";
extern int       MAPeriod   = 50;
extern string    ____1____   = "Type of average: SMA - 0, EMA - 1, SMMA - 2, LWMA - 3";
extern int       MaType      = 1;
extern string    ____2____   = "Type of price:cl=0,op=1,hi=2,lo=3,med=4";
extern int       PriceType   = 4;
extern string    ____3____   = "Moving Average Shift";
extern int       MaShift     = 0;
extern string    ____4____   = "Show oversold and overbought levels";
extern bool      ShowLevels  = true;
extern string    ____5____   = "Lines color (60%)";
extern color     LinesColor1 = Lime;
extern string    ____6____   = "Lines color (100%)";
extern color     LinesColor2 = Lime;
extern string    ____7____   = "Lines style: solid - 0, dashed - 1, dotted - 2";
extern int       LinesStyle  = 2;
extern double    Smooth      = 5;

//---- buffers
double ExtMapBuffer1[];

int init()
{
   SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(0,ExtMapBuffer1);

   string Short="MA Distance ("+MAPeriod+", "+MaType+", "+PriceType+", "+MaShift+")";
   IndicatorShortName(Short);
   SetIndexLabel(0,Short);
   
   SetLevelValue(0, 0.0);

   SetIndexDrawBegin(0,MAPeriod);
   return(0);
}

int deinit()
{
   // cleaning the mess
   if(ShowLevels == true)
   {
      ObjectDelete("dev1");
      ObjectDelete("dev2");
   
      ObjectDelete("dev3");
      ObjectDelete("dev4");
   }
   return(0);
}

int start()
{
   //main core    
   int i, counted_bars=IndicatorCounted();

   if(Bars<=MAPeriod) return(0);

   if(counted_bars<1)
      for(i=1;i<=MAPeriod;i++) ExtMapBuffer1[Bars-i]=0.0;

   i=Bars-MAPeriod-1;
   if(counted_bars>=MAPeriod) i=Bars-counted_bars-1;
   while(i>=0)
   {
      ExtMapBuffer1[i] = iSsm(priceSwitch(i) - iMA(NULL, 0, MAPeriod, MaShift, MaType, PriceType, i),Smooth,i);
      i--;
   }
   
   // Showing oversold/overbought levels
   if(ShowLevels == true)
   {
      int window = WindowFind("MA Distance ("+MAPeriod+", "+MaType+", "+PriceType+", "+MaShift+")");
      if(window == -1)
      {
         window = 1;
      }
      // counting stddev
      ArraySetAsSeries(ExtMapBuffer1, true);
      double dev = iStdDevOnArray(ExtMapBuffer1, Bars-counted_bars-1, 100,0,0,0);
      // lines creation
      ObjectCreate("dev1", OBJ_HLINE, window, TimeCurrent(), 1.2*dev);
      ObjectSetText("dev1", "+60%");
      ObjectSet("dev1", OBJPROP_COLOR, LinesColor1);
      ObjectSet("dev1", OBJPROP_STYLE, LinesStyle);
      
      ObjectCreate("dev2", OBJ_HLINE, window, TimeCurrent(), -1.8*dev); 
      ObjectSetText("dev2", "-60%");
      ObjectSet("dev2", OBJPROP_COLOR, LinesColor1);
      ObjectSet("dev2", OBJPROP_STYLE, LinesStyle);
      
      ObjectCreate("dev3", OBJ_HLINE, window, TimeCurrent(), 2*dev);
      ObjectSetText("dev3", "+100%");
      ObjectSet("dev3", OBJPROP_COLOR, LinesColor2);
      ObjectSet("dev3", OBJPROP_STYLE, LinesStyle);
      
      ObjectCreate("dev4", OBJ_HLINE, window, TimeCurrent(), -3*dev);  
      ObjectSetText("dev4", "-100%");
      ObjectSet("dev4", OBJPROP_COLOR, LinesColor2);
      ObjectSet("dev4", OBJPROP_STYLE, LinesStyle);      
   }
   return(0);
}

double priceSwitch(int i)
{
   double price;
   switch(PriceType)
   {
      case PRICE_CLOSE:
         price = Close[i];
         break;
      case PRICE_OPEN:
         price = Open[i];
         break;
      case PRICE_HIGH:
         price = High[i];
         break;
      case PRICE_LOW:
         price = Low[i];
         break;
      case PRICE_MEDIAN:
         price = (High[i]+Low[i])/2;
         break;
         
      default :
         price = Close[i];
   }
   return(price);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

double workSsm[][2];
#define _price  0
#define _ssm    1

double workSsmCoeffs[][4];
#define _period 0
#define _c1     1
#define _c2     2
#define _c3     3
#define Pi 3.14159265358979323846264338327950288

//
//
//
//
//

double iSsm(double price, double period, int i, int instanceNo=0)
{
   if (period<=1) return(price);
   if (ArrayRange(workSsm,0) !=Bars)                 ArrayResize(workSsm,Bars);
   if (ArrayRange(workSsmCoeffs,0) < (instanceNo+1)) ArrayResize(workSsmCoeffs,instanceNo+1);
   if (workSsmCoeffs[instanceNo][_period] != period)
   {
      workSsmCoeffs[instanceNo][_period] = period;
      double a1 = MathExp(-1.414*Pi/period);
      double b1 = 2.0*a1*MathCos(1.414*Pi/period);
         workSsmCoeffs[instanceNo][_c2] = b1;
         workSsmCoeffs[instanceNo][_c3] = -a1*a1;
         workSsmCoeffs[instanceNo][_c1] = 1.0 - workSsmCoeffs[instanceNo][_c2] - workSsmCoeffs[instanceNo][_c3];
   }

   //
   //
   //
   //
   //

      i = Bars-i-1;
      int s = instanceNo*2;   
          workSsm[i][s+_price] = price;
          workSsm[i][s+_ssm]   = workSsmCoeffs[instanceNo][_c1]*(workSsm[i][s+_price]+workSsm[i-1][s+_price])/2.0 + 
                                 workSsmCoeffs[instanceNo][_c2]*workSsm[i-1][s+_ssm]                              + 
                                 workSsmCoeffs[instanceNo][_c3]*workSsm[i-2][s+_ssm];
   return(workSsm[i][s+_ssm]);
}

