//+------------------------------------------------------------------+
//|                                                    kase peak.mq4 |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"

#property indicator_separate_window
#property indicator_buffers  5
#property indicator_color1   clrDimGray
#property indicator_color2   clrDimGray
#property indicator_color3   clrMagenta
#property indicator_color4   clrDeepSkyBlue
#property indicator_color5   clrMagenta
#property indicator_width3   2
#property indicator_width4   2
#property indicator_width5   2
#property strict

//
//
//
//
//

extern ENUM_TIMEFRAMES TimeFrame      = PERIOD_CURRENT; // Time frame to use
extern double          kpoDeviations  = 2.0;            // Kase peak oscillator deviations
extern int             kpoShortCycle  = 8;              // Kase peak oscillator short cycle
extern int             kpoLongCycle   = 65;             // Kase peak oscillator long cycle
extern double          kpoSensitivity = 40;             // Kase peak oscillator sensitivity
extern bool            allPeaksMode   = false;          // Show all peaks?
extern bool            Interpolate    = true;           // Interpolate in multi time frame mode?

//
//
//
//
//

double kphBuffer[];
double kpoBuffer[];
double kpdBuffer[];
double kpmBuffer[];
double kppBuffer[];
string indicatorFileName;
bool   returnBars;

//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//

int init()
{
   SetIndexBuffer(0,kphBuffer); SetIndexStyle(0,DRAW_HISTOGRAM);
   SetIndexBuffer(1,kpoBuffer);
   SetIndexBuffer(2,kpdBuffer);
   SetIndexBuffer(3,kpmBuffer);
   SetIndexBuffer(4,kppBuffer); SetIndexStyle(4,DRAW_HISTOGRAM);
   
      //
      //
      //
      //
      //
      
            indicatorFileName = WindowExpertName();
            returnBars        = (TimeFrame==-99);
            TimeFrame         = MathMax(TimeFrame,_Period);
   
   IndicatorShortName(timeFrameToString(TimeFrame)+" Kase peak oscillator ("+(string)kpoDeviations+","+(string)kpoShortCycle+","+(string)kpoLongCycle+","+(string)kpoSensitivity+")");   
   return(0);
}
int deinit() { return(0); }

//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//

