//+------------------------------------------------------------------+
//|                                             Angle of average.mq4 |
//|                                                           mladen |
//+------------------------------------------------------------------+
#property  copyright "mladen"

#property  indicator_separate_window
#property  indicator_buffers 4
#property  indicator_color1  LimeGreen
#property  indicator_color2  Orange
#property  indicator_color3  DimGray
#property  indicator_color4  Gray
#property  indicator_width1  2
#property  indicator_width2  2
#property  indicator_width4  2


//
//
//
//
//

extern int    NlmaPeriod       = 14;
extern ENUM_APPLIED_PRICE    NlmaPrice        = PRICE_CLOSE;
extern double AngleLevel       = 8;
extern int    AngleBars        = 6;

//
//
extern bool   ShowBadAngleZoneInMainChart = false;
extern string UniqueID  = "Angle MA zones";
extern color  ColorBadAngle    = C'98,26,19';
//extern double MaxValue         = 35000; 
double Dummy     = -1;
//
//

double Buffer1[];
double Buffer2[];
double Buffer3[];
double Buffer4[];
double colors[];
double times[];

int ChartScale,BarWidth;
double window_top,window_bottom;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int init()
{
  ChartScale = ChartScaleGet();             
        if(ChartScale == 0) {BarWidth = 1;}
  else {if(ChartScale == 1) {BarWidth = 1;}      
  else {if(ChartScale == 2) {BarWidth = 2;}
  else {if(ChartScale == 3) {BarWidth = 4;}
  else {if(ChartScale == 4) {BarWidth = 6;}
  else {BarWidth = 13;} }}}}
   
   IndicatorBuffers(6);
   SetIndexBuffer(0,Buffer1);
   SetIndexBuffer(1,Buffer2);
   SetIndexBuffer(2,Buffer3);
   SetIndexBuffer(3,Buffer4);
   SetIndexStyle(0,DRAW_HISTOGRAM,0, BarWidth);
   SetIndexStyle(1,DRAW_HISTOGRAM,0, BarWidth);
   SetIndexStyle(2,DRAW_HISTOGRAM,0, BarWidth);
   SetIndexBuffer(4,colors);
   SetIndexBuffer(5,times);
   //
   //
   //
   //
   //
      SetLevelValue(0, AngleLevel);
      SetLevelValue(1,-AngleLevel);
   IndicatorShortName("angle of nlma ("+NlmaPeriod+","+DoubleToStr(AngleLevel,2)+","+AngleBars+")");
   IndicatorDigits(2);
      
   window_top=WindowPriceMax()+iATR(Symbol(),PERIOD_D1,5,0);
   window_bottom=MathMax(0,WindowPriceMin()-iATR(Symbol(),PERIOD_D1,5,0));
   
   return(0);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int deinit()
{
   if (ShowBadAngleZoneInMainChart) {
      string lookFor       = UniqueID+":";
      int    lookForLength = StringLen(lookFor);
      for (int i=ObjectsTotal()-1; i>=0; i--)
      {
         string objectName = ObjectName(i);
            if (StringSubstr(objectName,0,lookForLength) == lookFor) ObjectDelete(objectName);
      }
   }
   return(0);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

#define Pi 3.141592653589793238462643

//
//
//
//
//

int start()
{
   int countedBars = IndicatorCounted();
      if(countedBars<0) return(-1);
      if(countedBars>0) countedBars--;
         int limit = MathMin(Bars-countedBars,Bars-1);
            
      if (Dummy<=Time[0]) Dummy = Time[0];
      static bool secondTime=false;
         if (secondTime)
         {
            for (;limit<Bars; limit++)
            {
               //Print("for secondTime ("+limit+")");
               if (colors[limit]!=colors[limit+1]) break;
            }
         }
         else secondTime=true;
   //
   //
   //
   //
   //
   
   for(int i=limit; i>=0; i--)
   {
      double range  = iATR(NULL,0,AngleBars*20,i);
      double angle  = 0.00;
      double price1 = iMA(NULL,0,1,0,MODE_SMA,NlmaPrice,i);
      double price2 = iMA(NULL,0,1,0,MODE_SMA,NlmaPrice,i+AngleBars);
      double change = iNonLagMa(price1,NlmaPeriod,i,0)-iNonLagMa(price2,NlmaPeriod,i,1);

         if (range != 0) angle = MathArctan(change/(range*AngleBars))*180.0/Pi;

      //
      //
      //
      //
      //
         colors[i]  = colors[i+1];
         times[i]   = times[i+1];
         
         string name = UniqueID+":"+Time[i];
               ObjectDelete(name);
               
      
         Buffer1[i] = EMPTY_VALUE;
         Buffer2[i] = EMPTY_VALUE;
         Buffer3[i] = angle;
         Buffer4[i] = angle;
         
         
            if (angle > AngleLevel) { 
               Buffer1[i] = angle; 
               Buffer3[i] = EMPTY_VALUE;
               colors[i] =  1;
            } 
            else if (angle < -AngleLevel) { 
               Buffer2[i] = angle; 
               Buffer3[i] = EMPTY_VALUE;
               colors[i] =  1;
            } 
            else {
               colors[i] =  EMPTY_VALUE;
            }
            
            if (ShowBadAngleZoneInMainChart) {
               if ((colors[i]!=colors[i+1]) || (i==0 && colors[i]!=1))
               {
                  times[i]= Time[i];
                  if (times[i+1]<Time[0])
                  {
                     //datetime lastTime = Time[i];
                     datetime lastTime = Time[i+1]; 
                     if (i==0) lastTime = Dummy;
                     
                     if (i==0 && colors[i]==EMPTY_VALUE) {
                        colors[i]=2;
                     }
                              
                     int clr = colors[i];
                     switch (clr)
                     {
                        case  1 : 
                        case  2 :
                           ObjectCreate(name,OBJ_RECTANGLE,0,times[i+1],window_bottom,lastTime,window_top);
                           ObjectSet(name,OBJPROP_BACK,true);
                           ObjectSet(name,OBJPROP_COLOR,ColorBadAngle);
                           break;
                        default :  
                           break;
                    }                        
                 }                     
               } 
            } //END if (ShowBadAngleZoneInMainChart) {
            
            
   }
   return(0);
}

//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//

#define _length  0
#define _len     1

double  nlmvalues[][2];
double  nlmprices[][2];
double  nlmalphas[][2];

//
//
//
//
//

double iNonLagMa(double price, double length, int r, int instanceNo=0)
{
   r = Bars-r-1;
   if (ArrayRange(nlmprices,0) != Bars)         ArrayResize(nlmprices,Bars);
   if (ArrayRange(nlmvalues,0) <  instanceNo+1) ArrayResize(nlmvalues,instanceNo+1);
                               nlmprices[r][instanceNo]=price;
   if (length<3 || r<3) return(nlmprices[r][instanceNo]);
   
   //
   //
   //
   //
   //
   
   if (nlmvalues[instanceNo][_length] != length  || ArraySize(nlmalphas)==0)
   {
      double Cycle = 4.0;
      double Coeff = 3.0*Pi;
      int    Phase = length-1;
      
         nlmvalues[instanceNo][_length] = length;
         nlmvalues[instanceNo][_len   ] = length*4 + Phase;  

         if (ArrayRange(nlmalphas,0) < nlmvalues[instanceNo][_len]) ArrayResize(nlmalphas,nlmvalues[instanceNo][_len]);
         for (int k=0; k<nlmvalues[instanceNo][_len]; k++)
         {
            if (k<=Phase-1) 
                 double t = 1.0 * k/(Phase-1);
            else        t = 1.0 + (k-Phase+1)*(2.0*Cycle-1.0)/(Cycle*length-1.0); 
            double beta = MathCos(Pi*t);
            double g = 1.0/(Coeff*t+1); if (t <= 0.5 ) g = 1;
      
            nlmalphas[k][instanceNo] = g * beta;
         }
   }
   
   //
   //
   //
   //
   //
   
    double sum = 0, sumw = 0;
        for (k=0; k < nlmvalues[instanceNo][_len] && (r-k)>=0; k++) { sum += nlmalphas[k][instanceNo]*nlmprices[r-k][instanceNo]; sumw += nlmalphas[k][instanceNo]; }
        if (sumw!=0)
             return(sum/sumw);
        else return(price);
}

//
//
//
//
//

void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)                                                    
{
  ChartScale = ChartScaleGet();
  init();  
}

//
//
//
//
//

int ChartScaleGet()
{
  long result = -1;
  ChartGetInteger(0,CHART_SCALE,0,result);
  return((int)result);
}
