//+------------------------------------------------------------------+
//|                 FXGuru_RSIHisto TripleStoch Divergence Alert.mq4 |
//|                               Copyright � 2009, the Guru Online. |
//|                                     http://www.theguruonline.biz |
//+------------------------------------------------------------------+
//| v1.0 Initial RSIHisto/TripleStoch Divergence Alert coding        |
//| v1.1 Restricted distance between bars to 55                      |
//| v1.2 Modified GrayZone inputs and Stoch Alert                    |
//| v1.3 Tweeked Divergence coding                                   |
//| v1.4 Made Divergence optional                                    |
//+------------------------------------------------------------------+
#property copyright "Copyright � 2009, the Guru Online."
#property link      "http://www.theguruonline.biz"

#property indicator_separate_window
#property indicator_buffers 7

//--- RSIHisto
#property indicator_width1 4
#property indicator_color1 Blue
#property indicator_style1 DRAW_HISTOGRAM
#property indicator_width2 4
#property indicator_color2 Red
#property indicator_style2 DRAW_HISTOGRAM
#property indicator_width3 3
#property indicator_color3 LightSlateGray
#property indicator_style3 DRAW_LINE
#property indicator_width4 4
#property indicator_color4 LightSlateGray
#property indicator_style4 DRAW_HISTOGRAM

//--- TripleStochastic
#property indicator_color5 Black
#property indicator_style5 DRAW_LINE
#property indicator_width5 2
#property indicator_levelcolor Black
#property indicator_levelstyle STYLE_DASH
#property indicator_levelwidth 1
#property indicator_level3 44
#property indicator_level4 -44
#define   indicator_minimum -53
#define   indicator_maximum 53

//--- Divergence
#property indicator_color6 MediumBlue
#property indicator_style6 DRAW_ARROW
#property indicator_width6 0
#property indicator_color7 Maroon
#property indicator_style7 DRAW_ARROW
#property indicator_width7 0

//+------------------------------------------------------------------+
//| Indicator variables                                              |
//+------------------------------------------------------------------+
static string   Indicator_Name            ="ATM_RSI TripleStoch";
static string   Version                   ="1.4";

extern string   a_                        =" : RSI Variables :";
extern int      RSI_Period                =13;
extern string   a1_                       =" : Price :";
extern string   a2_                       =" : : 0=Close price";
extern string   a3_                       =" : : 1=Open price";
extern string   a4_                       =" : : 2=High price";
extern string   a5_                       =" : : 3=Low price";
extern string   a6_                       =" : : 4=Median price, (high+low)/2";
extern string   a7_                       =" : : 5=Typical price, (high+low+close)/3";
extern string   a8_                       =" : : 6=Weighted close price, (high+low+close+close)/4";
extern int      RSI_Price                 =0;
extern bool     RSI_Alerts                =false;
extern double   BuyAlertLevel             =-44,
                SellAlertLevel            =44;
extern double   RSIHistoModify            =1.5;
extern int      RSIHisto_Width            =2;
extern color    RSIHistoUp_Color          =Blue;
extern color    RSIHistoDn_Color          =Red;
extern int      RSI_Width                 =2;
extern string   b_                        =" : GreyZone Variables :";
extern int      GrayZone_Limit            =13;
extern color    GrayZone_Color            =DarkGray;
extern string   c_                        =" : TripleStochastic Variables :";
extern int      TripleStochastic_KPeriod  =21;
extern int      TripleStochastic_Slowing  =8;
extern int      TripleStochastic_Price    =0;
extern int      TripleStochastic_Width    =2;
extern color    TripleStochastic_Color    =Black;
extern bool     TripleStochastic_Alerts   =false;
extern double   TripleStochastic_UpperZone=85,
                TripleStochastic_LowerZone=15;