double wrkBuffer[][6];
#define ccLog 0
#define ccDev 1
#define x1    2
#define xs    3
#define xp    4
#define xpAbs 5

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-2);
         if (returnBars) { kphBuffer[0] = MathMin(limit+1,Bars-1); return(0); }
         
   //
   //
   //
   //
   //

   if (TimeFrame == Period())
   {
      if (ArrayRange(wrkBuffer,0) != Bars) ArrayResize(wrkBuffer,Bars);
      for(int i=limit,r=Bars-i-1; i>=0; i--,r++)
      {
         wrkBuffer[r][x1]    = wrkBuffer[r-1][x1];
         wrkBuffer[r][xs]    = wrkBuffer[r-1][xs];
         wrkBuffer[r][ccLog] = MathLog(Close[i]/Close[i+1]);
         wrkBuffer[r][ccDev] = iDeviation(ccLog,9,r);

         //
         //
         //
         //
         //
      
         double avg = iSma(ccDev,30,r);
         if (avg>0)
         {
            double max1 = 0;
            double maxs = 0;
               for (int k=kpoShortCycle; k<kpoLongCycle && (i+k)<Bars; k++)
               {
                  max1 = MathMax(MathLog(High[i]/Low[i+k])/MathSqrt(k),max1);
                  maxs = MathMax(MathLog(High[i+k]/Low[i])/MathSqrt(k),maxs);
               }                  
            wrkBuffer[r][x1] = max1/avg;
            wrkBuffer[r][xs] = maxs/avg;
         }
         wrkBuffer[r][xp]    = kpoSensitivity*(iSma(x1,3,r)-iSma(xs,3,r));
         wrkBuffer[r][xpAbs] = MathAbs(wrkBuffer[r][xp]);

         //
         //
         //
         //
         //

         kppBuffer[i+1] = EMPTY_VALUE;      
         kpoBuffer[i]   = wrkBuffer[r][xp];
         kphBuffer[i]   = wrkBuffer[r][xp];

            double tmpVal = iSma(xpAbs,50,r)+kpoDeviations*(iDeviation(xpAbs,50,r));
            double maxVal = MathMax(90.0,tmpVal);
            double minVal = MathMin(90.0,tmpVal);
      
         if (kpoBuffer[i] > 0) { kpdBuffer[i] =  maxVal; kpmBuffer[i] =  minVal; }
         else                  { kpdBuffer[i] = -maxVal; kpmBuffer[i] = -minVal; }
      
         //
         //
         //
         //
         //

         if (i<Bars-2)
         if (!allPeaksMode)
         {         
            if (kpoBuffer[i+1]>0 && kpoBuffer[i+1]>kpoBuffer[i] && kpoBuffer[i+1]>=kpoBuffer[i+2] && kpoBuffer[i+1]>= maxVal) kppBuffer[i+1] = kpoBuffer[i+1];
            if (kpoBuffer[i+1]<0 && kpoBuffer[i+1]<kpoBuffer[i] && kpoBuffer[i+1]<=kpoBuffer[i+2] && kpoBuffer[i+1]<=-maxVal) kppBuffer[i+1] = kpoBuffer[i+1];
         }
         else
         {
            if (kpoBuffer[i+1]>0 && kpoBuffer[i+1]>kpoBuffer[i] && kpoBuffer[i+1]>=kpoBuffer[i+2]) kppBuffer[i+1] = kpoBuffer[i+1];
            if (kpoBuffer[i+1]<0 && kpoBuffer[i+1]<kpoBuffer[i] && kpoBuffer[i+1]<=kpoBuffer[i+2]) kppBuffer[i+1] = kpoBuffer[i+1];
         }         
      }
      return(0);
   }
   
   //
   //
   //
   //
   //
   
   limit = (int)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]);
      int x = y; if (i<Bars-1) x = iBarShift(NULL,TimeFrame,Time[i+1]);
         kphBuffer[i] = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,kpoDeviations,kpoShortCycle,kpoLongCycle,kpoSensitivity,allPeaksMode,0,y);
         kpoBuffer[i] = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,kpoDeviations,kpoShortCycle,kpoLongCycle,kpoSensitivity,allPeaksMode,1,y);
         kpdBuffer[i] = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,kpoDeviations,kpoShortCycle,kpoLongCycle,kpoSensitivity,allPeaksMode,2,y);
         kpmBuffer[i] = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,kpoDeviations,kpoShortCycle,kpoLongCycle,kpoSensitivity,allPeaksMode,3,y);
         kppBuffer[i] = EMPTY_VALUE;      
         if (x!=y)
            kppBuffer[i] = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,kpoDeviations,kpoShortCycle,kpoLongCycle,kpoSensitivity,allPeaksMode,4,y);
            

         //
         //
         //
         //
         //
      
         if (!Interpolate || (i>0 && y==iBarShift(NULL,TimeFrame,Time[i-1]))) continue;
         int n,k; datetime time = iTime(NULL,TimeFrame,y);
            for(n = 1; i+n < Bars && Time[i+n] >= time; n++) continue;
            for(k = 1; i+k < Bars && i+n < Bars && k<n; k++)
            {
               kphBuffer[i+k] = kphBuffer[i] + (kphBuffer[i+n] - kphBuffer[i])*k/n;
               kpoBuffer[i+k] = kpoBuffer[i] + (kpoBuffer[i+n] - kpoBuffer[i])*k/n;
               kpdBuffer[i+k] = kpdBuffer[i] + (kpdBuffer[i+n] - kpdBuffer[i])*k/n;
               kpmBuffer[i+k] = kpmBuffer[i] + (kpmBuffer[i+n] - kpmBuffer[i])*k/n;
            }               
   }
   return(0);
}

//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//

double iDeviation(int forDim, int period, int pos)
{
   double dMA  = iSma(forDim,period,pos);
   double dSum = 0;
      for(int i=0; i<period && pos>=0; i++,pos--) dSum += (wrkBuffer[pos][forDim]-dMA)*(wrkBuffer[pos][forDim]-dMA);
   return(MathSqrt(dSum/period));
}

//
//
//
//
//

double iSma(int forDim, int period, int pos)
{
   double sum = wrkBuffer[pos][forDim];
      for(int i=1; i<period && (pos-i)>=0; i++) sum += wrkBuffer[pos-i][forDim];
   return(sum/period);
}

//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//

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("");
}