//+------------------------------------------------------------------+
//|                        One Side Gaussian Support Resistance Rate |
//|                                                           mladen |
//|                                                                  |
//| original idea and first implementation by : Tinytjan             |
//| (http://codebase.mql4.com/ru/2735)                               |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfxgmail.com"

#property indicator_separate_window
#property indicator_buffers    1
#property indicator_color1     PaleVioletRed
#property indicator_width1     2
#property indicator_minimum    0
#property indicator_maximum    1
#property indicator_level1     0.5
#property indicator_levelcolor DarkSlateGray

//
//
//
//
//

extern string TimeFrame  = "Current time frame";
extern int    SRPeriod   = 40;
extern int    SmoothType = 3;

//
//
//
//
//

double SmoothHigh[];
double SmoothLow[];
double Rate[];
string indicatorFileName;
bool   returnBars;
bool   calculateValue;
int    timeFrame;


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int init()
{
   BuffersInit();
   IndicatorBuffers(3);
      SetIndexBuffer(0, Rate);
      SetIndexBuffer(1, SmoothHigh);
      SetIndexBuffer(2, SmoothLow);
      SmoothType  = MathMax(MathMin(SmoothType,7),0);

      //
      //
      //
      //
      //
      
         indicatorFileName = WindowExpertName();
         calculateValue    = TimeFrame=="calculateValue"; if (calculateValue) { return(0); }
         returnBars        = TimeFrame=="returnBars";     if (returnBars)     { return(0); }
         timeFrame         = stringToTimeFrame(TimeFrame);
      
      //
      //
      //
      //
      //
               
      IndicatorShortName(timeFrameToString(timeFrame)+" One side Gaussian SR rate("+SRPeriod+","+SmoothType+")");   
   return(0);
}

//
//
//
//
//

int start()
{
   int counted_bars=IndicatorCounted();
      if(counted_bars<0) return(-1);
      if(counted_bars>0) counted_bars--;
         int limit = MathMin(Bars-counted_bars,Bars-1);
         if (returnBars) { Rate[0] = MathMin(limit+1,Bars-1); return(0); }

   //
   //
   //
   //
   //

   if (calculateValue || timeFrame == Period())
   {
      for(int i=limit; i>=0; i--) 
      {
         SmoothLow[i]  = Smooth(SmoothType,PRICE_LOW, i);
         SmoothHigh[i] = Smooth(SmoothType,PRICE_HIGH,i);
            double Min = SmoothLow [ArrayMinimum(SmoothLow ,SRPeriod,i)];
            double Max = SmoothHigh[ArrayMaximum(SmoothHigh,SRPeriod,i)];
            if (Min == Max) 
                  Rate[i] = 0;
            else  Rate[i] = (Smooth(SmoothType,PRICE_WEIGHTED,i)-Min)/(Max - Min);
      }
      return(0);
   }      
   
   //
   //
   //
   //
   //
   
   limit = MathMax(limit,MathMin(Bars-1,iCustom(NULL,timeFrame,indicatorFileName,"returnBars",0,0)*timeFrame/Period()));
   for (i=limit; i>=0; i--)
   {
      int y = iBarShift(NULL,timeFrame,Time[i]);
         Rate[i] = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",SRPeriod,SmoothType,0,y);
   }
   return(0);
   
}


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

#define MaxLength 34
int    levels[] = {1,2,3,5,8,13,21,34};
double GaussianBuffer[][8];

//+------------------------------------------------------------------+
//| Gaussian function                                                |
//+------------------------------------------------------------------+
// Counts function Exp((x - x0)^2/s^2)
// x0 - higher point of function
// x  - point function is counted at
// s  - width of function // don't forget about 3-sigma rule

double Gaussian(int Size, int X)
{
   return (MathExp(-X*X*9/((Size + 1)*(Size + 1))));
}

//
//
//
//
//

void BuffersInit()
{
   int i;
   
   ArrayResize(GaussianBuffer,MaxLength);
   for (int k = 0; k < 8; k++)
   {
      double sum = 0.0;
         for (i = 0; i < MaxLength; i++) { if (i>=levels[k]) break; GaussianBuffer[i][k]  = Gaussian(levels[k],i); sum += GaussianBuffer[i][k];}
         for (i = 0; i < MaxLength; i++) { if (i>=levels[k]) break; GaussianBuffer[i][k] /= sum; }
   }                              
}

//
//
//
//
//

double Smooth(int level,int appliedPrice, int shift)
{
   double sum   = 0;
   int    limit = levels[level];
   
   if (shift >= (Bars - limit)) return(iMA(NULL,0,1,0,MODE_SMA,appliedPrice,shift));
   
   //
   //
   //
   //
   //
   
   for (int i = 0; i < limit; i++)
           sum += GaussianBuffer[i][level]*iMA(NULL,0,1,0,MODE_SMA,appliedPrice,shift+i);
   return (sum);
}

//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//

string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,15,30,60,240,1440,10080,43200};

//
//
//
//
//

int stringToTimeFrame(string tfs)
{
   tfs = stringUpperCase(tfs);
   for (int i=ArraySize(iTfTable)-1; i>=0; i--)
         if (tfs==sTfTable[i] || tfs==""+iTfTable[i]) return(MathMax(iTfTable[i],Period()));
                                                      return(Period());
}
string timeFrameToString(int tf)
{
   for (int i=ArraySize(iTfTable)-1; i>=0; i--) 
         if (tf==iTfTable[i]) return(sTfTable[i]);
                              return("");
}

//
//
//
//
//

string stringUpperCase(string str)
{
   string   s = str;

   for (int length=StringLen(str)-1; length>=0; length--)
   {
      int char = StringGetChar(s, length);
         if((char > 96 && char < 123) || (char > 223 && char < 256))
                     s = StringSetChar(s, length, char - 32);
         else if(char > -33 && char < 0)
                     s = StringSetChar(s, length, char + 224);
   }
   return(s);
}