//+------------------------------------------------------------------+
//|                                                        rsx on oma|
//|                                                           mladen |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"



#property indicator_separate_window
#property indicator_buffers 4
#property indicator_color1  Orange
#property indicator_width1  4
#property indicator_color2  White
#property indicator_style2  STYLE_DASH
#property indicator_color3  Crimson
#property indicator_width3  3
#property indicator_color4  LimeGreen
#property indicator_width4  3


//
//
//
//
//

extern int    RsxLength        = 14;
extern int    Price            = 0;
extern int    OmaLength        = 5;
extern double OmaSpeed         = 8.0;
extern bool   OmaAdaptive      = true;
extern int    HighLowPeriod    = 30;
extern bool   ShowChannel      = true;
extern bool   ShowZigZag       = true;
extern int    buyarrowwidth    = 2;
extern color  buyarrowcolor    = Lime;
extern int    sellarrowwidth   = 2;
extern color  sellarrowcolor   = Crimson;
extern int    buy1arrowwidth   = 2;
extern color  buy1arrowcolor   = Aqua;
extern int    sell1arrowwidth  = 2;
extern color  sell1arrowcolor  = Magenta;

extern string note             = "turn on Alert = true; turn off = false";
extern bool   alertsOn         = true;
extern bool   alertsOnCurrent  = true;
extern bool   alertsMessage    = true;
extern bool   alertsSound      = true;
extern bool   alertsEmail      = false;
extern string soundfile        = "alert2.wav";

//
//
//
//
//

double rsx[];
double HighBuffer[];
double LowBuffer[];
double ZigZagBuffer[];
double ZigZagLow[];
double ZigZagHigh[];
double trend[];

double wrkBuffer[][13];
double stored[][7];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int init()
{
   IndicatorBuffers(6);
   SetIndexBuffer(0,rsx); SetIndexLabel(0,"RSX");
   SetIndexBuffer(1,ZigZagBuffer);
   SetIndexBuffer(2,HighBuffer);
   SetIndexBuffer(3,LowBuffer);
   SetIndexBuffer(4,ZigZagLow);
   SetIndexBuffer(5,ZigZagHigh);
   SetIndexBuffer(6,trend);
   SetIndexStyle(1,DRAW_SECTION);
   SetIndexEmptyValue(0,0);
   SetIndexEmptyValue(1,0);
   SetIndexEmptyValue(4,0);
   SetIndexEmptyValue(5,0);
   SetIndexLabel(1,NULL);
         
    if (ShowChannel)
            {
               SetIndexStyle(2,DRAW_LINE);
               SetIndexStyle(3,DRAW_LINE);
            }
         else      
            {
               SetIndexStyle(2,DRAW_NONE);
               SetIndexStyle(3,DRAW_NONE);
            }
      OmaLength = MathMax(OmaLength,   1);
      OmaSpeed  = MathMax(OmaSpeed ,-1.5);
      
      IndicatorShortName("rsx channel on oma ("+RsxLength+","+OmaLength+","+DoubleToStr(OmaSpeed,2)+")");
   return(0);
}
int deinit() 
{ 
      for(int j=Bars; j>=0; j--)
      {
      ObjectDelete("Sell"+DoubleToStr(j,0));
      ObjectDelete("Buy" +DoubleToStr(j,0));

      ObjectDelete("Sell1"+DoubleToStr(j,0));
      ObjectDelete("Buy1" +DoubleToStr(j,0));

      }

return(0); 
}




