/////////////////////////////////////////////////////////////////////
// MT4-StockasticRSI-Oscillator.mq4
// Version 1.1
// Copyright © 2007, Bruce Hellstrom (brucehvn)
// bhweb@speakeasy.net
// http://www.metaquotes.net
/////////////////////////////////////////////////////////////////////

/*

This is a port of the VT Trader Stochastic-RSI-Oscillator to MT4.
    
Input Parameters:
RSIPeriod = The RSI Period to use (Default 8)
PeriodK = The Stochastic %K period. (Default 8)
SlowPeriod = The final smoothing (slow) value (Default 3)

Revision History

Version 1.0
* Initial Release

Version 1.1 ( 14 Nov 2007 )
* Fixed bug in HHV/LLV calculations to use current bar.  This avoids values > 100
    
*/    


#property copyright "Copyright © 2007, Bruce Hellstrom (brucehvn)"
#property link      "http: //www.metaquotes.net/"

#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1 Blue
#property indicator_style1 STYLE_SOLID
#property indicator_width1 2

#property indicator_levelcolor Red
#property indicator_levelwidth 1
#property indicator_levelstyle STYLE_DOT

#define INDICATOR_VERSION "v1.1"


// Input Parameters
extern int RSIPeriod = 8;
extern int PeriodK = 8;
extern int SlowPeriod = 3;
extern int StochBuyLevel = 25,
           StochSellLevel = 75,
           StochOSLevel = 25,
           StochOBLevel = 75;
extern string m0 = "MA_Adaptive_RSI settings";
extern int MA_Period = 20;
extern int MA_Shift = 0;
extern int MA_Method = 2;
extern int MA_Price = 0;
extern int ARSI_Period = 14;
extern bool AlertOnClosedCandle=true,
            ShowArrows=true,
            AlertOnBuySell=true,
            EmailOnBuySell=false,
            AlertOnOBOS=true,
            EmailOnOBOS=false;
extern int  ArrowWidth = 2;
extern color   ArrowsUpColor = Green,
               ArrowsDnColor = Red;

// Buffers
double RSIBuffer[];
double StochBuffer[];
double TempBuffer[];
bool debug = false;
int SignalCandle=0;
datetime LastAlert=0,LastAlert1=0;
// Other Variables
string ShortName;


/////////////////////////////////////////////////////////////////////
// Custom indicator initialization function
/////////////////////////////////////////////////////////////////////

int init() {

    IndicatorBuffers( 1 );
    SetIndexStyle( 0, DRAW_LINE, STYLE_SOLID, 1 );
    SetIndexBuffer( 0, StochBuffer );
    SetIndexDrawBegin( 0, RSIPeriod );
    ShortName = "MT4-StochasticRSI-Oscillator-" + INDICATOR_VERSION + " (" + RSIPeriod + "," + PeriodK + "," + SlowPeriod + ")";
    SetLevelValue(0,StochOBLevel);
    SetLevelValue(1,StochOSLevel);
    IndicatorShortName( ShortName );
    SetIndexLabel( 0, ShortName );
    
    ArraySetAsSeries( RSIBuffer, true );
    ArraySetAsSeries( TempBuffer, true );
    
    Print( ShortName );
    Print( "Copyright (c) 2007 - Bruce Hellstrom, bhweb@speakeasy.net" );
    if (AlertOnClosedCandle) SignalCandle=1;
    return( 0 );
}

/////////////////////////////////////////////////////////////////////
// Custom indicator deinitialization function
/////////////////////////////////////////////////////////////////////

void deinit() {
   Comment("");
   if (ShowArrows) {
      for (int i=ObjectsTotal()-1;i>=0;i--) {
         if (StringFind(ObjectName(i),"StochRSI")>-1) ObjectDelete(ObjectName(i));
         }
      }
}

/////////////////////////////////////////////////////////////////////
// Indicator Logic run on every tick
/////////////////////////////////////////////////////////////////////

