//+------------------------------------------------------------------+
//|                                                  EntropyMath.mq4 |
//|                                                    Aleksandr Pak |
//+------------------------------------------------------------------+
array out of range issue is at line 181

#property link      "www.forex-station.com"
#property copyright "www.forex-station.com"
#property strict

#property indicator_separate_window
#property indicator_buffers 4
#property indicator_color1  clrDodgerBlue
#property indicator_color2  clrOrange
#property indicator_color3  clrDarkSlateGray
#property indicator_color4  clrGold
#property indicator_width1  2
#property indicator_width2  2  
#property indicator_width3  2  
#property indicator_level1  0.0001
#property indicator_level2  -0.0001


extern ENUM_TIMEFRAMES    TimeFrame   = PERIOD_CURRENT; // Time frame
extern int                numbars     = 21;
extern int                AdaptPeriod = 15;
extern ENUM_APPLIED_PRICE AdaptPrice  = PRICE_CLOSE;
extern int                SignalSMA   = 5;
extern bool               Interpolate = true;           // Interpolate in multi time frame mode

//

double up[];
double dn[];
double entropy[];
double SignalBuffer[];
double trend[],count[];

string indicatorFileName;
#define _mtfCall(_buff,_ind) iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,numbars,AdaptPeriod,AdaptPrice,SignalSMA,_buff,_ind)
	
	
//+------------------------------------------------------------------+
int init()
{
   IndicatorBuffers(5);
   SetIndexBuffer(0,up); SetIndexStyle(0,DRAW_HISTOGRAM);
   SetIndexBuffer(1,dn); SetIndexStyle(1,DRAW_HISTOGRAM);
	SetIndexBuffer(2,entropy);  
	SetIndexBuffer(3,SignalBuffer); 
	SetIndexBuffer(4,trend);
	IndicatorDigits(Digits+2);
	
	indicatorFileName = WindowExpertName();
   TimeFrame         = fmax(TimeFrame,_Period); 
	IndicatorShortName(timeFrameToString(TimeFrame) + " Entropy(" + IntegerToString(numbars) + ")");	
	return(0);
}
//+------------------------------------------------------------------+
int deinit() { return(0); }

