Regular RSI Div

Author: Copyright � 2007, FX5
Regular RSI Div

This script is a technical analysis tool designed for the MetaTrader platform to identify "divergences"—situations where the price movement of an asset contradicts the momentum shown by a mathematical indicator. By spotting these contradictions, traders can potentially identify when a trend is losing steam or when a reversal may be approaching.

Core Logic and Mechanics

1. Data Foundation The script begins by calculating two primary pieces of information:

  • Oscillator Momentum (OsMA): It modifies the standard RSI (Relative Strength Index) and applies a multiplier to create a balanced oscillator that moves above and below a zero line.
  • Smoothing: The logic incorporates Moving Averages (EMA and SMA) to smooth out "market noise," ensuring that the signals generated are based on significant trends rather than minor, momentary price flickers.

2. Peak and Trough Detection To find a divergence, the script must first identify significant high points (peaks) and low points (troughs). It scans the historical data to find:

  • Local "top" points where the indicator reached a high level before turning back down.
  • Local "bottom" points where the indicator reached a low level before turning back up. It performs this search systematically, looking for specific price structures that define a clear "swing."

3. Divergence Identification The primary goal of the script is to compare two consecutive peaks (for bearish signals) or two consecutive troughs (for bullish signals). It looks for two specific types of disagreement:

  • Bearish Divergence: This occurs when the market price makes a higher high (going up), but the oscillator makes a lower high (going down). This suggests that while the price is rising, the underlying momentum is weakening, potentially signaling a downward reversal.
  • Bullish Divergence: This occurs when the market price makes a lower low (going down), but the oscillator makes a higher low (going up). This suggests that despite the price dropping, buying momentum is building, potentially signaling an upward reversal.

4. Visual Feedback and Alerts Once the script identifies one of these contradictions:

  • Arrows: It places visual arrows on the chart to highlight exactly where the divergence occurred.
  • Trend Lines: If enabled in the settings, the script automatically draws lines connecting the peaks or troughs. These lines provide a clear visual "bridge" between the price action and the indicator movement, making it easier for the user to see the mathematical gap between the two.

Summary of User Experience

Instead of forcing the user to manually compare complex charts, this script automates the heavy lifting. It constantly monitors the history of the candles, filters out minor fluctuations using moving averages, and alerts the user via visual markers whenever the price and the momentum indicator stop moving in sync.

Indicators Used
Moving average indicatorMoving average indicatorRelative strength index
Miscellaneous
Implements a curve of type %1
10 Views
0 Downloads
0 Favorites
Regular RSI Div
//+------------------------------------------------------------------+
//|                                               FX5_Divergence.mq4 |
//|                                                              FX5 |
//|                                                    hazem@uk2.net |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2007, FX5"
#property link      "hazem@uk2.net"
//----
#property indicator_separate_window
#property indicator_buffers 5
#property indicator_color1 LimeGreen
#property indicator_color2 FireBrick
#property indicator_color3 Green
#property indicator_color4 Red
//---- input parameters
extern string separator1 = "*** bear Settings ***";
 extern double rsiperiod1=7;
 
 //extern double t3=3;
//extern double b=0.7;
 int    fastEMA = 3;
 int    slowEMA = 6;
 int    signal = 3;
extern string separator2 = "*** Indicator Settings";
extern double positiveSensitivity = 0.0001;
extern double negativeSensitivity = -0.0001;
extern double historyBarsCount = 0;
extern bool   drawDivergenceLines = false;
//---- buffers
double upOsMA[];
double downOsMA[];
double bullishDivergence[];
double bearishDivergence[];
double OsMA[];
double MACD[];
double Signal[];
static int chartBarsCount;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//---- indicators
   IndicatorBuffers(7);
//----   
   SetIndexStyle(0, DRAW_HISTOGRAM, STYLE_SOLID, 2);
   SetIndexBuffer(0, upOsMA);
   SetIndexStyle(1, DRAW_HISTOGRAM, STYLE_SOLID, 2);
   SetIndexBuffer(1, downOsMA);
   SetIndexStyle(2, DRAW_ARROW);
   SetIndexBuffer(2, bullishDivergence);
   SetIndexArrow(2, 233);
   SetIndexStyle(3, DRAW_ARROW);
   SetIndexBuffer(3, bearishDivergence);
   SetIndexArrow(3, 234);
   SetIndexStyle(4, DRAW_NONE);
   SetIndexBuffer(4, OsMA);
