//------------------------------------------------------------------
#property copyright "dr.house7 & mladen"
#property link      "www.forex-station.com"
//------------------------------------------------------------------
#property indicator_separate_window
#property indicator_buffers 7
#property indicator_color1  DimGray  
#property indicator_color2  DarkGray
#property indicator_color3  Red
#property indicator_color4  LimeGreen
#property indicator_color5  Red
#property indicator_color6  LimeGreen
#property indicator_color7  Red
#property indicator_width1  2
#property indicator_width2  2
#property indicator_width6  3
#property indicator_width7  3
#property indicator_level1  0

//
//
//
//
//

extern int    RsiPeriod1   = 14;
extern double Speed1       = 1.2;
extern int    RsiPrice1    = PRICE_CLOSE;
extern int    RsiPeriod2   = 34;
extern double Speed2       = 0.8;
extern int    RsiPrice2    = PRICE_CLOSE;
extern int    SignalPeriod = 9;
extern int    SignalMethod = MODE_SMA;
extern double AccStep      = 0.01;
extern double AccLimit     = 0.1;

double macdh[];
double macd[];
double signal[];
double sarUp[];
double sarDn[];
double saraUp[];
double saraDn[];

//------------------------------------------------------------------
//
//------------------------------------------------------------------
// 
//
//
//
//