//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int start()
{
   int counted_bars=IndicatorCounted();
   int lastZag;
   int i,r,limit;

   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
         limit = Bars-counted_bars;
         if (ArrayRange(wrkBuffer,0) != Bars) { ArrayResize(wrkBuffer,Bars); ArrayResize(stored,Bars); }
         
         if (ShowZigZag)
         for (lastZag=limit+1; lastZag<Bars; lastZag++) if (ZigZagLow[lastZag] != 0 || ZigZagHigh[lastZag] != 0) break;

   //
   //
   //
   //
   //
   
   double Kg = (3.0)/(2.0+RsxLength);
   double Hg = 1.0-Kg;
   for(i=limit, r=Bars-i-1; i>=0; i--, r++)
   {
      wrkBuffer[r][12] = iAverage(iMA(NULL,0,1,0,MODE_SMA,Price,i),OmaLength,OmaSpeed,OmaAdaptive,r);

         if (i==(Bars-1)) { for (int c=0; c<12; c++) wrkBuffer[r][c] = 0; continue; }  

      //
      //
      //
      //
      //
      
      double roc = wrkBuffer[r][12]-wrkBuffer[r-1][12];
      double roa = MathAbs(roc);
      for (int k=0; k<3; k++)
      {
         int kk = k*2;
            wrkBuffer[r][kk+0] = Kg*roc                + Hg*wrkBuffer[r-1][kk+0];
            wrkBuffer[r][kk+1] = Kg*wrkBuffer[r][kk+0] + Hg*wrkBuffer[r-1][kk+1]; roc = 1.5*wrkBuffer[r][kk+0] - 0.5 * wrkBuffer[r][kk+1];
            wrkBuffer[r][kk+6] = Kg*roa                + Hg*wrkBuffer[r-1][kk+6];
            wrkBuffer[r][kk+7] = Kg*wrkBuffer[r][kk+6] + Hg*wrkBuffer[r-1][kk+7]; roa = 1.5*wrkBuffer[r][kk+6] - 0.5 * wrkBuffer[r][kk+7];
      }
      if (roa != 0)
           rsx[i] = MathMax(MathMin((roc/roa+1.0)*50.0,100.00),0.00); 
      else rsx[i] = 50.0;
      
      
      LowBuffer[i]   = rsx[ArrayMinimum(rsx,HighLowPeriod,i)];
      HighBuffer[i]  = rsx[ArrayMaximum(rsx,HighLowPeriod,i)];
      
      if (!ShowZigZag) continue;
      
      if (rsx[i] > LowBuffer[i] && rsx[i+1]==LowBuffer[i+1]) 
      { 
            ObjectCreate("Buy"+DoubleToStr(i,0),OBJ_ARROW,0,Time[i],Low[i]-iATR(NULL,0,20,i)/2.0); 
            ObjectSet   ("Buy"+DoubleToStr(i,0),OBJPROP_ARROWCODE,228);
            ObjectSet   ("Buy"+DoubleToStr(i,0),OBJPROP_WIDTH,buyarrowwidth);
            ObjectSet   ("Buy"+DoubleToStr(i,0),OBJPROP_COLOR,buyarrowcolor);
            trend[i] = 1; 
            }

         if (rsx[i] < HighBuffer[i] && rsx[i+1]==HighBuffer[i+1]) 
         {  
            ObjectCreate("Sell"+DoubleToStr(i,0),OBJ_ARROW,0,Time[i],High[i]+iATR(NULL,0,20,i)/2.0); 
            ObjectSet   ("Sell"+DoubleToStr(i,0),OBJPROP_ARROWCODE,230);
            ObjectSet   ("Sell"+DoubleToStr(i,0),OBJPROP_WIDTH,sellarrowwidth);
            ObjectSet   ("Sell"+DoubleToStr(i,0),OBJPROP_COLOR,sellarrowcolor);
            trend[i] = -1; 
            }

       
       
         if (HighBuffer[i] > HighBuffer[i+1] && HighBuffer[i+1]==HighBuffer[i+2])
            {
            ObjectCreate("Buy1"+DoubleToStr(i,0),OBJ_ARROW,0,Time[i],Low[i]-iATR(NULL,0,20,i)/2.0); 
            ObjectSet   ("Buy1"+DoubleToStr(i,0),OBJPROP_ARROWCODE,225);
            ObjectSet   ("Buy1"+DoubleToStr(i,0),OBJPROP_WIDTH,buy1arrowwidth);
            ObjectSet   ("Buy1"+DoubleToStr(i,0),OBJPROP_COLOR,buy1arrowcolor);
            }

         if (LowBuffer[i] < LowBuffer[i+1] && LowBuffer[i+1]==LowBuffer[i+2])
            {
            ObjectCreate("Sell1"+DoubleToStr(i,0),OBJ_ARROW,0,Time[i],High[i]+iATR(NULL,0,20,i)/2.0); 
            ObjectSet   ("Sell1"+DoubleToStr(i,0),OBJPROP_ARROWCODE,226);
            ObjectSet   ("Sell1"+DoubleToStr(i,0),OBJPROP_WIDTH,sell1arrowwidth);
            ObjectSet   ("Sell1"+DoubleToStr(i,0),OBJPROP_COLOR,sell1arrowcolor);
            }


      
       ZigZagLow[i]  = 0;
       ZigZagHigh[i] = 0;
         if (LowBuffer[i] < LowBuffer[i+1])
            {
               if (ZigZagBuffer[lastZag] == LowBuffer[lastZag])
                   ZigZagBuffer[lastZag] = 0;
                   ZigZagBuffer[i]       =  LowBuffer[i];
                   ZigZagLow[i]          =  LowBuffer[i];
                                 lastZag = i;
                                 continue;
            }
         if (HighBuffer[i] > HighBuffer[i+1])
            {
               if (ZigZagBuffer[lastZag] == HighBuffer[lastZag])
                   ZigZagBuffer[lastZag] = 0;
                   ZigZagBuffer[i]       =  HighBuffer[i];
                   ZigZagHigh[i]         =  HighBuffer[i];
                                 lastZag = i;
                                 continue;
            }
         if (ZigZagBuffer[i] != 0)
            {
               ZigZagBuffer[i] = 0;
               for (lastZag=i+1; lastZag<Bars; lastZag++)
               {
                  if (ZigZagLow[lastZag]  != 0) { ZigZagBuffer[lastZag] = ZigZagLow[lastZag];  break; }
                  if (ZigZagHigh[lastZag] != 0) { ZigZagBuffer[lastZag] = ZigZagHigh[lastZag]; break; }
               }
            }
   }
   
   if (alertsOn)
      {
      if (alertsOnCurrent)
           int whichBar = 0;
      else     whichBar = 1;

         //
         //
         //
         //
         //
         
         if (trend[whichBar] != trend[whichBar+1])
         if (trend[whichBar] == 1)
               doAlert("uptrend");
         else  doAlert("downtrend");       
   }
   
   return(0);
}


