//+------------------------------------------------------------------+
//|                                                 Adaptive EMA.mq4 |
//|                                 Adaptive EMA with ATR and StdDev |
//|           Converted from https://www.tradingview.com/v/W4SLAv9j/ |
//|                                                        by global |
//+------------------------------------------------------------------+
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 6
#property strict

// Input Parameters
extern int             MaxBars           = 0;                 // Maximum Bars, 0=all bars, minimum=500
input int              EMA_Length        = 20;                // EMA Length
input int              Lookback_Period   = 30;                // Lookback Period for StdDev
input double           StdDev_Multiplier = 0.5;               // StdDev Multiplier, default: 2.0
input int              ATR_Length        = 14;                // ATR Length
input double           ATR_Multiplier    = 0.5;               // ATR Multiplier, default: 1.5
//+-----------------------------------------------------------------------------------------------------------+
input  ENUM_LINE_STYLE EMAStyle          = STYLE_SOLID;       // EMA Trend Line Style
input  int             EMAWidth          = 3;                 // EMA Trend Line Width
input  color           EMAUpColor        = clrMediumSeaGreen; // EMA Up Trend Color
input  color           EMADnColor        = clrRed;            // EMA Down Trend Color
input  color           EMARColor         = clrYellow;         // EMA Range Color
//+-----------------------------------------------------------------------------------------------------------+
input  bool            ShowUpper         = true;              // Show Upper StdDev Band?
input  ENUM_LINE_STYLE UpperStyle        = STYLE_DOT;         // Upper Band Style
input  int             UpperWidth        = 1;                 // Upper Band Width
input  color           UpperColor        = clrMediumSeaGreen; // Upper Band Color
//+-----------------------------------------------------------------------------------------------------------+
input  bool            ShowLower         = true;              // Show Lower StdDev Band?
input  ENUM_LINE_STYLE LowerStyle        = STYLE_DOT;         // Lower Band Style
input  int             LowerWidth        = 1;                 // Lower Band Width
input  color           LowerColor        = clrRed;            // Lower Band Color
//+-----------------------------------------------------------------------------------------------------------+

//---- Internal variables
int maxPeriod;

// Buffers
double EMA_Buffer[],EMAa[],EMAb[];
double Upper_Band[],Lower_Band[];
double TrendState[];

// Initialize the Indicator
int OnInit()
{
   IndicatorBuffers(6);
   SetIndexBuffer(0,EMA_Buffer,INDICATOR_DATA); SetIndexLabel(0,"EMA");        SetIndexStyle(0,DRAW_LINE,EMAStyle,EMAWidth,EMAUpColor);
   SetIndexBuffer(1,EMAa,INDICATOR_DATA);       SetIndexLabel(1,"EMAa");       SetIndexStyle(1,DRAW_LINE,EMAStyle,EMAWidth,EMADnColor);
   SetIndexBuffer(2,EMAb,INDICATOR_DATA);       SetIndexLabel(2,"EMAb");       SetIndexStyle(2,DRAW_LINE,EMAStyle,EMAWidth,EMARColor);
   SetIndexBuffer(3,Upper_Band,INDICATOR_DATA); SetIndexLabel(3,"Upper");      SetIndexStyle(3,ShowUpper ? DRAW_LINE : DRAW_NONE,UpperStyle,UpperWidth,UpperColor);
   SetIndexBuffer(4,Lower_Band,INDICATOR_DATA); SetIndexLabel(4,"Lower");      SetIndexStyle(4,ShowLower ? DRAW_LINE : DRAW_NONE,LowerStyle,LowerWidth,LowerColor); 
   SetIndexBuffer(5,TrendState);                SetIndexLabel(5,"TrendState"); SetIndexStyle(5,DRAW_NONE); 

   maxPeriod=MathMax(EMA_Length,Lookback_Period);
   maxPeriod=MathMax(maxPeriod,ATR_Length);
   if(MaxBars>0 && MaxBars<500) MaxBars=500;

   IndicatorShortName("Adaptive EMA");
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom indicator de-initialization function                      |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
// Calculate the Indicator
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,counted_bars=prev_calculated;
   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
   int limit = fmin(rates_total-counted_bars,rates_total-maxPeriod);
   if(MaxBars>0 && limit>MaxBars) limit=MaxBars;

   if(TrendState[limit]==-1) CleanPoint(limit,EMAa,EMAb);
   for(i=limit; i>=0 && !_StopFlag; i--)
   {
      // Calculate EMA
      EMA_Buffer[i] = iMA(NULL, 0, EMA_Length, 0, MODE_EMA, PRICE_CLOSE, i);

      // Calculate Standard Deviation
      double stddev = iDeviation(EMA_Buffer,Lookback_Period,i);

      // Calculate Upper and Lower Bands
      Upper_Band[i] = EMA_Buffer[i] + (stddev * StdDev_Multiplier);
      Lower_Band[i] = EMA_Buffer[i] - (stddev * StdDev_Multiplier);

      // Calculate ATR
      double atr = iATR(NULL, 0, ATR_Length, i);
      double atr_upper = EMA_Buffer[i] + (atr * ATR_Multiplier);
      double atr_lower = EMA_Buffer[i] - (atr * ATR_Multiplier);

      // Trend Detection
      if(close[i] > Upper_Band[i] && close[i] > atr_upper) { TrendState[i] = 1; }
      else if(close[i] < Lower_Band[i] && close[i] < atr_lower) { TrendState[i] = -1; }
      else { TrendState[i] = TrendState[i+1]; }

      EMAa[i] = EMAb[i] = EMPTY_VALUE;
      if(TrendState[i]==-1) PlotPoint(i,EMAa,EMAb,EMA_Buffer);
   }
   
   return(rates_total);
}

double iDeviation(double& array[], int period, int pos)
{
   double dMA  = iSma(array,period,pos);
   double dSum = 0;
      for(int i=0; i<period; i++,pos++) dSum += (array[pos]-dMA)*(array[pos]-dMA);
   return(MathSqrt(dSum/period));
}

double iSma(double& array[], int period, int pos)
{
   double sum = 0.0;
      for(int i=0; i<period; i++,pos++) sum += array[pos];
   return(sum/period);     
}

void CleanPoint(int i,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 PlotPoint(int i,double& first[],double& second[],double& from[])
{
   if(i>Bars-3) 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;
   }
}
//+------------------------------------------------------------------+

//+--------------------------- END ----------------------------------+