int start() {
    
    int counted_bars = IndicatorCounted();
    
    // Check for errors
    if ( counted_bars < 0 ) {
        return( -1 );
    }

    // Last bar will be recounted
    if ( counted_bars > 0 ) {
        counted_bars--;
    }

    // Resize the non-buffer array if necessary
    if ( ArraySize( RSIBuffer ) != ArraySize( StochBuffer ) ) {
        ArraySetAsSeries( RSIBuffer, false );
        ArrayResize( RSIBuffer, ArraySize( StochBuffer ) );
        ArraySetAsSeries( RSIBuffer, true );
    }
    
    if ( ArraySize( TempBuffer ) != ArraySize( StochBuffer ) ) {
        ArraySetAsSeries( TempBuffer, false );
        ArrayResize( TempBuffer, ArraySize( StochBuffer ) );
        ArraySetAsSeries( TempBuffer, true );
    }
    
    
    // Get the upper limit
    int limit = Bars - counted_bars;
    
    for ( int ictr = 0; ictr < limit; ictr++ ) {
        RSIBuffer[ictr] = iRSI( NULL, 0, RSIPeriod, PRICE_CLOSE, ictr );
        if ( debug ) {
            if ( RSIBuffer[ictr] > 100.0 ) {
                Print( "Bar: ", ictr, " RSI: ", RSIBuffer[ictr] );
            }
        }
    }

    for ( ictr = 0; ictr < limit; ictr++ ) {
        double llv = LLV( RSIBuffer, PeriodK, ictr );
        double hhv = HHV( RSIBuffer, PeriodK, ictr );
        
        if ( ( hhv - llv ) > 0 ) {
            TempBuffer[ictr] = ( ( RSIBuffer[ictr] - llv ) /
                                 ( hhv - llv ) ) * 100;
            if ( debug && ictr < 100 ) {
                if ( TempBuffer[ictr] > 100.0 ) {
                    Print( "Bar: ", ictr, " TempBuffer: ", TempBuffer[ictr], " RSI: ", RSIBuffer[ictr], " hhv: ", hhv, " llv:", llv );
                }
            }
        }
    }
    double rsimaUp,rsimaDn;
    for ( ictr = 0; ictr < limit; ictr++ ) {
        StochBuffer[ictr] = iMAOnArray( TempBuffer, 0, SlowPeriod, 0, MODE_EMA, ictr );
    }
    for (ictr=limit-1;ictr>=SignalCandle;ictr--) {
      rsimaUp=iCustom(NULL,0,"MA_adaptive_rsi nrp",MA_Period,MA_Shift,MA_Method,MA_Price,ARSI_Period,1,ictr);
      rsimaDn=iCustom(NULL,0,"MA_adaptive_rsi nrp",MA_Period,MA_Shift,MA_Method,MA_Price,ARSI_Period,3,ictr);
      Comment("rsi=",MathMin(rsimaUp,rsimaDn));
      if (rsimaUp!=EMPTY_VALUE && rsimaDn==EMPTY_VALUE && StochBuffer[ictr]>StochBuffer[ictr+1] && StochBuffer[ictr+1]<=StochBuffer[ictr+2] && StochBuffer[ictr+1]<=StochOSLevel) {
         if (ictr==SignalCandle && LastAlert!=Time[0]) {
            LastAlert=Time[0];
            DoAlert(1,1);
            }
         if (ShowArrows) DrawArrow(ictr,ArrowsUpColor,233,false);
         }
      else if (rsimaDn!=EMPTY_VALUE && rsimaUp==EMPTY_VALUE && StochBuffer[ictr]<StochBuffer[ictr+1] && StochBuffer[ictr+1]>=StochBuffer[ictr+2] && StochBuffer[ictr+1]>=StochOBLevel) {
         if (LastAlert1!=Time[0] && ictr==SignalCandle) {
            LastAlert1=Time[0];
            DoAlert(-1,1);
            }
         if (ShowArrows) DrawArrow(ictr,ArrowsDnColor,234,true);
         }
      if (rsimaUp!=EMPTY_VALUE && rsimaDn==EMPTY_VALUE && StochBuffer[ictr]<StochOSLevel && StochBuffer[ictr+1]>=StochOSLevel) {   
         if (LastAlert!=Time[0] && ictr==SignalCandle) {
            LastAlert=Time[0];
            DoAlert(1,-1);
            }
         }
      else if (rsimaDn!=EMPTY_VALUE && rsimaUp==EMPTY_VALUE && StochBuffer[ictr]>StochOBLevel && StochBuffer[ictr+1]<=StochOBLevel) {
         if (LastAlert1!=Time[0] && ictr==SignalCandle) {
            LastAlert1=Time[0];
            DoAlert(-1,-1);
            }
         }
      }
    return( 0 );
}