void doAlert(string doWhat)
{
   static string   previousAlert="nothing";
   static datetime previousTime;
   string message;
   
      if (previousAlert != doWhat || previousTime != Time[0]) {
          previousAlert  = doWhat;
          previousTime   = Time[0];

          //
          //
          //
          //
          //

          message =  StringConcatenate(Symbol()," at ",TimeToStr(TimeLocal(),TIME_SECONDS),"rsx oma channel",doWhat);
             if (alertsMessage) Alert(message);
             if (alertsEmail)   SendMail(StringConcatenate(Symbol(),"rsx oma channel"),message);
             if (alertsSound)   PlaySound(soundfile);
      }
}
   


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

#define E1  0
#define E2  1
#define E3  2
#define E4  3
#define E5  4
#define E6  5
#define res 6

//
//
//
//
//

double iAverage(double price, double averagePeriod, double const, bool adaptive, int r, int ashift=0)
{
   double e1=stored[r-1][E1+ashift];  double e2=stored[r-1][E2+ashift];
   double e3=stored[r-1][E3+ashift];  double e4=stored[r-1][E4+ashift];
   double e5=stored[r-1][E5+ashift];  double e6=stored[r-1][E6+ashift];

   //
   //
   //
   //
   //

      if (adaptive && (averagePeriod > 1))
      {
         double minPeriod = averagePeriod/2.0;
         double maxPeriod = minPeriod*5.0;
         int    endPeriod = MathCeil(maxPeriod);
         double signal    = MathAbs((price-stored[r-endPeriod][res]));
         double noise     = 0.00000000001;

            for(int k=1; k<endPeriod; k++) noise=noise+MathAbs(price-stored[r-k][res]);

         averagePeriod = ((signal/noise)*(maxPeriod-minPeriod))+minPeriod;
      }
      
      //
      //
      //
      //
      //
      
      double alpha = (2.0+const)/(1.0+const+averagePeriod);

      e1 = e1 + alpha*(price-e1); e2 = e2 + alpha*(e1-e2); double v1 = 1.5 * e1 - 0.5 * e2;
      e3 = e3 + alpha*(v1   -e3); e4 = e4 + alpha*(e3-e4); double v2 = 1.5 * e3 - 0.5 * e4;
      e5 = e5 + alpha*(v2   -e5); e6 = e6 + alpha*(e5-e6); double v3 = 1.5 * e5 - 0.5 * e6;

   //
   //
   //
   //
   //

   stored[r][E1+ashift]  = e1;  stored[r][E2+ashift] = e2;
   stored[r][E3+ashift]  = e3;  stored[r][E4+ashift] = e4;
   stored[r][E5+ashift]  = e5;  stored[r][E6+ashift] = e6;
   stored[r][res+ashift] = price;
   return(v3);
}