#property  copyright "www,forex-tsd.com"
#property  link      "www,forex-tsd.com"

//---- indicator settings
#property  indicator_chart_window
#property  indicator_buffers 1
#property  indicator_color1  Blue

#property  indicator_width1  4

//---- indicator parameters
extern ENUM_TIMEFRAMES    TimeFrame            = PERIOD_CURRENT;
extern double             FastEMA              = 4;
extern double             SlowEMA              = 6;
extern double             SignalEMA            = 5;
extern ENUM_APPLIED_PRICE PriceToCross         = PRICE_MEDIAN;
extern bool               alertsOn             = false;
extern bool               alertsOnCurrent      = true;
extern bool               alertsMessage        = false;
extern bool               alertsSound          = false;
extern bool               alertsEmail          = false;
extern bool               alertsPush           = false;
extern bool               verticalLinesVisible = false;
extern bool               linesOnFirst         = true;
extern string             verticalLinesID      = "mp Lines3";
extern color              verticalLinesUpColor = DeepSkyBlue;
extern color              verticalLinesDnColor = PaleVioletRed;
extern ENUM_LINE_STYLE    verticalLinesStyle   = STYLE_DOT;
extern int                verticalLinesWidth   = 0;
extern bool               Interpolate          = true;
//---- indicator buffers

double Price[];
double cross[];
double predict[];
string indicatorFileName;
bool   returnBars;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//---- drawing settings
   IndicatorBuffers(2);   
   SetIndexBuffer(0,Price);
   SetIndexBuffer(1,cross);
 
      indicatorFileName = WindowExpertName();
      returnBars        = TimeFrame==-99;
      TimeFrame         = MathMax(TimeFrame,_Period);
   IndicatorShortName(timeFrameToString(TimeFrame)+" MACD("+FastEMA+","+SlowEMA+","+SignalEMA+")");
   SetIndexLabel(0,"MACD Predictor");

//---- initialization done
   return(0);
  }