//+------------------------------------------------------------------+
int start()
{
   int i, counted_bars = IndicatorCounted();
   
   if (counted_bars < 0) return -1;
   if (counted_bars > 0) counted_bars--;

   // Resize the array to ensure count[0] is accessible
   ArrayResize(count, 1);

   int limit = fmin(Bars - counted_bars, Bars - 1);
   count[0] = limit;
            if (TimeFrame!=_Period)
            {
               limit = (int)fmax(limit,fmin(Bars-1,_mtfCall(10,0)*TimeFrame/_Period));
               for (i=limit;i>=0 && !_StopFlag; i--)
               {
                  int y = iBarShift(NULL,TimeFrame,Time[i]);
                     up[i]           = _mtfCall(0,y);
                     dn[i]           = _mtfCall(1,y);
                     entropy[i]      = _mtfCall(2,y);
                     SignalBuffer[i] = _mtfCall(3,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 time = iTime(NULL,TimeFrame,y);
                           for(n = 1; (i+n)<Bars && Time[i+n] >= time; n++) continue;	
                           for(k = 1; k<n && (i+n)<Bars && (i+k)<Bars; k++) 
                           {
                              _interpolate(entropy);
                              _interpolate(SignalBuffer);
                              if (up[i]!= EMPTY_VALUE) up[i+k] = entropy[i+k];
  	                           if (dn[i]!= EMPTY_VALUE) dn[i+k] = entropy[i+k];
                           }                           
               }
   return(0);
   }
   
   //
   
   for(i=limit; i>=0; i--) 
	{
	   double dev   = iStdDev(NULL,0,AdaptPeriod,0,MODE_SMA,AdaptPrice,i);
      double avg   = iSma(dev,AdaptPeriod,i,0);
      double coeff = 1; if (dev!=0) coeff = avg/dev;
         
         //
         
      	double sumx  = 0.0;
	      double sumx2 = 0.0;
	      double avgx  = 0.0;
	      double rmsx  = 1.0;
			for (int j=0;j<numbars+1 && (i+j+1)<Bars; j++)
			{
				double r=MathLog(Close[i+j] / Close[i+j+1]) ;
				sumx += r;
				sumx2 += r * r;
			}
		   if (numbars==0)  
		         { avgx = Close[i];       rmsx = 0.0;                     }
		   else  { avgx = sumx / numbars; rmsx = MathSqrt(sumx2/numbars); }
		   double P;
		   if (rmsx!=0)
		                P = ((avgx/rmsx)+1)/2.0;
         else	       P = 0;
		         double G = P * MathLog(1+rmsx) + (1-P) * MathLog(1-rmsx);
		   entropy[i] = iSsm(G,coeff*numbars,i,0);
		   
		    //
		    
		    up[i]    = EMPTY_VALUE;
		    dn[i]    = EMPTY_VALUE;
		    trend[i] = trend[i+1];
		    if (entropy[i]>0) trend[i] = 1;
		    if (entropy[i]<0) trend[i] =-1;
		    if (trend[i] == 1) up[i] = entropy[i];
		    if (trend[i] ==-1) dn[i] = entropy[i];
	}
	
   for(i=limit; i>=0; i--) SignalBuffer[i]=iMAOnArray(entropy,Bars,SignalSMA,0,MODE_SMA,i);
	return(0);
}

//+------------------------------------------------------------------+

double workSsm[][2];
#define _price  0
#define _ssm    1

double workSsmCoeffs[][4];
#define _period 0
#define _c1     1
#define _c2     2
#define _c3     3
#define Pi 3.14159265358979323846264338327950288

//

double iSsm(double price, double period, int i, int instanceNo)
{
   if (ArrayRange(workSsm,0) !=Bars)                 ArrayResize(workSsm,Bars);
   if (ArrayRange(workSsmCoeffs,0) < (instanceNo+1)) ArrayResize(workSsmCoeffs,instanceNo+1);
   if (workSsmCoeffs[instanceNo][_period] != period)
   {
      workSsmCoeffs[instanceNo][_period] = period;
      double a1 = MathExp(-1.414*Pi/period);
      double b1 = 2.0*a1*MathCos(1.414*Pi/period);
         workSsmCoeffs[instanceNo][_c2] = b1;
         workSsmCoeffs[instanceNo][_c3] = -a1*a1;
         workSsmCoeffs[instanceNo][_c1] = 1.0 - workSsmCoeffs[instanceNo][_c2] - workSsmCoeffs[instanceNo][_c3];
   }

   //

      i = Bars-i-1;
      int s = instanceNo*2;   
          workSsm[i][s+_price] = price;
          workSsm[i][s+_ssm]   = workSsmCoeffs[instanceNo][_c1]*(workSsm[i][s+_price]+workSsm[i-1][s+_price])/2.0 + // array out of range here!
                                 workSsmCoeffs[instanceNo][_c2]*workSsm[i-1][s+_ssm]                              + 
                                 workSsmCoeffs[instanceNo][_c3]*workSsm[i-2][s+_ssm];
   return(workSsm[i][s+_ssm]);
}

//+------------------------------------------------------------------+

double workSma[][2];
double iSma(double price, int period, int r, int instanceNo=0)
{
   if (ArrayRange(workSma,0)!= Bars) ArrayResize(workSma,Bars); instanceNo *= 2; r = Bars-r-1;

   //
      
   workSma[r][instanceNo] = price;
   int k;
   if (r>=period)
          workSma[r][instanceNo+1] = workSma[r-1][instanceNo+1]+(workSma[r][instanceNo]-workSma[r-period][instanceNo])/period;
   else { workSma[r][instanceNo+1] = 0; for(k=0; k<period && (r-k)>=0; k++) workSma[r][instanceNo+1] += workSma[r-k][instanceNo];  
          workSma[r][instanceNo+1] /= k; }
   return(workSma[r][instanceNo+1]);
}

//+------------------------------------------------------------------+

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("");
}
//+------------------------------------------------------------------+
