//+------------------------------------------------------------------+
//|                              ema deviations bands - SSL style.mq5|
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 6
#property indicator_plots   3

#property indicator_label1  "SSL Down (Red)"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrYellow
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2

#property indicator_label2  "SSL Up (Lime)"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrAqua
#property indicator_style2  STYLE_SOLID
#property indicator_width2  2

#property indicator_label3  "EMA"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrWhite
#property indicator_style3  STYLE_DOT
#property indicator_width3  1

//--- inputs
input int    Periods    = 20;
input int    Price      = PRICE_CLOSE;
input double Deviations = 1.0;

//--- plot buffers
double buffer1[];   // piros vonal
double buffer2[];   // zöld vonal
double buffer3[];   // EMA középvonal

//--- calculation buffers
double ema1[];      // EMA of price
double ema2[];      // EMA of price^2
double Hlv[];       // trend állapot

//+------------------------------------------------------------------+
int OnInit()
{
   SetIndexBuffer(0, buffer1, INDICATOR_DATA);
   SetIndexBuffer(1, buffer2, INDICATOR_DATA);
   SetIndexBuffer(2, buffer3, INDICATOR_DATA);
   SetIndexBuffer(3, ema1,    INDICATOR_CALCULATIONS);
   SetIndexBuffer(4, ema2,    INDICATOR_CALCULATIONS);
   SetIndexBuffer(5, Hlv,     INDICATOR_CALCULATIONS);

   ArraySetAsSeries(buffer1, false);
   ArraySetAsSeries(buffer2, false);
   ArraySetAsSeries(buffer3, false);
   ArraySetAsSeries(ema1,    false);
   ArraySetAsSeries(ema2,    false);
   ArraySetAsSeries(Hlv,     false);

   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, Periods);
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, Periods);
   PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, Periods);

   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
void OnDeinit(const int reason) {}

//+------------------------------------------------------------------+
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[])
{
   if(rates_total < Periods + 1)
      return(0);

   double alpha = 2.0 / (1.0 + (double)Periods);

   int start = (prev_calculated > 0) ? prev_calculated : 0;

   for(int i = start; i < rates_total; i++)
   {
      double price = GetPrice(i, open, high, low, close);

      if(i == 0)
      {
         ema1[0]    = price;
         ema2[0]    = price * price;
         buffer3[0] = price;
         buffer1[0] = price;
         buffer2[0] = price;
         Hlv[0]     = 0;
         continue;
      }

      // EMA of price and price^2
      ema1[i] = ema1[i-1] + alpha * (price         - ema1[i-1]);
      ema2[i] = ema2[i-1] + alpha * (price * price - ema2[i-1]);

      // EMA középvonal
      buffer3[i] = buffer3[i-1] + alpha * (price - buffer3[i-1]);

      // exponential deviation
      double var = (double)Periods * (ema2[i] - ema1[i] * ema1[i]) / ((double)Periods - 1.0);
      double dev = (var > 0.0) ? MathSqrt(var) : 0.0;

      double upperBand = buffer3[i] + Deviations * dev;
      double lowerBand = buffer3[i] - Deviations * dev;

      // SSL Hlv állapot frissítése
      Hlv[i] = Hlv[i-1];
      if(close[i] > upperBand) Hlv[i] =  1;
      if(close[i] < lowerBand) Hlv[i] = -1;

      // Vonalak felcserélése
      if(Hlv[i] == -1)
      {
         buffer1[i] = upperBand;   // piros = felső
         buffer2[i] = lowerBand;   // zöld  = alsó
      }
      else
      {
         buffer1[i] = lowerBand;   // piros = alsó
         buffer2[i] = upperBand;   // zöld  = felső
      }
   }

   return(rates_total);
}

//+------------------------------------------------------------------+
double GetPrice(int i,
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[])
{
   switch(Price)
   {
      case PRICE_OPEN:     return open[i];
      case PRICE_HIGH:     return high[i];
      case PRICE_LOW:      return low[i];
      case PRICE_CLOSE:    return close[i];
      case PRICE_MEDIAN:   return (high[i] + low[i]) / 2.0;
      case PRICE_TYPICAL:  return (high[i] + low[i] + close[i]) / 3.0;
      case PRICE_WEIGHTED: return (high[i] + low[i] + close[i] + close[i]) / 4.0;
      default:             return close[i];
   }
}
//+------------------------------------------------------------------+