int deinit()
{
   ObjectDelete("Signal3");
   deleteLines();
   
return(0);
}
//+------------------------------------------------------------------+
//| Moving Averages Convergence/Divergence                           |
//+------------------------------------------------------------------+
int start()
  {
   double v1minus2divsgEMAplus1 = 1.0 - 2.0 / (SignalEMA + 1.0);
   double v1minus2divSEMAplus1  = 1.0 - 2.0 / (SlowEMA + 1.0);
   double v1minus2divFEMAplus1  = 1.0 - 2.0 / (FastEMA + 1.0);
   double FEMAmSEMAt2           = 2 * (FastEMA - SlowEMA);
   double FEMAp1tSEMAp1         = (FastEMA + 1.0)*(SlowEMA + 1.0);
   
   int counted_bars=IndicatorCounted();
   int limit;

   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
         limit=MathMin(Bars-counted_bars,Bars-1);
         if (returnBars) { Price[0] = MathMin(limit+1,Bars-1); return(0); }

 
   
   if (TimeFrame == Period())
   {
      for (int i=limit;i>=0;i--)
      {
         double tpredict =(-1.0) / (FEMAmSEMAt2 * v1minus2divsgEMAplus1) * FEMAp1tSEMAp1 * ((-v1minus2divsgEMAplus1)*(iMA(NULL,0,FastEMA,0,1,PRICE_CLOSE,0)   * v1minus2divFEMAplus1 - iMA(NULL,0,SlowEMA,0,1,PRICE_CLOSE,0)   * v1minus2divSEMAplus1 ));// + iCustom(NULL,0,"DiNapoli MACD",FastEMA,SlowEMA,SignalEMA,false,0,0) * v1minus2divsgEMAplus1);
                Price[i] =(-1.0) / (FEMAmSEMAt2 * v1minus2divsgEMAplus1) * FEMAp1tSEMAp1 * ((-v1minus2divsgEMAplus1)*(iMA(NULL,0,FastEMA,0,1,PRICE_CLOSE,i+1) * v1minus2divFEMAplus1 - iMA(NULL,0,SlowEMA,0,1,PRICE_CLOSE,i+1) * v1minus2divSEMAplus1 ));// + iCustom(NULL,0,"DiNapoli MACD",FastEMA,SlowEMA,SignalEMA,false,0,i+1) * v1minus2divsgEMAplus1);
         double price    = iMA(NULL,0,1,0,MODE_SMA,PriceToCross,i);
         cross[i] = cross[i+1];
            if (Price[i]>price) cross[i] =  1;
            if (Price[i]<price) cross[i] = -1;
            
            
           if (verticalLinesVisible)
           {
             deleteLine(Time[i]);
             if (cross[i]!=cross[i+1])
             {
                if (cross[i] == 1) drawLine(i,verticalLinesUpColor);
                if (cross[i] ==-1) drawLine(i,verticalLinesDnColor);
             }
           }      
      //double predict=(-1.0)*1.0/((FastEMA-SlowEMA)*2*(1.0-2.0/(SignalEMA+1.0)))* (FastEMA+1.0)*(SlowEMA+1.0)*((2.0/(SignalEMA+1.0)-1.0)*(iMA(NULL,0,FastEMA,0,1,PRICE_CLOSE,0)*(1.0-2.0/(FastEMA+1.0))-iMA(NULL,0,SlowEMA,0,1,PRICE_CLOSE,0)*(1.0-2.0/(SlowEMA+1.0)))+iCustom(NULL,0,"DiNapoli MACD",FastEMA,SlowEMA,SignalEMA,false,0,0)*(1-2.0/(SignalEMA+1.0)));

    datetime futureBarTime  = Time[i]+TimeFrame*60;  
    datetime futureBarTime1 = Time[i];  
 
      ObjectCreate("Signal3",OBJ_TREND,0,Time[i],Price[i],futureBarTime,tpredict);
         ObjectSet("Signal3",OBJPROP_COLOR,Blue);
         ObjectSet("Signal3",OBJPROP_WIDTH,2);
         ObjectSet("Signal3",OBJPROP_RAY,true);
         ObjectSet("Signal3",OBJPROP_STYLE,STYLE_SOLID);
         double predict1=ObjectGet("Signal3",OBJPROP_PRICE1);
      
    if(predict1<tpredict||predict1>tpredict)
    {
      ObjectDelete("Signal3");
      
      ObjectCreate("Signal3",OBJ_TREND,0,Time[i],Price[i],futureBarTime,tpredict);
         ObjectSet("Signal3",OBJPROP_COLOR,Blue);
         ObjectSet("Signal3",OBJPROP_WIDTH,2);
         ObjectSet("Signal3",OBJPROP_RAY,true);
         ObjectSet("Signal3",OBJPROP_STYLE,STYLE_SOLID);
         predict1=ObjectGet("Signal3",OBJPROP_PRICE1);}

   }
   manageAlerts();
   return(0);
   
  }
  
   limit = MathMax(limit,MathMin(Bars-1,iCustom(NULL,TimeFrame,indicatorFileName,-99,0,0)*TimeFrame/Period()));
   for (i=limit; i>=0; i--)
   {
      int y = iBarShift(NULL,TimeFrame,Time[i]);
         Price[i] = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,FastEMA,SlowEMA,SignalEMA,PriceToCross,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,alertsPush,verticalLinesVisible,linesOnFirst,verticalLinesID,verticalLinesUpColor,verticalLinesDnColor,verticalLinesStyle,verticalLinesWidth,0,y);

      
         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 k = 1; k < n; k++) Price[i+k] = Price[i] + (Price[i+n] - Price[i])*k/n;
                  
   }
return(0);
}


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("");
}


void manageAlerts()
{
   if (alertsOn)
   {
      if (alertsOnCurrent)
           int whichBar = 0;
      else     whichBar = 1; 
      if (cross[whichBar] != cross[whichBar+1])
      {
         if (cross[whichBar] ==  1) doAlert("up");
         if (cross[whichBar] == -1) doAlert("down");
      }
   }
}


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(timeFrameToString(Period())+" "+Symbol()," at ",TimeToStr(TimeLocal(),TIME_SECONDS)," MACD predictor crossed price ",doWhat);
          if (alertsMessage) Alert(message);
          if (alertsEmail)   SendMail(Symbol()+" MACD predictor",message);
          if (alertsPush)    SendNotification(message);
          if (alertsSound)   PlaySound("alert2.wav");
   }
}


void drawLine(int i,color theColor)
{
      string name = verticalLinesID+":"+Time[i];

      
      int add = 0; if (!linesOnFirst) add = _Period*60-1;
      ObjectCreate(name,OBJ_VLINE,0,Time[i]+add,0);
         ObjectSet(name,OBJPROP_COLOR,theColor);
         ObjectSet(name,OBJPROP_STYLE,verticalLinesStyle);
         ObjectSet(name,OBJPROP_WIDTH,verticalLinesWidth);
         ObjectSet(name,OBJPROP_BACK,true);
}


void deleteLines()
{
   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);
   }
}



void deleteLine(datetime time)
{
   string lookFor = verticalLinesID+":"+time; ObjectDelete(lookFor);
}
