//+-----------------------------------------------------------------+
//+           Spearman,Rosh Bookkeeper, 2007, yuzefovich@gmail.com  +
//+           Leledc:added MaBuffer,alerts                          +
//+                                                                 +
//+-----------------------------------------------------------------+
#property indicator_separate_window
#property indicator_buffers  6
#property indicator_color1 clrDodgerBlue
#property indicator_width1 2
#property indicator_color2 clrOrange
#property indicator_width2 2
#property indicator_color3 clrDodgerBlue
#property indicator_width3 1
#property indicator_color4 clrMagenta
#property indicator_width4 1
#property indicator_color5 clrWhite
#property indicator_width5 1
#property indicator_color6 clrWhite
#property indicator_width6 1
#property indicator_maximum 1.1
#property indicator_minimum -1.1
//---- input parameters
//---- Snake 
extern ENUM_TIMEFRAMES TimeFrame   = PERIOD_CURRENT; // Time frame
extern int            SnakeRange   = 13; 
extern int            FilterPeriod = 21; 
extern double         MartFiltr    = 2;
extern int            PriceConst   = 6; 
extern int            MaPeriod     = 5;
extern ENUM_MA_METHOD MaMode       = MODE_LWMA;
extern double         LevelsCross  = 0.95;
extern int            Countbars    = 567;
extern bool           AlertOn      = false;
extern int            ArrowUp      = 225;
extern int            ArrowDown    = 108;
extern int            ArrowUp2     = 108;
extern int            ArrowDown2   = 108;
input bool            ArrowOnFirst = false;
 input bool           Interpolate  = true;           // Interpolate in mtf mode
                               
//---- buffers
double SRC[],Axis[],Mart[],Ma[],Up[],Down[],Up2[],Down2[],count[];

//---- SpearmanRankCorrelation
int    rangeN = 14; //   = 30 maximum
double R2[];
double multiply;
int    PriceInt[];
int    SortInt[];
bool TurnedUp = false;
bool TurnedDown = false;
string indicatorFileName;
#define _mtfCall(_buff,_ind) iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,SnakeRange,FilterPeriod,MartFiltr,PriceConst,MaPeriod,MaMode,LevelsCross,Countbars,AlertOn,ArrowUp,ArrowDown,ArrowUp2,ArrowDown2,ArrowOnFirst,_buff,_ind)