int init()
{
   SetIndexBuffer(0,macdh); SetIndexStyle(0,DRAW_HISTOGRAM);
   SetIndexBuffer(1,macd); 
   SetIndexBuffer(2,signal); 
   SetIndexBuffer(3,sarUp);  SetIndexStyle(3,DRAW_ARROW); SetIndexArrow(3,159);
   SetIndexBuffer(4,sarDn);  SetIndexStyle(4,DRAW_ARROW); SetIndexArrow(4,159);
   SetIndexBuffer(5,saraUp); SetIndexStyle(5,DRAW_ARROW); SetIndexArrow(5,159);
   SetIndexBuffer(6,saraDn); SetIndexStyle(6,DRAW_ARROW); SetIndexArrow(6,159);
      IndicatorShortName("Parabolic marsi adaptive MACD("+RsiPeriod1+","+DoubleToStr(Speed1,2)+","+RsiPeriod2+","+DoubleToStr(Speed2,2)+")");
   return(0);
}
int start()
{
   int i,limit,counted_bars=IndicatorCounted();
      if(counted_bars<0) return(-1);
      if(counted_bars>0) counted_bars--;
         limit = MathMin(Bars-counted_bars,Bars-1);

   //
   //
   //
   //
   //

   for(i=limit; i>=0; i--) 
   {
      double sarClose;
      double sarOpen;
      double sarPosition;
      double sarChange;
      double macdHi = iMaRsi(High[i],RsiPeriod1,Speed1,i,0) - iMaRsi(High[i],RsiPeriod2,Speed2,i,1);
      double macdLo = iMaRsi(Low[i], RsiPeriod1,Speed1,i,2) - iMaRsi(Low[i], RsiPeriod2,Speed2,i,3);
      macd[i]   = iMaRsi((macdHi+macdLo)/2.0,RsiPeriod1,Speed1,i,4)-iMaRsi((macdHi+macdLo)/2.0,RsiPeriod2,Speed2,i,5);
      iParabolic(macd[i],macd[i],AccStep,AccLimit,sarClose,sarOpen,sarPosition,sarChange,i);
      macdh[i]  = macd[i];
      sarUp[i]  = EMPTY_VALUE;
      sarDn[i]  = EMPTY_VALUE;
      saraUp[i] = EMPTY_VALUE;
      saraDn[i] = EMPTY_VALUE;
      
      if (sarPosition==1)
            sarUp[i] = sarClose;
      else  sarDn[i] = sarClose;
      if (sarChange!=0)
         if (sarPosition==1)
               saraUp[i] = sarClose;
         else  saraDn[i] = sarClose;
   }   
   for(i=limit; i>=0; i--) signal[i] = iMAOnArray(macd,0,SignalPeriod,0,SignalMethod,i);
   return(0);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

double workMaRsi[][6];
double iMaRsi(int price, int rsiPeriod, double speed, int i, int instanceNo=0)
{
   if (ArrayRange(workMaRsi,0)!=Bars) ArrayResize(workMaRsi,Bars); int r = Bars-i-1;

   //
   //
   //
   //
   //
   
   double tprice = iMA(NULL,0,1,0,MODE_SMA,price,i);
      if (r<rsiPeriod)
            workMaRsi[r][instanceNo] = tprice;
      else  workMaRsi[r][instanceNo] = workMaRsi[r-1][instanceNo]+(speed*MathAbs(iRSI(NULL,0,rsiPeriod,price,i)/100.0-0.5))*(tprice-workMaRsi[r-1][instanceNo]);
   return(workMaRsi[r][instanceNo]);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

double work[][7];
#define _high     0
#define _low      1
#define _ohigh    2
#define _olow     3
#define _open     4
#define _position 5
#define _af       6


void iParabolic(double high, double low, double step, double limit, double& pClose, double& pOpen, double& pPosition, double& pChange, int i)
{
   if (ArrayRange(work,0)!=Bars) ArrayResize(work,Bars); i = Bars-i-1;
   
   //
   //
   //
   //
   //

      pChange = 0;
         work[i][_ohigh]    = high;
         work[i][_olow]     = low;
            if (i<1)
               {
                  work[i][_high]     = high;
                  work[i][_low]      = low;
                  work[i][_open]     = high;
                  work[i][_position] = -1;
                  return;
               }
         work[i][_open]     = work[i-1][_open];
         work[i][_af]       = work[i-1][_af];
         work[i][_position] = work[i-1][_position];
         work[i][_high]     = MathMax(work[i-1][_high],high);
         work[i][_low]      = MathMin(work[i-1][_low] ,low );

   //
   //
   //
   //
   //
   
   if (work[i][_position] == 1)
      if (low<=work[i][_open])
         {
            work[i][_position] = -1;
               pChange = -1;
               pClose  = work[i][_high];
                         work[i][_high] = high;
                         work[i][_low]  = low;
                         work[i][_af]   = step;
                         work[i][_open] = pClose + work[i][_af]*(work[i][_low]-pClose);
                            if (work[i][_open]<work[i  ][_ohigh]) work[i][_open] = work[i  ][_ohigh];
                            if (work[i][_open]<work[i-1][_ohigh]) work[i][_open] = work[i-1][_ohigh];
         }
      else
         {
               pClose = work[i][_open];
                    if (work[i][_high]>work[i-1][_high] && work[i][_af]<limit) work[i][_af] = MathMin(work[i][_af]+step,limit);
                        work[i][_open] = pClose + work[i][_af]*(work[i][_high]-pClose);
                            if (work[i][_open]>work[i  ][_olow]) work[i][_open] = work[i  ][_olow];
                            if (work[i][_open]>work[i-1][_olow]) work[i][_open] = work[i-1][_olow];
         }
   else
      if (high>=work[i][_open])
         {
            work[i][_position] = 1;
               pChange = 1;
               pClose  = work[i][_low];
                         work[i][_high] = high;
                         work[i][_low]  = low;
                         work[i][_af]   = step;
                         work[i][_open] = pClose + work[i][_af]*(work[i][_high]-pClose);
                            if (work[i][_open]>work[i  ][_olow]) work[i][_open] = work[i  ][_olow];
                            if (work[i][_open]>work[i-1][_olow]) work[i][_open] = work[i-1][_olow];
         }
      else
         {
               pClose = work[i][_open];
               if (work[i][_low]<work[i-1][_low] && work[i][_af]<limit) work[i][_af] = MathMin(work[i][_af]+step,limit);
                   work[i][_open] = pClose + work[i][_af]*(work[i][_low]-pClose);
                            if (work[i][_open]<work[i  ][_ohigh]) work[i][_open] = work[i  ][_ohigh];
                            if (work[i][_open]<work[i-1][_ohigh]) work[i][_open] = work[i-1][_ohigh];
         }

   //
   //
   //
   //
   //
   
   pOpen     = work[i][_open];
   pPosition = work[i][_position];
}