//+------------------------------------------------------------------+
//|                                     UCI - universal cycle index  |
//|                                                           mladen |
//|                                                                  |
//|                                                                  |
//|                                                                  |
//| Developed by Stuart Belknap                                      |
//| TASC may 2005                                                    |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"

#property indicator_separate_window
#property indicator_buffers 5
#property indicator_color1 Orange
#property indicator_color2 Lime
#property indicator_color3 DimGray
#property indicator_color4 DimGray
#property indicator_color5 DimGray
#property indicator_style2 STYLE_DOT
#property indicator_style3 STYLE_DOT
#property indicator_style4 STYLE_DOT
#property indicator_style5 STYLE_DOT

//
//
//
//
//

extern int    Length             =  25;
extern int    Price              =  PRICE_CLOSE;
extern bool   UseFixedVolatility = false;
extern bool   ShowRealTime       = true;
extern bool   ShowCentered       = true;
extern double LevelUp            =  50;
extern double LevelDown          = -50;

//
//
//
//
//

double  buffer1[];
double  buffer2[];
double  buffer3[];
double  buffer4[];
double  buffer5[];
double  buffer6[];

//
//
//
//
//

double work[][3];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int init()
{
   IndicatorBuffers(6);
   SetIndexBuffer(0,buffer1); SetIndexLabel(0,"SB Cycle Index");
   SetIndexBuffer(1,buffer2); SetIndexLabel(1,"SB Centered Index"); SetIndexShift(1,-MathFloor(0.5*Length));
   SetIndexBuffer(2,buffer3); SetIndexLabel(2,NULL);
   SetIndexBuffer(3,buffer4); SetIndexLabel(3,NULL);
   SetIndexBuffer(4,buffer5); SetIndexLabel(4,NULL);
   SetIndexBuffer(5,buffer6);
         SetIndexDrawBegin(0,2*Length);
         SetIndexDrawBegin(1,2*Length);
         if (!ShowRealTime && !ShowCentered) ShowRealTime = true;
   string  fixedVolatility = "fixed ";
   if (!UseFixedVolatility)
           fixedVolatility = "non-fixed ";
   IndicatorShortName("Universal cycle index "+fixedVolatility+"("+Length+")");
   return(0);
}
int deinit()
{
   return(0);
}


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int start()
{
   int doubleLength = 2*Length;
   int midLength    = MathFloor(0.5*Length);
   int shortLength  = MathFloor(0.5*midLength);
   int counted_bars = IndicatorCounted();
   int i,r,limit;
   
   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
           limit=MathMin(Bars-counted_bars,Bars-1);
           if (ArrayRange(work,0) != Bars) ArrayResize(work,Bars);

      
   //
   //
   //
   //
   //
   
   for(i=limit, r=Bars-i-1; i>=0; i--,r++)
   {  
      double ym       = 0.00;
      double shortEma = iMA(NULL,0,shortLength,0,MODE_EMA,Price,i);
      double midEma   = iMA(NULL,0,midLength  ,0,MODE_EMA,Price,i);
      double maValue  = iMA(NULL,0,Length     ,0,MODE_SMA,Price,i+midLength);
      
      if (UseFixedVolatility)
            double sigom = calculateSigom(Price,50          ,25    ,12       ,r,i);
      else         sigom = calculateSigom(Price,doubleLength,Length,midLength,r,i);
      
      //
      //
      //
      //
      //

            buffer1[i] = EMPTY_VALUE;
            buffer2[i] = EMPTY_VALUE;
            buffer3[i] = LevelUp;
            buffer4[i] = 0.00;
            buffer5[i] = LevelDown;
            buffer6[i] = 0.00;

      //
      //
      //
      //
      //
      
      if (maValue != 0)
            ym = 100*(iMA(NULL,0,midLength,0,MODE_SMA,Price,i+shortLength)-maValue)/maValue;
      if (midEma != 0)
            buffer6[i] = 100*(shortEma-midEma)/midEma;
      double ymes  = iLsma(buffer6,6,i);
      if (sigom != 0)
         {
            if (ShowCentered) buffer2[i] = 100*ym/sigom;
            if (ShowRealTime) buffer1[i] = 100*ymes/sigom;
         }            
   }    
   return(0);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

#define yom    0
#define varyom 1
#define som    2

//
//
//
//
//

double calculateSigom(int price, int doubleLength, int length, int halfLength, int r, int i)
{
   double maValue = iMA(NULL,0,length,0,MODE_SMA,price,i);
      if (maValue > 0)
           work[r][yom] = 100*(iMA(NULL,0,1,0,MODE_SMA,price,i+halfLength)-maValue)/maValue;
      else work[r][yom] = 0;
   
      //
      //
      //
      //
      //
         
      double yomSum1 = work[r][yom];
      double yomSum2 = work[r][yom]*work[r][yom];
      for (int k=1; (i+k) <Bars && k<doubleLength; k++)
      {
         yomSum1 += work[r-k][yom];
         yomSum2 += work[r-k][yom]*work[r-k][yom];
      }
      double avyom = yomSum1/k;
      
         work[r][varyom] = yomSum2/k-avyom*avyom;
         work[r][som]    = MathSqrt(work[r-halfLength][varyom]);

      //
      //
      //
      //
      //
      //
         
      double sigom = work[r][som];
            for (k=1; (i+k) <Bars && k<length; k++) sigom += work[r-k][som];
         
   return(sigom/k);
}


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

double iLsma(double& array[],int period,int shift)
{
   double lengthvar = (period + 1.0)/3.0;
   double sum       = 0.0;
   double res       = 0.0;

   //
   //
   //
   //
   //
   
   for(int i = period; i >= 1 ; i--)
      sum += (i-lengthvar)*array[shift+period-i];
      res  = sum*6/(period*(period+1.0));
   return(res);
}