extern int      TripleStochastic_LevelStyle=1;
extern int      TripleStochastic_LevelWidth=1;
extern color    TripleStochastic_LevelColor=Black;
extern string   d_                        =" : Divergence Variables :";
extern bool     Show_Divergence           =FALSE;
extern int      DivergenceMinBarLimit     =8;
extern int      DivergenceMaxBarLimit     =44;
extern int      DivergenceConfirmation    =3;
extern bool     drawDivergenceLines       =FALSE;
extern bool     Divergence_Alerts         =FALSE;
extern int      bullishDivergence_Arrow   =108;//SYMBOL_ARROWUP;
extern int      bearishDivergence_Arrow   =108;//SYMBOL_ARROWDOWN;
extern int      Divergence_Arrow_Size     =0;
extern bool     Divergence_ArrowInGrayZone=TRUE;
extern color    bullishDivergence_Color   =MediumBlue;
extern color    bearishDivergence_Color   =Maroon;

static int      Positive=0, Negative=0;
extern string   e_                        =" : Alert Variables :";
extern bool     Alert_EveryTick           =FALSE;
extern bool     Alert_Popup               =false;
extern bool     Alert_Mail                =FALSE;
extern string   Alert_Mail_Subject        ="";
extern string   Alert_Audible             ="nothing.wav";
static datetime Alert_Time;

extern string   f_                        =" : Display Variables :";
extern string   f1_                       =" : Corner : 0=Top Left";
extern string   f2_                       =" : : 1=Top Right";
extern string   f3_                       =" : : 2=Bottom Left";
extern string   f4_                       =" : : 3=Bottom Right";
static int      Display_Corner            =3;
extern color    color_text                =Black;

static bool     DebugLogger               =FALSE;
static datetime lastAlertTime, BarTimeLastAlert;
static string   indicatorShortName;
static int      indicatorWindow;