int init() { 
    IndicatorDigits(MarketInfo(Symbol(),MODE_DIGITS));

IndicatorBuffers(9);
SetIndexBuffer(0,SRC);   SetIndexStyle(0,DRAW_LINE);
SetIndexBuffer(1,Ma);    SetIndexStyle(1,DRAW_LINE);
SetIndexBuffer(2,Up);    SetIndexStyle(2,DRAW_ARROW); SetIndexArrow(2,ArrowUp);
SetIndexBuffer(3,Down);  SetIndexStyle(3,DRAW_ARROW); SetIndexArrow(3,ArrowDown);
SetIndexBuffer(4,Up2);   SetIndexStyle(4,DRAW_ARROW); SetIndexArrow(4,ArrowUp2);
SetIndexBuffer(5,Down2); SetIndexStyle(5,DRAW_ARROW); SetIndexArrow(5,ArrowDown2);
SetIndexBuffer(6,Axis);      
SetIndexBuffer(7,Mart);  
SetIndexBuffer(8,count);     

SetLevelValue(0,LevelsCross);
SetLevelValue(1,-LevelsCross);
SetLevelValue(2,0);

ArrayResize(R2,rangeN);
 ArrayResize(PriceInt,rangeN);
ArrayResize(SortInt,rangeN);

indicatorFileName = WindowExpertName();
TimeFrame         = fmax(TimeFrame,_Period);

IndicatorShortName(timeFrameToString(TimeFrame)+ WindowExpertName()+"( SR:"+SnakeRange+", FP:"+FilterPeriod+", MA:"+MaPeriod+" )");
multiply=pow(10,_Digits); 
return(0); 

}
//+------------------------------------------------------------------+
int deinit() { return(0); }
//+------------------------------------------------------------------+
int start() {
   SetIndexDrawBegin(0,Bars-Countbars);
   SetIndexDrawBegin(1,Bars-Countbars);
   SetIndexDrawBegin(2,Bars-Countbars);
   SetIndexDrawBegin(3,Bars-Countbars);
   SetIndexDrawBegin(4,Bars-Countbars);
   SetIndexDrawBegin(5,Bars-Countbars);
   int counted_bars=IndicatorCounted();
      if(counted_bars<0) return(-1);
      if(counted_bars>0) counted_bars--;
         int limit = fmin(Bars-counted_bars,Bars-1); count[0] = limit;
         
         //
         //
         //
         
         if (TimeFrame != Period())
         {
            limit = (int)MathMax(limit,MathMin(Bars-1,_mtfCall(8,0)*TimeFrame/_Period));
            for(int i=limit; i>=0 && !_StopFlag; i--)
            {
               int y = iBarShift(NULL,TimeFrame,Time[i]);
               int x = y;
               if (ArrowOnFirst)
                     {  if (i<Bars-1) x = iBarShift(NULL,TimeFrame,Time[i+1]);               }
               else  {  if (i>0)      x = iBarShift(NULL,TimeFrame,Time[i-1]); else x = -1;  }
                  SRC[i]  = _mtfCall(0,y);
                  Ma[i]   = _mtfCall(1,y); 
                  if (x!=y)
                  {
                     Up[i]    = _mtfCall(2, y);
                     Down[i]  = _mtfCall(3,y);
                     Up2[i]   = _mtfCall(4, y);
                     Down2[i] = _mtfCall(5,y);
                  }
              
                  //
                  //
                  //
                     
                  if (!Interpolate || (i>0 && y==iBarShift(NULL,TimeFrame,Time[i-1]))) continue;
                    #define _interpolate(buff) buff[i+k] = buff[i]+(buff[i+n]-buff[i])*k/n
                    int n,k; datetime btime = iTime(NULL,TimeFrame,y);
                       for(n = 1; (i+n)<Bars && Time[i+n] >= btime; n++) continue;	
                       for(k = 1; k<n && (i+n)<Bars && (i+k)<Bars; k++) 
                       {
                          _interpolate(SRC); 
                          _interpolate(Ma);
                       }               
              }    
   return(0);
   }  
   
   //
   //
   //
 
   int limit2;
   int LastSignal;
   counted_bars = IndicatorCounted();
   if(counted_bars < 0) 
   return(-1);
    if(counted_bars > 0) 
   limit=Bars-counted_bars;
   if(counted_bars== 0)
   limit=Bars-SnakeRange-1; 
  if (i> limit2) 
   limit2= i;    
   if (limit2 <Countbars-1 )
   limit =Countbars-1;   
for(i=0;i<limit;i++) {
   Up[i]=Down[i]=Up2[i]=Down2[i]=SRC[i]=Ma[i]=EMPTY_VALUE;
}
for(i=0;i<limit;i++) MartAxis(i);
for(i=0;i<limit;i++) SmoothOverMart(i);

 for(i=limit;i>=0;i--)   { 
 for(k=0;k<rangeN;k++)

  PriceInt[k]=MathRound(Mart[i+k]*multiply);
  RankPrices(PriceInt);
  SRC[i]=SpearmanRankCorrelation(R2,rangeN);
  if(SRC[i]>1.0) SRC[i]=1.0; 
  if(SRC[i]<-1.0)SRC[i]=-1.0;
  }
 for(i=limit;i>=0;i--){ Ma[i]=iMAOnArray(SRC,0,MaPeriod,0,MaMode,i); }
 for(i=limit;i>=0;i--)
 { 
    if (SRC[i]>Ma[i]  && SRC[i]>-LevelsCross && SRC[i]<0&& Ma[i]<0&& i!=0 && LastSignal!=1){
    LastSignal=1;
    Up[i]=SRC[i];
    Down[i]=EMPTY_VALUE;

   if  (AlertOn   && i==1 && !TurnedUp )
           { 
            Alert(WindowExpertName()+" is crossing UP on"+" "+Symbol()," ",Period()+" "+"minute charts");
            TurnedUp = true;
            TurnedDown = false;
     }
  }
  else if 
  (SRC[i]<Ma[i]&& SRC[i]<LevelsCross&& SRC[i]>0&& Ma[i]>0&& i!=0 && LastSignal!=-1){
     LastSignal=-1;

  Down[i]=SRC[i];
  Up[i]=EMPTY_VALUE;
  if  (AlertOn  &&  i==1 &&!TurnedDown )
           { 
            Alert(WindowExpertName()+" is crossing DOWN on"+" "+Symbol()," ",Period()+" "+"minute charts");
                      
             TurnedUp =false ;
            TurnedDown = true;
     }       
  }
  }
   for(i=limit;i>=0;i--)
  { 

    if (SRC[i]>Ma[i] && Ma[i]>-LevelsCross && SRC[i]<0&& Ma[i]<0&& i!=0 && LastSignal!=1){
   LastSignal=1;
  Up2[i]=SRC[i];
    Down2[i]=EMPTY_VALUE;
}
else if 
  (SRC[i]<Ma[i]&& Ma[i]<LevelsCross&& SRC[i]>0&& Ma[i]>0&& i!=0 && LastSignal!=-1){
     LastSignal=-1;

  Down2[i]=SRC[i];
  Up2[i]=EMPTY_VALUE;
  }
  }
    if (i> limit2) 
   limit2= i;

return(0);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
void MartAxis(int Pos) { int SnakeWeight,i,w,ww,Shift;double SnakeSum;
switch(PriceConst) {
case  0: 
  Axis[Pos]=iMA(NULL,0,SnakeRange+1,0,MODE_LWMA,PRICE_CLOSE,Pos);
  break;
case  1: 
  Axis[Pos]=iMA(NULL,0,SnakeRange+1,0,MODE_LWMA,PRICE_OPEN,Pos);
  break;
case  2: 
  Axis[Pos]=iMA(NULL,0,SnakeRange+1,0,MODE_LWMA,PRICE_HIGH,Pos);
  break;
case  3: 
  Axis[Pos]=iMA(NULL,0,SnakeRange+1,0,MODE_LWMA,PRICE_LOW,Pos);
  break;
case  4: 
  Axis[Pos]=iMA(NULL,0,SnakeRange+1,0,MODE_LWMA,PRICE_MEDIAN,Pos);
  break;
case  5: 
  Axis[Pos]=iMA(NULL,0,SnakeRange+1,0,MODE_LWMA,PRICE_TYPICAL,Pos);
  break;
case  6: 
  Axis[Pos]=iMA(NULL,0,SnakeRange+1,0,MODE_LWMA,PRICE_WEIGHTED,Pos);
  break;
default: 
  Axis[Pos]=iMA(NULL,0,SnakeRange+1,0,MODE_LWMA,PRICE_WEIGHTED,Pos);
  break; }
for(Shift=Pos+SnakeRange+2;Shift>Pos;Shift--) { SnakeSum=0.0;
SnakeWeight=0; i=0; w=Shift+SnakeRange; ww=Shift-SnakeRange;
if(ww<Pos) ww=Pos;
while(w>=Shift) { i++; SnakeSum=SnakeSum+i*SnakePrice(w); 
SnakeWeight=SnakeWeight+i; w--; }
while(w>=ww) { i--; SnakeSum=SnakeSum+i*SnakePrice(w);
SnakeWeight=SnakeWeight+i; w--; }
Axis[Shift]=SnakeSum/SnakeWeight; } return; }
//----
double SnakePrice(int Shift) {
switch(PriceConst) {
   case  0: return(Close[Shift]);
   case  1: return(Open[Shift]);
   case  2: return(High[Shift]);
   case  3: return(Low[Shift]);
   case  4: return((High[Shift]+Low[Shift])/2);
   case  5: return((Close[Shift]+High[Shift]+Low[Shift])/3);
   case  6: return((2*Close[Shift]+High[Shift]+Low[Shift])/4);
   default: return(Close[Shift]); } }
//+------------------------------------------------------------------+
void SmoothOverMart(int Shift) { double t,b;
t=Axis[ArrayMaximum(Axis,FilterPeriod,Shift)];
b=Axis[ArrayMinimum(Axis,FilterPeriod,Shift)];
Mart[Shift]=(2*(2+MartFiltr)*Axis[Shift]-(t+b))/2/(1+MartFiltr);
return; }
//+------------------------------------------------------------------+
//| calculate  RSP  function                                         |
//+------------------------------------------------------------------+
double SpearmanRankCorrelation(double& Ranks[], int N)
  {
//----
   double res,z2;
   int i;
   for(i = 0; i < N; i++)
     {
       z2 += MathPow(Ranks[i] - i - 1, 2);
     }
   res = 1 - 6*z2 / (MathPow(N,3) - N);
//----
   return(res);
  }
//+------------------------------------------------------------------+
//| Ranking array of prices function                                 |
//+------------------------------------------------------------------+
void RankPrices(int& InitialArray[])
  {
//----
   int i, k, m, dublicat, counter, etalon;
   double dcounter, averageRank;
   double TrueRanks[];
   ArrayResize(TrueRanks, rangeN);
   ArrayCopy(SortInt, InitialArray);
   for(i = 0; i < rangeN; i++) 
       TrueRanks[i] = i + 1;
  // if(direction)
       ArraySort(SortInt, 0, 0, MODE_DESCEND);
  // else
    //   ArraySort(SortInt, 0, 0, MODE_ASCEND);
   for(i = 0; i < rangeN-1; i++)
     {
       if(SortInt[i] != SortInt[i+1]) 
           continue;
       dublicat = SortInt[i];
       k = i + 1;
       counter = 1;
       averageRank = i + 1;
       while(k < rangeN)
         {
           if(SortInt[k] == dublicat)
             {
               counter++;
               averageRank += k + 1;
               k++;
             }
           else
               break;
         }
       dcounter = counter;
       averageRank = averageRank / dcounter;
       for(m = i; m < k; m++)
           TrueRanks[m] = averageRank;
       i = k;
     }
   for(i = 0; i < rangeN; i++)
     {
       etalon = InitialArray[i];
       k = 0;
       while(k < rangeN)
         {
           if(etalon == SortInt[k])
             {
               R2[i] = TrueRanks[k];
               break;
             }
           k++;
         }
     }
//----
   return;
  }
  
//
//
//

string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,15,30,60,240,1440,10080,43200};

string timeFrameToString(int tf)
{
   for (int i=ArraySize(iTfTable)-1; i>=0; i--) 
         if (tf==iTfTable[i]) return(sTfTable[i]);
                              return("");
}


//+------------------------------------------------------------------+

/*
int Tma(int Tma){
int limit,j,k,i;
 for (i=limit; i>=0; i--)
   {
      double sum  = (rangeN+1)*iMA(NULL,0,1,0,MODE_SMA,0,i);
      double sumw = (rangeN+1);
      for(j=1, k=rangeN; j<=rangeN; j++, k--)
      {
         sum  += k*iMA(NULL,0,1,0,MODE_SMA,0,i+j);
         sumw += k;

         if (j<=i)
         {
            sum  += k*iMA(NULL,0,1,0,MODE_SMA,0,i-j);
            sumw += k;
         }
      }
      
            Tma = sum/sumw;
      
   }



}*/
//+------------------------------------------------------------------+