//+------------------------------------------------------------------+
//|                                          Guppy MMA oscilator.mq4 |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "www.forex-tsd.com"

#property indicator_separate_window
#property indicator_buffers 7
#property indicator_color1  clrLimeGreen
#property indicator_color2  clrDarkOrange
#property indicator_color3  clrDarkOrange
#property indicator_color4  clrPaleVioletRed
#property indicator_color5  clrDimGray
#property indicator_color6  clrDimGray
#property indicator_color7  clrDimGray
#property indicator_style5  STYLE_DOT
#property indicator_style6  STYLE_DOT
#property indicator_style7  STYLE_DOT

//
//
//
//
//

#import "dynamicZone.dll"
   double dzBuyP(double& sourceArray[],double probabiltyValue, int lookBack, int bars, int i, double precision);
   double dzSellP(double& sourceArray[],double probabiltyValue, int lookBack, int bars, int i, double precision);
#import

//
//
//
//
//

extern ENUM_TIMEFRAMES    TimeFrame              = PERIOD_CURRENT;
extern ENUM_APPLIED_PRICE Price                  = PRICE_CLOSE;
extern ENUM_MA_METHOD     MaMethod               = MODE_EMA;
extern int                SignalPeriod           = 21;
extern int                DzLookBackBars         = 35;       // dynamic zones lookback
extern double             DzStartBuyProbability  = 0.90;     // dynamic upper zone
extern double             DzStartSellProbability = 0.90;     // dynamic lower zone
extern bool               alertsOn               = true;
extern bool               alertsOnCurrent        = false;
extern bool               alertsMessage          = true;
extern bool               alertsSound            = false;
extern bool               alertsEmail            = false;
extern bool               alertsNotify           = false;
extern bool               verticalLinesVisible   = false;
extern bool               linesOnNewest          = false;        // Arrows drawn on newest bar of higher time frame bar?
extern string             verticalLinesID        = "gmmaLines";
extern color              verticalLinesUpColor   = clrLimeGreen;
extern color              verticalLinesDnColor   = clrOrange;
extern ENUM_LINE_STYLE    verticalLinesStyle     = STYLE_DOT;
extern int                verticalLinesWidth     = 0;
extern bool               Interpolate            = true;
extern int                linesWidth             =  3;            // Lines width

//
//
//
//
//

double buffer1[];
double bufferda[];
double bufferdb[];
double buffer2[];
double trend[];
double bl1[];
double sl1[];
double zl1[];
double periods[]={3,5,8,10,12,15,30,35,40,45,50,60};
int    persize;
string indicatorFileName;
bool   returnBars;

//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//

int init()
{
   IndicatorBuffers(8);
   SetIndexBuffer(0,buffer1);  SetIndexStyle(0,EMPTY,EMPTY,linesWidth);
   SetIndexBuffer(1,bufferda); SetIndexStyle(1,EMPTY,EMPTY,linesWidth);
   SetIndexBuffer(2,bufferdb); SetIndexStyle(2,EMPTY,EMPTY,linesWidth);
   SetIndexBuffer(3,buffer2);
   SetIndexBuffer(4,bl1);
   SetIndexBuffer(5,sl1);
   SetIndexBuffer(6,zl1);
   SetIndexBuffer(7,trend);
   persize =ArraySize(periods);
   
      //
      //
      //
      //
      //
      
         indicatorFileName = WindowExpertName();
         returnBars        = TimeFrame==-99;
         TimeFrame         = MathMax(TimeFrame,_Period);
      
      //
      //
      //
      //
      //

   IndicatorShortName(timeFrameToString(TimeFrame)+" Guppy MMA oscillator");
   return(0);
}
int deinit()
{
   string lookFor       = verticalLinesID+":";
   int    lookForLength = StringLen(lookFor);
   for (int i=ObjectsTotal()-1; i>=0; i--)
   {
      string objectName = ObjectName(i);
         if (StringSubstr(objectName,0,lookForLength) == lookFor) ObjectDelete(objectName);
   }
   return(0);
}

//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//

