#property indicator_separate_window
#property indicator_buffers 3
#property indicator_color1 White
#property indicator_color2 Red
#property indicator_color3 Lime
#property indicator_width2 3
#property indicator_width3 3

extern int OsMAFastPeriod=12;
extern int OsMASlowPeriod=26;
extern int OsMASignalPeriod=9;
extern int OsMAPrice=0;
extern int ExtrLeftBars=2;
extern int ExtrRightBars=1;
extern double PlusSens=0.0001;
extern double MinusSens=-0.0001;
extern bool DrawLinesSW=true;
extern bool DrawLinesChW=true;
extern color Col_Peak_1=Red;
extern color Col_Peak_2=DeepPink;
extern color Col_Trough_1=LimeGreen;
extern color Col_Trough_2=YellowGreen;
extern string ShortName="OsMA_Divergence_v1";
input bool               divAlert                     = true;               // Divergence alerts true/false?
input bool               divAlertsMessage             = true;               // Divergence alerts message true/false?
input bool               divAlertsSound               = true;               // Divergence alerts sound true/false?
input bool               divAlertsEmail               = false;              // Divergence alerts email true/false?
input bool               divAlertsNotify              = false;              // Divergence alerts push notification true/false?
input string             divAlertsSoundName           = "alert1.wav";       // Divergence alerts sound file name

double osma[];
double Sig1[];
double Sig2[];
double peack_1_i[];
double peack_2_i[];
double trogh_1_i[];
double trogh_2_i[];

int init()
  {

   IndicatorBuffers(7);

   SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(0,osma);
   SetIndexStyle(1,DRAW_ARROW);
   SetIndexArrow(1,159);   
   SetIndexBuffer(1,Sig1);
   SetIndexStyle(2,DRAW_ARROW);
   SetIndexArrow(2,159);    
   SetIndexBuffer(2,Sig2);
   
   SetIndexBuffer(3,peack_1_i);
   SetIndexBuffer(4,peack_2_i);
   SetIndexBuffer(5,trogh_1_i);
   SetIndexBuffer(6,trogh_2_i);
   
   IndicatorShortName(ShortName);

   return(0);
  }

int deinit()
  {

   if(DrawLinesSW || DrawLinesChW)fObjDeleteByPrefix(ShortName);

   return(0);
  }