double LLV( double& indBuffer[], int Periods, int shift ) {
    double dblRet = 0.0;
    int startindex = shift;
    
    for ( int llvctr = startindex; llvctr < ( startindex + Periods ); llvctr++ ) {
        if ( llvctr == startindex ) {
            dblRet = indBuffer[llvctr];
        }
        dblRet = MathMin( dblRet, indBuffer[llvctr] );
    }
    
    return( dblRet );
}

double HHV( double& indBuffer[], int Periods, int shift ) {
    double dblRet = 0.0;
    int startindex = shift;
    
    for ( int hhvctr = startindex; hhvctr < ( startindex + Periods ); hhvctr++ ) {
        if ( hhvctr == startindex ) {
            dblRet = indBuffer[hhvctr];
        }
        dblRet = MathMax( dblRet, indBuffer[hhvctr] );
    }
    
    return( dblRet );
}
void DrawArrow(int i, color theColor,int theCode,bool up) {
   string name = "StochRSI:"+Time[i];
   double gap  = 3.0*iATR(NULL,0,20,i)/4.0;   
   ObjectCreate(name,OBJ_ARROW,0,Time[i],0);
   ObjectSet(name,OBJPROP_ARROWCODE,theCode);
   ObjectSet(name,OBJPROP_COLOR,theColor);
   ObjectSet(name,OBJPROP_WIDTH,ArrowWidth);
   if (up)
         ObjectSet(name,OBJPROP_PRICE1,High[i]+gap);
   else  ObjectSet(name,OBJPROP_PRICE1,Low[i] -gap);
   return;
}
void DoAlert(int cmd, int res) {
   if (res>0) {
      if (cmd>0) {
         if (AlertOnBuySell) Alert("StochRSI Buy Alert! "+Symbol()+" Period "+Period());
         if (EmailOnBuySell) SendMail("StochRSI Buy Alert!",Symbol()+" Period "+Period()+" - Buy entry price "+NormalizeDouble(Ask,Digits));
         }
      else if (cmd<0) {
         if (AlertOnBuySell) Alert("StochRSI Sell Alert! "+Symbol()+" Period "+Period());
         if (EmailOnBuySell) SendMail("StochRSI Sell Alert!",Symbol()+" Period "+Period()+" - Sell entry price "+NormalizeDouble(Bid,Digits));
         }
      }
   else if (res<0) {
      if (cmd>0) {
         if (AlertOnOBOS) Alert("StochRSI OverSold Alert! "+Symbol()+" Period "+Period());
         if (EmailOnOBOS) SendMail("StochRSI OverSold Alert!",Symbol()+" Period "+Period());
         }
      else if (cmd<0) {
         if (AlertOnOBOS) Alert("StochRSI OverBought Alert! "+Symbol()+" Period "+Period());
         if (EmailOnOBOS) SendMail("StochRSI OverBought Alert!",Symbol()+" Period "+Period());
         }
      }
   return;
}

                  

