//+------------------------------------------------------------------+
//|                                                 Projection bands |
//|                                                                  |
//|                                                                  |
//| original indicator described in TASC 13:7 article                |
//| "Signaling Change With Projection Bands" by Mel Widner Ph.D.     }
//|                                                                  |
//+------------------------------------------------------------------+

#property copyright "mladen"
#property link      "mladenfx@gmail.com"

#property indicator_chart_window
#property  indicator_buffers 3
#property  indicator_color1  LimeGreen
#property  indicator_color2  Orange
#property  indicator_color3  DarkGray
#property  indicator_style3  STYLE_DOT

//
//
//
//
//

extern ENUM_TIMEFRAMES TimeFrame = PERIOD_CURRENT;
extern int             ProjectionPeriod = 20;

//
//
//
//
//

double bufferUp[];
double bufferDn[];
double bufferMi[];
bool   returnBars;
string indicatorFileName;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int init()
{
   SetIndexBuffer(0,bufferUp);
   SetIndexBuffer(1,bufferDn);
   SetIndexBuffer(2,bufferMi);
         returnBars = (TimeFrame==-99);
         TimeFrame  = MathMax(TimeFrame,_Period);
         indicatorFileName = WindowExpertName();
         IndicatorShortName("Projection bands ("+ProjectionPeriod+")");
   return(0);
}
int deinit()
{
   return(0);
}


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int start()
{
   int counted_bars=IndicatorCounted();
   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
         int limit=MathMin(Bars-counted_bars,Bars-1);
         if (returnBars) { bufferUp[0] = limit+1; return(0); }
         if (TimeFrame!=Period())
         {
            limit = MathMax(limit,MathMin(Bars-1,iCustom(NULL,TimeFrame,indicatorFileName,-99,0,0)*TimeFrame/Period()));
            for (int i=limit; i>=0; i--)
            {
               int y = iBarShift(NULL,TimeFrame,Time[i]);
                  bufferUp[i] = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,ProjectionPeriod,0,y);
                  bufferDn[i] = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,ProjectionPeriod,1,y);
                  bufferMi[i] = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,ProjectionPeriod,2,y);
            }
            return(0);
         }

   //
   //
   //
   //
   //
   
   for(i=limit; i>=0; i--)
   {
      double slopel = lrsSlope(ProjectionPeriod,PRICE_LOW ,i);
      double slopeh = lrsSlope(ProjectionPeriod,PRICE_HIGH,i);
         double max = iMA(NULL,0,1,0,MODE_SMA,PRICE_HIGH,i);
         double min = iMA(NULL,0,1,0,MODE_SMA,PRICE_LOW ,i);

         for (int k=1; k<ProjectionPeriod; k++)
         {
            min = MathMin(min,iMA(NULL,0,1,0,MODE_SMA,PRICE_LOW ,i+k)+k*slopel);
            max = MathMax(max,iMA(NULL,0,1,0,MODE_SMA,PRICE_HIGH,i+k)+k*slopeh);
         }
         bufferUp[i] = max;
         bufferDn[i] = min;
         bufferMi[i] = (max+min)/2.0;
   }
   return(0);
}


  
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//

double lrsSlope(int period,int appliedPrice,int shift)
{
   double sumx  = period*(period+1.0)/2.0;
   double sumx2 = period*(period+1.0)*(2*period+1.0)/6.0;
   double sumxy = 0.00;
   double sumy  = 0.00;

   int n = period;
   int i;
      for (i=0; i<period; i++,n--)
      {
         double price  = iMA(NULL,0,1,0,MODE_SMA,appliedPrice,shift+i);
                sumxy += n*price;
                sumy  +=   price;
      }        

   //
   //
   //
   //
   //
   
   double slope = 0.00;
   double top   = period*sumxy - sumx*sumy;
   double bot   = period*sumx2 - sumx*sumx;
      if (bot != 0) slope = top/bot;
   return(slope);
}