int start(){

         int limit=Bars-IndicatorCounted();

            for(int i=limit-1;i>=0;i--){
               osma[i]=iOsMA(NULL,0,OsMAFastPeriod,OsMASlowPeriod,OsMASignalPeriod,OsMAPrice,i);
               int extri=i+ExtrRightBars;

               Sig1[i]=EMPTY_VALUE;
               Sig2[i]=EMPTY_VALUE;                            
               
               peack_1_i[i]=peack_1_i[i+1];
               peack_2_i[i]=peack_2_i[i+1];               
               trogh_1_i[i]=trogh_1_i[i+1];
               trogh_2_i[i]=trogh_2_i[i+1];               
               
               bool PeackNow=false;
               bool TroghNow=false;
               
                  double extrv=osma[extri];
                  
                  if(extrv>PlusSens){
                     for(int j=i;j<extri;j++){
                        if(extrv<=osma[j]){
                           break;
                        }
                     }
                     if(j==extri){
                        int extril=extri+ExtrLeftBars;
                           for(j=extril;j>extri;j--){
                              if(extrv<=osma[j]){
                                 break;
                              }
                           }
                           if(j==extri){
                              PeackNow=true;
                                    if(peack_1_i[i]==EMPTY_VALUE){
                                       peack_1_i[i]=Time[extri];
                                    }
                                    else{
                                       if(osma[extri]>osma[iBarShift(NULL,0,peack_1_i[i],false)]){
                                          peack_1_i[i]=Time[extri];
                                       }
                                    }
                           }
                     }
                  }
                  if(extrv<MinusSens){                  
                     for(j=i;j<extri;j++){
                        if(extrv>=osma[j]){
                           break;
                        }
                     }
                     if(j==extri){
                        extril=extri+ExtrLeftBars;
                           for(j=extril;j>extri;j--){
                              if(extrv>=osma[j]){
                                 break;
                              }
                           }
                           if(j==extri){
                              TroghNow=true;
                                    if(trogh_1_i[i]==EMPTY_VALUE){
                                       trogh_1_i[i]=Time[extri];
                                    }
                                    else{
                                       if(osma[extri]<osma[iBarShift(NULL,0,trogh_1_i[i],false)]){
                                          trogh_1_i[i]=Time[extri];
                                       }
                                    }                              
                           }
                     }                  
                  }  
                  
                  if(osma[i]>0 && osma[i+1]<=0){
                     peack_2_i[i]=peack_1_i[i];
                     peack_1_i[i]=EMPTY_VALUE;
                  }                    
                  
                  if(osma[i]<0 && osma[i+1]>=0){
                     trogh_2_i[i]=trogh_1_i[i];
                     trogh_1_i[i]=EMPTY_VALUE;                  
                  }
                  
               string ObjName1=ShortName+"_PeakIW_"+Time[extri];
               string ObjName2=ShortName+"_PeakPW_"+Time[extri];
               ObjectDelete(ObjName1);   
               ObjectDelete(ObjName2);    
                               
                  if(PeackNow){
                     if(peack_1_i[i]!=EMPTY_VALUE){
                        if(peack_2_i[i]!=EMPTY_VALUE){
                           if(osma[extri]>=osma[iBarShift(NULL,0,peack_1_i[i],false)]){ 
                              int z2=iBarShift(NULL,0,peack_2_i[i],false);
                              int z1=extri;
                                 if(osma[z2]<osma[z1] && High[z2]>High[z1]){
                                    Sig1[i]=osma[i]+Point/4;
                                       if(DrawLinesSW)fObjTrendLine(ObjName1,peack_2_i[i],osma[z2],Time[extri],osma[z1],false,Col_Peak_1,1,WindowFind(ShortName),0,true);
                                       if(DrawLinesChW)fObjTrendLine(ObjName2,peack_2_i[i],High[z2],Time[extri],High[z1],false,Col_Peak_1,1,0,0,false);
                                       if (divAlert) DisplayAlert("Classical bearish divergence",z2);
                                   }
                                 if(osma[z2]>osma[z1] && High[z2]<High[z1]){
                                    Sig2[i]=osma[i]+Point/4;
                                       if(DrawLinesSW)fObjTrendLine(ObjName1,peack_2_i[i],osma[z2],Time[extri],osma[z1],false,Col_Peak_2,1,WindowFind(ShortName),0,true);
                                       if(DrawLinesChW)fObjTrendLine(ObjName2,peack_2_i[i],High[z2],Time[extri],High[z1],false,Col_Peak_2,1,0,0,false);
                                       if (divAlert) DisplayAlert("Hidden bearish divergence",z2);
                                 }                                                
                           }
                        }
                     }
                  }

               ObjName1=ShortName+"_TroghIW_"+Time[extri];
               ObjName2=ShortName+"_TroghPW_"+Time[extri];
               ObjectDelete(ObjName1);   
               ObjectDelete(ObjName2);    
                               
                  if(TroghNow){
                     if(trogh_1_i[i]!=EMPTY_VALUE){
                        if(trogh_2_i[i]!=EMPTY_VALUE){
                           if(osma[extri]<=osma[iBarShift(NULL,0,trogh_1_i[i],false)]){ 
                              z2=iBarShift(NULL,0,trogh_2_i[i],false);
                              z1=extri;
                                 if(osma[z2]>osma[z1] && Low[z2]<Low[z1]){
                                    Sig1[i]=osma[i]-Point/4;
                                       if(DrawLinesSW)fObjTrendLine(ObjName1,trogh_2_i[i],osma[z2],Time[extri],osma[z1],false,Col_Trough_1,1,WindowFind(ShortName),0,true);
                                       if(DrawLinesChW)fObjTrendLine(ObjName2,trogh_2_i[i],Low[z2],Time[extri],Low[z1],false,Col_Trough_1,1,0,0,false);
                                       if (divAlert) DisplayAlert("Classical bullish divergence",z2);  
                                 }
                                 if(osma[z2]<osma[z1] && Low[z2]>Low[z1]){
                                    Sig2[i]=osma[i]-Point/4;
                                       if(DrawLinesSW)fObjTrendLine(ObjName1,trogh_2_i[i],osma[z2],Time[extri],osma[z1],false,Col_Trough_2,1,WindowFind(ShortName),0,true);
                                       if(DrawLinesChW)fObjTrendLine(ObjName2,trogh_2_i[i],Low[z2],Time[extri],Low[z1],false,Col_Trough_2,1,0,0,false);
                                       if (divAlert) DisplayAlert("Hidden bullish divergence",z2);
                                 }                                                
                           }
                        }
                     }
                  }                  
                  
                                 
                       
            }
      
   return(0);
  }

void fObjTrendLine(
   string aObjectName,
   datetime aTime_1,
   double aPrice_1,
   datetime aTime_2,
   double aPrice_2,
   bool aRay=false,
   color aColor=Red,
   int aWidth=1,
   int aWindowNumber=0,
   int aStyle=0,
   bool aBack=false
   ){
      if(ObjectFind(aObjectName)!=aWindowNumber){
         ObjectCreate(aObjectName,OBJ_TREND,aWindowNumber,aTime_1,aPrice_1,aTime_2,aPrice_2);
      }      
   ObjectSet(aObjectName,OBJPROP_TIME1,aTime_1);
   ObjectSet(aObjectName,OBJPROP_PRICE1,aPrice_1);   
   ObjectSet(aObjectName,OBJPROP_TIME2,aTime_2);       
   ObjectSet(aObjectName,OBJPROP_PRICE2,aPrice_2); 
   ObjectSet(aObjectName,OBJPROP_RAY,aRay);     
   ObjectSet(aObjectName,OBJPROP_COLOR,aColor);
   ObjectSet(aObjectName,OBJPROP_WIDTH,aWidth);
   ObjectSet(aObjectName,OBJPROP_BACK,aBack);
   ObjectSet(aObjectName,OBJPROP_STYLE,aStyle);                
}

void fObjDeleteByPrefix(string aPrefix){
   
   for(int i=ObjectsTotal()-1;i>=0;i--){
      if(StringFind(ObjectName(i),aPrefix,0)==0){
         ObjectDelete(ObjectName(i));
      }
   }
}

//
//
//

void DisplayAlert(string doWhat, int shift)
{
    string dmessage;
    static datetime lastAlertTime;
    if(shift <= 2 && Time[0] != lastAlertTime)
    {
      dmessage = timeFrameToString(_Period)+" "+_Symbol+" at "+TimeToStr(TimeLocal(),TIME_SECONDS)+" OsMA "+doWhat;
          if (divAlertsMessage) Alert(dmessage);
          if (divAlertsNotify)  SendNotification(dmessage);
          if (divAlertsEmail)   SendMail(_Symbol+" OsMA ",dmessage);
          if (divAlertsSound)   PlaySound(divAlertsSoundName); 
          lastAlertTime = Time[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("");
}