int start()
{
   double alpha = 2.0/(1.0+SignalPeriod);
   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) { buffer1[0] = MathMin(limit+1,Bars-1); return(0); }

   //
   //
   //
   //
   //

   if (TimeFrame == Period())
   {
      if (trend[limit]==-1) CleanPoint(limit,bufferda,bufferdb);
      for(int i=limit; i>=0; i--)
      {
         double sum  = 0;
         for(int j=0; j<persize; j++)
         {
            if (periods[j]<30)
                  sum  += iMA(NULL,0,periods[j],0,MaMethod,Price,i);
            else  sum  -= iMA(NULL,0,periods[j],0,MaMethod,Price,i);
         }
         buffer1[i] = sum*10.0;
         buffer2[i] = buffer2[i+1]+alpha*(buffer1[i]-buffer2[i+1]);
         
         if (DzStartBuyProbability >0) bl1[i] = dzBuyP (buffer1, DzStartBuyProbability,  DzLookBackBars, Bars, i, 0.0001);
         if (DzStartSellProbability>0) sl1[i] = dzSellP(buffer1, DzStartSellProbability, DzLookBackBars, Bars, i, 0.0001);
                                       zl1[i] = dzSellP(buffer1, 0.5                   , DzLookBackBars, Bars, i, 0.0001);
         bufferda[i] = EMPTY_VALUE;
         bufferdb[i] = EMPTY_VALUE;
         trend[i] = trend[i+1];
         if (buffer1[i]>buffer2[i]) trend[i] = 1;
         if (buffer1[i]<buffer2[i]) trend[i] =-1;
         if (trend[i] == -1) PlotPoint(i,bufferda,bufferdb,buffer1);
            
            
            //
            //
            //
            //
            //
         
            if (verticalLinesVisible && (i+1)<Bars)
            {
               ObjectDelete(verticalLinesID+":"+(string)Time[i]);
               if (trend[i] != trend[i+1])
               {
                  if (trend[i] == 1) drawLine(i,verticalLinesUpColor);
                  if (trend[i] ==-1) drawLine(i,verticalLinesDnColor);
               }
             }   
      } 
      
     //
     //
     //
     //
     //
   
     if (alertsOn)
      {
         int whichBar = 1; if (alertsOnCurrent) whichBar = 0;
         if (trend[whichBar] != trend[whichBar+1])
         if (trend[whichBar] == 1)
               doAlert("up");
         else  doAlert("down");       
      }   
      return(0);
   }
   
   //
   //
   //
   //
   //
   
   limit = MathMax(limit,MathMin(Bars-1,iCustom(NULL,TimeFrame,indicatorFileName,-99,0,0)*TimeFrame/Period()));
   if (trend[limit]==-1) CleanPoint(limit,bufferda,bufferdb);
   for (i=limit; i>=0; i--)
   {
      int y = iBarShift(NULL,TimeFrame,Time[i]);
         buffer1[i]  = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,Price,MaMethod,SignalPeriod,DzLookBackBars,DzStartBuyProbability,DzStartSellProbability,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,alertsNotify,verticalLinesVisible,linesOnNewest,verticalLinesID,verticalLinesUpColor,verticalLinesDnColor,verticalLinesStyle,verticalLinesWidth,0,y);
         buffer2[i]  = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,Price,MaMethod,SignalPeriod,DzLookBackBars,DzStartBuyProbability,DzStartSellProbability,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,alertsNotify,verticalLinesVisible,linesOnNewest,verticalLinesID,verticalLinesUpColor,verticalLinesDnColor,verticalLinesStyle,verticalLinesWidth,3,y);
         bl1[i]      = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,Price,MaMethod,SignalPeriod,DzLookBackBars,DzStartBuyProbability,DzStartSellProbability,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,alertsNotify,verticalLinesVisible,linesOnNewest,verticalLinesID,verticalLinesUpColor,verticalLinesDnColor,verticalLinesStyle,verticalLinesWidth,4,y);
         sl1[i]      = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,Price,MaMethod,SignalPeriod,DzLookBackBars,DzStartBuyProbability,DzStartSellProbability,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,alertsNotify,verticalLinesVisible,linesOnNewest,verticalLinesID,verticalLinesUpColor,verticalLinesDnColor,verticalLinesStyle,verticalLinesWidth,5,y);
         zl1[i]      = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,Price,MaMethod,SignalPeriod,DzLookBackBars,DzStartBuyProbability,DzStartSellProbability,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,alertsNotify,verticalLinesVisible,linesOnNewest,verticalLinesID,verticalLinesUpColor,verticalLinesDnColor,verticalLinesStyle,verticalLinesWidth,6,y);
         trend[i]    = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,Price,MaMethod,SignalPeriod,DzLookBackBars,DzStartBuyProbability,DzStartSellProbability,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,alertsNotify,verticalLinesVisible,linesOnNewest,verticalLinesID,verticalLinesUpColor,verticalLinesDnColor,verticalLinesStyle,verticalLinesWidth,8,y);
         bufferda[i] = EMPTY_VALUE;
         bufferdb[i] = EMPTY_VALUE;
         
         //
         //
         //
         //
         //
         
         if (!Interpolate || y==iBarShift(NULL,TimeFrame,Time[i-1])) continue;

         //
         //
         //
         //
         //

         datetime time = iTime(NULL,TimeFrame,y);
            for(int n = 1; i+n < Bars && Time[i+n] >= time; n++) continue;	
            for(int x = 1; x < n; x++)
            {
               buffer1[i+x] = buffer1[i] + (buffer1[i+n]- buffer1[i]) * x/n;
               buffer2[i+x] = buffer2[i] + (buffer2[i+n]- buffer2[i]) * x/n;
               bl1[i+x]     = bl1[i]     + (bl1[i+n]    - bl1[i])     * x/n;
               sl1[i+x]     = sl1[i]     + (sl1[i+n]    - sl1[i])     * x/n;
               zl1[i+x]     = zl1[i]     + (zl1[i+n]    - zl1[i])     * x/n;
            }                        
   }
   for(i=limit; i>=0; i--) if (trend[i] == -1) PlotPoint(i,bufferda,bufferdb,buffer1);