// additional buffers   
   SetIndexBuffer(5, MACD);
   SetIndexBuffer(6, Signal);      
//----   
   SetIndexDrawBegin(0, signal);
   SetIndexDrawBegin(1, signal);
//----   
   IndicatorDigits(MarketInfo(Symbol(), MODE_DIGITS) + 2);
   IndicatorShortName("Regular_RSI_Divergence");
//----
   if(historyBarsCount <= 0 || historyBarsCount > Bars)
       chartBarsCount = Bars;
   else
       chartBarsCount = historyBarsCount;
//----
   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);   
     }
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   int countedBars = IndicatorCounted();
   if(countedBars < 0)
       countedBars = 0;
//----
   CalculateOsMA(countedBars);      
   CalculateDivergence(countedBars);   
//----
   return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CalculateDivergence(int countedBars)
  {
   double arrowSeparation = 1 / MathPow(10, MarketInfo(Symbol(), 
                            MODE_DIGITS) + 2) * 50;
//----    
   for(int i = chartBarsCount - countedBars; i >= 0; i--)
     {
       bearishDivergence[i] = EMPTY_VALUE;
       bullishDivergence[i] = EMPTY_VALUE;
       //----   
       int firstPeakOrTroughShift = GetFirstPeakOrTrough(i);
       double firstPeakOrTroughOsMA = OsMA[firstPeakOrTroughShift];
       if(firstPeakOrTroughOsMA > 0)
         {
           int peak_0   = GetIndicatorLastPeak(i);
           int trough_0 = GetIndicatorLastTrough(peak_0);
           int peak_1   = GetIndicatorLastPeak(trough_0);
           int trough_1 = GetIndicatorLastTrough(peak_1);
         }
       else
         {        
           trough_0 = GetIndicatorLastTrough(i);
           peak_0   = GetIndicatorLastPeak(trough_0);
           trough_1 = GetIndicatorLastTrough(peak_0);         
           peak_1   = GetIndicatorLastPeak(trough_1);                       
         }
       //----  
       if(peak_0 == -1 || peak_1 == -1 || trough_0 == -1 || 
          trough_1 == -1)
           continue;
       //----          
       double indicatorLastPeak = OsMA[peak_0];
       double indicatorThePeakBefore = OsMA[peak_1];
       double indicatorLastTrough = OsMA[trough_0];
       double indicatorTheTroughBefore = OsMA[trough_1];
/*      
       int pricePeak_0 = GetPriceLastPeak(peak_0);
       int pricePeak_1 = GetPriceLastPeak(peak_1);
       int priceTrough_0 = GetPriceLastTrough(trough_0);
       int priceTrough_1 = GetPriceLastTrough(trough_1);
*/
       int pricePeak_0 = peak_0;
       int pricePeak_1 = peak_1;
       int priceTrough_0 = trough_0;
       int priceTrough_1 = trough_1;
       //----
       double priceLastPeak = High[pricePeak_0];
       double priceThePeakBefore = High[pricePeak_1];
       double priceLastTrough = Low[priceTrough_0];
       double priceTheTroughBefore = Low[priceTrough_1];
       // Bearish divergence condition         
       if((priceLastPeak > priceThePeakBefore && 
           indicatorLastPeak < indicatorThePeakBefore) ||
           (priceLastPeak < priceThePeakBefore && 
           indicatorLastPeak > indicatorThePeakBefore))
         {
           bearishDivergence[peak_0] = upOsMA[peak_0] + arrowSeparation;
           if(drawDivergenceLines)
             {
               PriceDrawLine(Time[pricePeak_0], Time[pricePeak_1], 
                             priceLastPeak, priceThePeakBefore, Red);
               IndicatorDrawLine(Time[peak_0], Time[peak_1], indicatorLastPeak, 
                                 indicatorThePeakBefore, Red);
             }
           continue;
         }
       // Bullish divergence condition           
       if((priceLastTrough < priceTheTroughBefore && 
           indicatorLastTrough > indicatorTheTroughBefore) ||
           (priceLastTrough > priceTheTroughBefore && 
           indicatorLastTrough < indicatorTheTroughBefore))
         {
           bullishDivergence[trough_0] = downOsMA[trough_0] - arrowSeparation;
           if(drawDivergenceLines)
             {
               PriceDrawLine(Time[priceTrough_0], Time[priceTrough_1], 
                             priceLastTrough, priceTheTroughBefore, Green);
               IndicatorDrawLine(Time[trough_0], Time[trough_1], indicatorLastTrough, 
                                 indicatorTheTroughBefore, Green);
             }
           continue;
         }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CalculateOsMA(int countedBars)
  {
   for(int i = Bars - countedBars; i >= 0; i--)
     {
       MACD[i]=iMA(NULL, 0, fastEMA, 0, MODE_EMA, PRICE_CLOSE, i) -
               iMA(NULL, 0, slowEMA, 0, MODE_EMA, PRICE_CLOSE, i);
     }
   for(i = Bars - countedBars; i >= 0; i--)
     {
       Signal[i] = iMAOnArray(MACD, Bars, signal, 0, MODE_SMA, i);
       OsMA[i] = (iRSI(NULL,0,rsiperiod1,PRICE_WEIGHTED,i)-50)*2;
       //----
       if(OsMA[i] > 0)
         {
           upOsMA[i] = OsMA[i];
           downOsMA[i] = 0;
         }
       else 
           if(OsMA[i] < 0)
             {
               downOsMA[i] = OsMA[i];
               upOsMA[i] = 0;   
             }
           else
             {
               upOsMA[i] = 0;
               downOsMA[i] = 0;   
             }
     }            
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int GetPositiveRegionStart(int index)
  {
   int regionStart;
   for(int i = index + 1; i < Bars; i++)
     {
       if(OsMA[i] >= OsMA[i-1] && OsMA[i] >= OsMA[i+1] && 
          OsMA[i] >= OsMA[i+2] && OsMA[i] > positiveSensitivity)
           return(i);    
     }
   return(-1);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int GetNegativeRegionStart(int index)
  {
   for(int i = index + 1; i < Bars; i++)
     {
       if(OsMA[i] <= OsMA[i-1] && OsMA[i] <= OsMA[i+1] && 
          OsMA[i] <= OsMA[i+2] && OsMA[i] < negativeSensitivity)
           return(i);   
     }
   return(-1);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int GetFirstPeakOrTrough(int index)
  {
   for(int i = index + 1; i < Bars; i++)
     {
       if((OsMA[i] >= OsMA[i-1] && OsMA[i] >= OsMA[i+1] && 
          OsMA[i] >= OsMA[i+2] && OsMA[i] > positiveSensitivity) ||
          (OsMA[i] <= OsMA[i-1] && OsMA[i] <= OsMA[i+1] && 
          OsMA[i] <= OsMA[i+2] && OsMA[i] < negativeSensitivity))
           return(i);
     }
   return(-1);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int GetIndicatorLastPeak(int index)
  {
   int regionStart = GetPositiveRegionStart(index);
   if(regionStart == -1)
       return(-1);
//----   
   int peakShift = 0;
   double peakValue = 0;
//----
   for(int i = regionStart; i < Bars; i++)
     {
       if(OsMA[i] > peakValue && OsMA[i] >= OsMA[i-1] && 
          OsMA[i] >= OsMA[i+1] && OsMA[i] >= OsMA[i+2] && 
          OsMA[i] > positiveSensitivity)
         {
           peakValue = OsMA[i];
           peakShift = i;
         }
       if(OsMA[i] < 0)
           break;  
     } 
   return(peakShift);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int GetIndicatorLastTrough(int index)
  {
   int regionStart = GetNegativeRegionStart(index);
   if(regionStart == -1)
       return(-1);
//----         
   int troughShift = 0;
   double troughValue = 0;
//----   
   for(int i = regionStart; i < Bars; i++)
     {
       if(OsMA[i] < troughValue && OsMA[i] <= OsMA[i-1] && 
          OsMA[i] <= OsMA[i+1] && OsMA[i] <= OsMA[i+2] && 
          OsMA[i] < negativeSensitivity)
         {
           troughValue = OsMA[i];
           troughShift = i;
         }   
       if(OsMA[i] > 0)
           break;  
     }  
   return(troughShift);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void PriceDrawLine(datetime x1, datetime x2, double y1, double y2, 
                   color lineColor)
  {
   string label = "DivergenceLine# " + 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);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void IndicatorDrawLine(datetime x1, datetime x2, double y1, double y2, 
                       color lineColor)
  {
   int indicatorWindow = WindowFind("FX5_Divergence(" + fastEMA + "," + 
                                    slowEMA + "," + signal + ")");
   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);
  }
//+------------------------------------------------------------------+

Comments