double RSI_Up[],
       RSI_Dn[],
       RSI_Main[],
       RSI_Gray[],
       TripleStochastic[],
       bullishDivergence[],
       bearishDivergence[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
   IndicatorBuffers(7);
   SetIndexStyle( 0, DRAW_HISTOGRAM, EMPTY, RSIHisto_Width, RSIHistoUp_Color );
   SetIndexBuffer( 0, RSI_Up );
   SetIndexStyle( 1, DRAW_HISTOGRAM, EMPTY, RSIHisto_Width, RSIHistoDn_Color );
   SetIndexBuffer( 1, RSI_Dn );
   SetIndexStyle( 2, DRAW_LINE, STYLE_SOLID, RSI_Width, GrayZone_Color );
   SetIndexBuffer( 2, RSI_Main );
   SetIndexStyle( 3, DRAW_HISTOGRAM, EMPTY, RSIHisto_Width, GrayZone_Color );
   SetIndexBuffer( 3, RSI_Gray );

   SetIndexStyle( 4, DRAW_LINE, STYLE_SOLID, TripleStochastic_Width, TripleStochastic_Color );
   SetIndexBuffer( 4, TripleStochastic );
   SetLevelStyle( TripleStochastic_LevelStyle, TripleStochastic_LevelWidth, TripleStochastic_LevelColor );
   SetLevelValue( 0, ( TripleStochastic_UpperZone/100*80 )-40 );
   SetLevelValue( 1, ( TripleStochastic_LowerZone/100*80 )-40 );

   SetIndexStyle( 5, DRAW_ARROW, STYLE_SOLID, Divergence_Arrow_Size, bullishDivergence_Color );
   SetIndexBuffer( 5, bullishDivergence );
   SetIndexArrow( 5, bullishDivergence_Arrow );
   SetIndexStyle( 6, DRAW_ARROW, STYLE_SOLID, Divergence_Arrow_Size, bearishDivergence_Color );
   SetIndexBuffer( 6, bearishDivergence );
   SetIndexArrow( 6, bearishDivergence_Arrow );

   indicatorShortName="RSI ["+DoubleToStr( RSI_Period, 0 )+","+DoubleToStr( RSI_Price, 0 )+","+DoubleToStr( RSIHistoModify, 2 )
      +"X] 3xStoc ["+DoubleToStr( TripleStochastic_KPeriod, 0 )+","+DoubleToStr( TripleStochastic_Slowing, 0 )+","+DoubleToStr( TripleStochastic_Price, 0 )+"]";

   if( Show_Divergence )
     {
      Indicator_Name=Indicator_Name+" Divergence";
      indicatorShortName=indicatorShortName+" Divergence";
     }

   if( ( RSI_Alerts || TripleStochastic_Alerts || Divergence_Alerts ) && ( Alert_Popup || Alert_Mail || Alert_Audible!="" ) )
     {
      Indicator_Name=Indicator_Name+" Alert";
      indicatorShortName=indicatorShortName+" Alert";
      if( Alert_Mail_Subject=="" ) Alert_Mail_Subject=Indicator_Name;
     }

   IndicatorShortName( indicatorShortName );
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
   for( int i = ObjectsTotal() - 1; i >= 0; i--)
     {
      string label = ObjectName(i);
      if( StringSubstr(label, 0, 14) != "DivergenceLine")
         continue;
      ObjectDelete(label);   
     }
   Comment( "" );
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   string Alert_Message="";
   indicatorWindow=WindowFind( indicatorShortName );
   if( indicatorWindow<1 ) return(0);
   _Draw_Label(  5,  1,  7, "Copyright", CharToStr( 169 )+" "+Year()+", ElectroLegal.com & the Guru : [v"+Version+"] "+Indicator_Name, color_text, "Arial Narrow", 3 );
   _Draw_Label(  5, 10, 14, "ATM",       "ATM",                                                                                        color_text, "Arial Black",  3 );
   if( ObjectFind( "["+Indicator_Name+"] GrayZone" )==-1 )
     {
      ObjectCreate( "["+Indicator_Name+"] GrayZone", OBJ_RECTANGLE, indicatorWindow, 0, GrayZone_Limit, 0, -GrayZone_Limit );
      ObjectSet( "["+Indicator_Name+"] GrayZone", OBJPROP_STYLE, STYLE_SOLID );
      ObjectSet( "["+Indicator_Name+"] GrayZone", OBJPROP_COLOR, GrayZone_Color );
      ObjectSet( "["+Indicator_Name+"] GrayZone", OBJPROP_BACK, TRUE );
      ObjectSet( "["+Indicator_Name+"] GrayZone", OBJPROP_TIME1, Time[Bars] );
     }
   ObjectSet( "["+Indicator_Name+"] GrayZone", OBJPROP_TIME2, Time[0]+Period()*60 );

   int counted_bars=IndicatorCounted();
//---- check for possible errors
   if( counted_bars<0 ) return(-1);
//---- last counted bar will be recounted
   if( counted_bars>0 ) counted_bars--;

   int limit=Bars-31;
   if( counted_bars>=31 ) limit=Bars-counted_bars-1;
//----
   for( int I=limit; I>=0; I-- )
     {
//--- RSI Histo
      RSI_Main[I]=( ( iRSI( 0, 0, RSI_Period, RSI_Price, I )-50 )*RSIHistoModify );
      if( RSI_Main[I]>GrayZone_Limit )
        {
         RSI_Up[I]=RSI_Main[I];
         RSI_Dn[I]=GrayZone_Limit;
         RSI_Gray[I]=GrayZone_Limit;
        }
      else if( RSI_Main[I]<-GrayZone_Limit )
        {
         RSI_Up[I]=-GrayZone_Limit;
         RSI_Dn[I]=RSI_Main[I];
         RSI_Gray[I]=-GrayZone_Limit;
        }
      else
        {
         RSI_Dn[I]=EMPTY_VALUE;
         RSI_Up[I]=EMPTY_VALUE;
         RSI_Gray[I]=EMPTY_VALUE;
        }
      if( RSI_Main[I]>BuyAlertLevel && RSI_Alerts )
        {
         if( Positive==0 )
           {
            Positive=1;
            Negative=0;
            if( BuyAlertLevel>0 ) Alert_Message=Alert_Message+"ATM Possible PAB Buy Heads Up.\n";
           }
        }
      else if( RSI_Main[I]<SellAlertLevel && RSI_Alerts )
        {
         if( Negative==0 )
           {
            Negative=1;
            Positive=0;
            if( SellAlertLevel<0 ) Alert_Message=Alert_Message+"ATM Possible PAB Sell Heads Up.\n";
           }
        }
//--- Triple Stochastic
      TripleStochastic[I]=( ( (
         iStochastic( NULL, 0, TripleStochastic_KPeriod*1, 1, TripleStochastic_Slowing*1, 0, TripleStochastic_Price, MODE_MAIN, I )+
         iStochastic( NULL, 0, TripleStochastic_KPeriod*2, 1, TripleStochastic_Slowing*2, 0, TripleStochastic_Price, MODE_MAIN, I )+
         iStochastic( NULL, 0, TripleStochastic_KPeriod*3, 1, TripleStochastic_Slowing*3, 0, TripleStochastic_Price, MODE_MAIN, I ) )/3.0
         )/100*80 )-40;
      if( I<1 )
        {
         if( iTime( NULL, 0, I )>BarTimeLastAlert )
           {
            BarTimeLastAlert=Time[0];
            if( TripleStochastic[I]>=( TripleStochastic_LowerZone/100*80 )-40 && TripleStochastic[I+1]<( TripleStochastic_LowerZone/100*80 )-40 && TripleStochastic_Alerts )
              {
               Alert_Message=Alert_Message+"ATM Stoch heads OVERBOUGHT.\n";
              }
            if( TripleStochastic[I]<=( TripleStochastic_UpperZone/100*80 )-40 && TripleStochastic[I+1]>( TripleStochastic_UpperZone/100*80 )-40 && TripleStochastic_Alerts )
              {
               Alert_Message=Alert_Message+"ATM Stoch heads OVERSOLD.\n";
              }
           }
        }
//--- Divergence
      if( Show_Divergence )
        {
         ObjectDelete( "DivergenceLine #"+DoubleToStr( I+DivergenceConfirmation, 0 ) );
         ObjectDelete( "DivergenceLine PA#"+DoubleToStr( I+DivergenceConfirmation, 0 ) );
         bearishDivergence[I+DivergenceConfirmation]=EMPTY_VALUE;
         if( IsIndicatorPeak( I+DivergenceConfirmation ) )
           {
            int currentPeak=I+DivergenceConfirmation;
            int lastPeak   =GetIndicatorLastPeak( I+DivergenceConfirmation );
            if(
                  lastPeak>0
               && RSI_Main[currentPeak]<RSI_Main[lastPeak]
               && High[currentPeak]>High[lastPeak]
              )
              {
                if( Divergence_ArrowInGrayZone ) bearishDivergence[currentPeak]=0;
                else                             bearishDivergence[currentPeak]=RSI_Main[currentPeak];
                if( drawDivergenceLines )
                  {
                    DrawPriceTrendLine( Time[currentPeak], Time[lastPeak], High[currentPeak], 
                                        High[lastPeak], bearishDivergence_Color, STYLE_SOLID );
                    DrawIndicatorTrendLine( Time[currentPeak], Time[lastPeak], RSI_Main[currentPeak],
                                            RSI_Main[lastPeak], bearishDivergence_Color, STYLE_SOLID );
                  }
               if( Divergence_Alerts ) Alert_Message=Alert_Message+"Classic bearish divergence @"+Ask+".\n";
              }
            if(
                  lastPeak>0
               && RSI_Main[currentPeak]>RSI_Main[lastPeak]
               && High[currentPeak]<High[lastPeak]
              )
              {
                if( Divergence_ArrowInGrayZone ) bearishDivergence[currentPeak]=0;
                else                             bearishDivergence[currentPeak]=RSI_Main[currentPeak];
                if( drawDivergenceLines )
                  {
                    DrawPriceTrendLine( Time[currentPeak], Time[lastPeak], High[currentPeak], 
                                        High[lastPeak], bearishDivergence_Color, STYLE_DOT );
                    DrawIndicatorTrendLine( Time[currentPeak], Time[lastPeak], RSI_Main[currentPeak],
                                            RSI_Main[lastPeak], bearishDivergence_Color, STYLE_DOT );
                  }
               if( Divergence_Alerts ) Alert_Message=Alert_Message+"Reverse bearish divergence @"+Ask+".\n";
              }
           }
         bullishDivergence[I+DivergenceConfirmation]=EMPTY_VALUE;
         if( IsIndicatorTrough( I+DivergenceConfirmation ) )
           {
            int currentTrough=I+DivergenceConfirmation;
            int lastTrough   =GetIndicatorLastTrough( I+DivergenceConfirmation );
            if(
                  lastTrough>0
               && RSI_Main[currentTrough]>RSI_Main[lastTrough]
               && Low[currentTrough]<Low[lastTrough]
              )
              {
               if( Divergence_ArrowInGrayZone ) bullishDivergence[currentTrough]=0;
               else                             bullishDivergence[currentTrough]=RSI_Main[currentTrough];
               if( drawDivergenceLines )
                 {
                   DrawPriceTrendLine( Time[currentTrough], Time[lastTrough], Low[currentTrough], 
                                       Low[lastTrough], bullishDivergence_Color, STYLE_SOLID );
                   DrawIndicatorTrendLine( Time[currentTrough], Time[lastTrough], RSI_Main[currentTrough],
                                           RSI_Main[lastTrough], bullishDivergence_Color, STYLE_SOLID );
                 }
               if( Divergence_Alerts ) Alert_Message=Alert_Message+"Classic bullish divergence @"+Ask+".\n";
              }
            if(
                  lastTrough>0
               && RSI_Main[currentTrough]<RSI_Main[lastTrough]
               && Low[currentTrough]>Low[lastTrough]
              )
              {
               if( Divergence_ArrowInGrayZone ) bullishDivergence[currentTrough]=0;
               else                             bullishDivergence[currentTrough]=RSI_Main[currentTrough];
               if( drawDivergenceLines==true )
                 {
                   DrawPriceTrendLine( Time[currentTrough], Time[lastTrough], Low[currentTrough], 
                                       Low[lastTrough], bullishDivergence_Color, STYLE_DOT );
                   DrawIndicatorTrendLine( Time[currentTrough], Time[lastTrough], RSI_Main[currentTrough],
                                           RSI_Main[lastTrough], bullishDivergence_Color, STYLE_DOT );
                 }
               if( Divergence_Alerts ) Alert_Message=Alert_Message+"Reverse bullish divergence @"+Ask+".\n";
              }
           }
        } //- end Divergence
     }
   if( ( Alert_Time!=Time[0] || Alert_EveryTick ) && Alert_Message!="" )
     {
      if( Alert_Popup ) Alert( Symbol()+" M"+Period()+":"+Alert_Message );
      if( Alert_Mail  ) SendMail( Symbol()+" M"+Period()+":"+Alert_Mail_Subject, Alert_Message );
      if( Alert_Audible!="" ) PlaySound( Alert_Audible );
      Alert_Time=Time[0];
      Alert_Message="";
     }
   return(0);
}
//+------------------------------------------------------------------+
//| Draws a label                                                    |
//+------------------------------------------------------------------+
void _Draw_Label( int _x, int _y, int _fontSize, string _name, string _text, color _color, string _fontName, int _Display_Corner=-1 )
  {
   if( _Display_Corner==-1 ) _Display_Corner=Display_Corner;
   ObjectDelete( "["+Indicator_Name+"] "+_name );
   ObjectCreate( "["+Indicator_Name+"] "+_name, OBJ_LABEL, indicatorWindow, 0, 0 );
   ObjectSetText( "["+Indicator_Name+"] "+_name, _text, _fontSize, _fontName, _color );
   ObjectSet( "["+Indicator_Name+"] "+_name, OBJPROP_BACK, TRUE );
   ObjectSet( "["+Indicator_Name+"] "+_name, OBJPROP_CORNER, _Display_Corner );
   ObjectSet( "["+Indicator_Name+"] "+_name, OBJPROP_XDISTANCE, _x );
   ObjectSet( "["+Indicator_Name+"] "+_name, OBJPROP_YDISTANCE, _y );
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsIndicatorPeak( int shift )
  {
   if(
      RSI_Main[shift]>GrayZone_Limit
     )
     {
      for( int i=1; i<=DivergenceConfirmation; i++)
        {
         if(
               RSI_Main[shift+i]<GrayZone_Limit
            || RSI_Main[shift]<RSI_Main[shift+i]
//            || RSI_Main[shift-i]<GrayZone_Limit
            || RSI_Main[shift]<RSI_Main[shift-i]
           )
            return( FALSE );
        }
      return( TRUE );
     }   
   return( FALSE );
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsIndicatorTrough( int shift )
  {
   if(
      RSI_Main[shift]<-GrayZone_Limit
     )
     {
      for( int i=1; i<=DivergenceConfirmation; i++)
        {
         if(
               RSI_Main[shift+i]>-GrayZone_Limit
            || RSI_Main[shift]>RSI_Main[shift+i]
//            || RSI_Main[shift-i]>-GrayZone_Limit
            || RSI_Main[shift]>RSI_Main[shift-i]
           )
            return( FALSE );
        }
      return( TRUE );
     }   
   return( FALSE );
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int GetIndicatorLastPeak( int shift )
  {
   for( int i=shift+DivergenceMinBarLimit; i<shift+DivergenceMaxBarLimit; i++ )
     {
      if(
            IsIndicatorPeak( i )
         && RSI_Main[shift]<RSI_Main[i]
         && High[shift]>High[i]
        )
         return( i );
     }
   return( -1 );
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int GetIndicatorLastTrough( int shift )
  {  
   for( int i=shift+DivergenceMinBarLimit; i<shift+DivergenceMaxBarLimit; i++ )
     {
      if(
         IsIndicatorTrough( i )
         && RSI_Main[shift]>RSI_Main[i]
         && Low[shift]<Low[i]
        )
         return( i );
     }
   return( -1 );
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DrawPriceTrendLine(datetime x1, datetime x2, double y1, double y2, color lineColor, double style )
  {
   string label = "DivergenceLine PA#" + DoubleToStr(x1, 0);
   ObjectDelete(label);
   ObjectCreate(label, OBJ_TREND, 0, x1, y1, x2, y2, 0, 0);
   ObjectSet(label, OBJPROP_RAY, 0);
   ObjectSet(label, OBJPROP_COLOR, lineColor);
   ObjectSet(label, OBJPROP_STYLE, style);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DrawIndicatorTrendLine(datetime x1, datetime x2, double y1, double y2, color lineColor, double style)
  {
//   int indicatorWindow = WindowFind("RSI HistoAlert ["+RSI_Period+","+RSI_Price+","+RSI_Signal+","+RSI_Mode+","+DoubleToStr(RSIHistoModify,2)+"X]");
   if(indicatorWindow < 0)
       return;
   string label = "DivergenceLine #" + DoubleToStr(x1, 0);
   ObjectDelete(label);
   ObjectCreate(label, OBJ_TREND, indicatorWindow, x1, y1, x2, y2, 0, 0);
   ObjectSet(label, OBJPROP_RAY, 0);
   ObjectSet(label, OBJPROP_COLOR, lineColor);
   ObjectSet(label, OBJPROP_STYLE, style);
  }
//+------------------------------------------------------------------+