return(0);
}

//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//

void CleanPoint(int i,double& first[],double& second[])
{
   if ((second[i]  != EMPTY_VALUE) && (second[i+1] != EMPTY_VALUE))
        second[i+1] = EMPTY_VALUE;
   else
      if ((first[i] != EMPTY_VALUE) && (first[i+1] != EMPTY_VALUE) && (first[i+2] == EMPTY_VALUE))
          first[i+1] = EMPTY_VALUE;
}

//
//
//
//
//

void PlotPoint(int i,double& first[],double& second[],double& from[])
{
   if (i>=Bars-2) return;
   if (first[i+1] == EMPTY_VALUE)
         {
            if (first[i+2] == EMPTY_VALUE) 
                  { first[i]  = from[i]; first[i+1]  = from[i+1]; second[i] = EMPTY_VALUE; }
            else  { second[i] = from[i]; second[i+1] = from[i+1]; first[i]  = EMPTY_VALUE; }
         }
   else  { first[i] = from[i]; second[i] = EMPTY_VALUE; }
}

//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//

string sTfTable[] = {"M1","M5","M10","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,10,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("");
}

//
//
//
//
//

void doAlert(string doWhat)
{
   static string   previousAlert="nothing";
   static datetime previousTime;
   string message;
   
      if (previousAlert != doWhat || previousTime != Time[0]) {
          previousAlert  = doWhat;
          previousTime   = Time[0];


       //
       //
       //
       //
       //

       message = StringConcatenate(Symbol()," ",timeFrameToString(_Period)," at ",TimeToStr(TimeLocal(),TIME_SECONDS)+" Dz Guppy MMA oscillator ",doWhat);
          if (alertsMessage) Alert(message);
          if (alertsNotify)  SendNotification(message);
          if (alertsEmail)   SendMail(StringConcatenate(Symbol()," Dz Guppy MMA oscillator "),message);
          if (alertsSound)   PlaySound("alert2.wav");
   }
}

//
//
//
//
//

void drawLine(int i,color theColor)
{
   string name = verticalLinesID+":"+(string)Time[i];
   
      //
      //
      //
      //
      //
      
      datetime time = Time[i]; if (linesOnNewest) time += _Period*60-1;    
      ObjectCreate(name,OBJ_VLINE,0,time,0);
         ObjectSet(name,OBJPROP_COLOR,theColor);
         ObjectSet(name,OBJPROP_STYLE,verticalLinesStyle);
         ObjectSet(name,OBJPROP_WIDTH,verticalLinesWidth);
         ObjectSet(name,OBJPROP_BACK,true);
}